Toshihiro Shimizu 890ddd
#include "toonz/txshsimplelevel.h"
Toshihiro Shimizu 890ddd
#include "imagebuilders.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzLib includes
Toshihiro Shimizu 890ddd
#include "toonz/txshleveltypes.h"
Toshihiro Shimizu 890ddd
#include "toonz/imagemanager.h"
Toshihiro Shimizu 890ddd
#include "toonz/studiopalette.h"
Toshihiro Shimizu 890ddd
#include "toonz/hook.h"
Toshihiro Shimizu 890ddd
#include "toonz/toonzscene.h"
Toshihiro Shimizu 890ddd
#include "toonz/levelproperties.h"
Toshihiro Shimizu 890ddd
#include "toonz/levelupdater.h"
Toshihiro Shimizu 890ddd
#include "toonz/fullcolorpalette.h"
Toshihiro Shimizu 890ddd
#include "toonz/preferences.h"
Toshihiro Shimizu 890ddd
#include "toonz/stage.h"
Toshihiro Shimizu 890ddd
#include "toonz/textureutils.h"
Toshihiro Shimizu 890ddd
#include "toonz/levelset.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzBase includes
Toshihiro Shimizu 890ddd
#include "tenv.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "trasterimage.h"
Toshihiro Shimizu 890ddd
#include "tvectorimage.h"
Toshihiro Shimizu 890ddd
#include "tmeshimage.h"
Toshihiro Shimizu 890ddd
#include "timagecache.h"
Toshihiro Shimizu 890ddd
#include "tofflinegl.h"
Toshihiro Shimizu 890ddd
#include "tvectorgl.h"
Toshihiro Shimizu 890ddd
#include "tvectorrenderdata.h"
Toshihiro Shimizu 890ddd
#include "tropcm.h"
Toshihiro Shimizu 890ddd
#include "tpixelutils.h"
Toshihiro Shimizu 890ddd
#include "timageinfo.h"
Toshihiro Shimizu 890ddd
#include "tlogger.h"
Toshihiro Shimizu 890ddd
#include "tstream.h"
Toshihiro Shimizu 890ddd
#include "tsystem.h"
Toshihiro Shimizu 890ddd
#include "tcontenthistory.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Qt includes
Toshihiro Shimizu 890ddd
#include <QDir>
Toshihiro Shimizu 890ddd
#include <QRegExp>
Toshihiro Shimizu 890ddd
#include <QMessageBox>
Keisuke Ogaki 8b06ff
#include <QtCore>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "../common/psdlib/psd.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace bc = boost::container;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//******************************************************************************************
Toshihiro Shimizu 890ddd
//    Global stuff
Toshihiro Shimizu 890ddd
//******************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
DEFINE_CLASS_CODE(TXshSimpleLevel, 20)
Toshihiro Shimizu 890ddd
PERSIST_IDENTIFIER(TXshSimpleLevel, "level")
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//******************************************************************************************
Toshihiro Shimizu 890ddd
//    Local namespace stuff
Toshihiro Shimizu 890ddd
//******************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
int idBaseCode = 1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct CompatibilityStruct {
Shinya Kitaoka 120a6e
  int writeMask, neededMask, forbiddenMask;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
CompatibilityStruct compatibility = {
Shinya Kitaoka 120a6e
    0x00F1,  // mask written.   Note: Student main must be 0x00F2
Shinya Kitaoka 120a6e
    //                 Note: the 0x00F0 part is currently not used.
Shinya Kitaoka 120a6e
    0x0000,  // mandatory mask: loaded levels MUST have a mask with these bits
Shinya Kitaoka 120a6e
             // set
Shinya Kitaoka 120a6e
    //                 Note: if mandatory mask != 0 then no old level (without
Shinya Kitaoka 120a6e
    //                 mask)
Shinya Kitaoka 120a6e
    //                       can be loaded
Shinya Kitaoka 120a6e
    //                 Note: this mask is currently not used.
Shinya Kitaoka 120a6e
    0x000E  // forbidden mask: loaded levels MUST NOT have a mask with these
Shinya Kitaoka 120a6e
            // bits set
Shinya Kitaoka 120a6e
    //
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline std::string rasterized(std::string id) { return id + "_rasterized"; }
Toshihiro Shimizu 890ddd
inline std::string filled(std::string id) { return id + "_filled"; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QString getCreatorString() {
Shinya Kitaoka 120a6e
  QString creator = QString::fromStdString(TEnv::getApplicationName()) + " " +
Shinya Kitaoka 120a6e
                    QString::fromStdString(TEnv::getApplicationVersion()) +
Shinya Kitaoka 120a6e
                    " CM(" + QString::number(compatibility.writeMask, 16) + ")";
Shinya Kitaoka 120a6e
  return creator;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool checkCreatorString(const QString &creator) {
Shinya Kitaoka 120a6e
  int mask = 0;
Shinya Kitaoka 120a6e
  if (creator != "") {
Shinya Kitaoka 120a6e
    QRegExp rx("CM\\([0-9A-Fa-f]*\\)");
Shinya Kitaoka 120a6e
    int pos = rx.indexIn(creator);
Shinya Kitaoka 120a6e
    int len = rx.matchedLength();
Shinya Kitaoka 120a6e
    if (pos >= 0 && len >= 4) {
Shinya Kitaoka 120a6e
      QString v;
Shinya Kitaoka 120a6e
      if (len > 4) v = creator.mid(pos + 3, len - 4);
Shinya Kitaoka 120a6e
      bool ok        = true;
Shinya Kitaoka 120a6e
      mask           = v.toInt(&ok, 16);
Toshihiro Shimizu 890ddd
    }
Toshihiro Shimizu 890ddd
  }
Shinya Kitaoka 120a6e
  return (mask & compatibility.neededMask) == compatibility.neededMask &&
Shinya Kitaoka 120a6e
         (mask & compatibility.forbiddenMask) == 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool isAreadOnlyLevel(const TFilePath &path) {
Shinya Kitaoka 120a6e
  if (path.isEmpty() || !path.isAbsolute()) return false;
Shinya Kitaoka 120a6e
  if (path.getDots() == "." ||
Shinya Kitaoka 120a6e
      (path.getDots() == ".." &&
Shinya Kitaoka 120a6e
       (path.getType() == "tlv" || path.getType() == "tpl"))) {
Shinya Kitaoka 120a6e
    if (!TSystem::doesExistFileOrLevel(path)) return false;
Shinya Kitaoka 120a6e
    TFileStatus fs(path);
Shinya Kitaoka 120a6e
    return !fs.isWritable();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  /*- 処理が重くなるので、連番ファイルは全てfalseを返す -*/
Shinya Kitaoka 120a6e
  /*
Shinya Kitaoka 120a6e
else if(path.getDots() == "..")
Shinya Kitaoka 120a6e
{
Shinya Kitaoka 120a6e
TFilePath dir = path.getParentDir();
Shinya Kitaoka 120a6e
QDir qDir(QString::fromStdWString(dir.getWideString()));
Shinya Kitaoka 120a6e
QString levelName =
Shinya Kitaoka 120a6e
QRegExp::escape(QString::fromStdWString(path.getWideName()));
Shinya Kitaoka 120a6e
QString levelType = QString::fromStdString(path.getType());
Shinya Kitaoka 120a6e
QString exp(levelName+".[0-9]{1,4}."+levelType);
Shinya Kitaoka 120a6e
QRegExp regExp(exp);
Shinya Kitaoka 120a6e
QStringList list = qDir.entryList(QDir::Files);
Shinya Kitaoka 120a6e
QStringList livelFrames = list.filter(regExp);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
bool isReadOnly=false;
Shinya Kitaoka 120a6e
int i;
Shinya Kitaoka 120a6e
for(i=0; i
Toshihiro Shimizu 890ddd
{
Shinya Kitaoka 120a6e
TFilePath frame = dir+TFilePath(livelFrames[i].toStdWString());
Shinya Kitaoka 120a6e
if(frame.isEmpty() || !frame.isAbsolute()) continue;
Shinya Kitaoka 120a6e
TFileStatus fs(frame);
Shinya Kitaoka 120a6e
isReadOnly = !fs.isWritable();
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
return isReadOnly;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void getIndexesRangefromFids(TXshSimpleLevel *level,
Shinya Kitaoka 120a6e
                             const std::set<TFrameId> &fids, int &fromIndex,
Shinya Kitaoka 120a6e
                             int &toIndex) {
Shinya Kitaoka 120a6e
  if (fids.empty()) {
Shinya Kitaoka 120a6e
    fromIndex = toIndex = -1;
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  toIndex   = 0;
Shinya Kitaoka 120a6e
  fromIndex = level->getFrameCount() - 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::set<TFrameId>::const_iterator it;
Shinya Kitaoka 120a6e
  for (it = fids.begin(); it != fids.end(); ++it) {
Shinya Kitaoka 120a6e
    int index                        = level->guessIndex(*it);
Shinya Kitaoka 120a6e
    if (index > toIndex) toIndex     = index;
Shinya Kitaoka 120a6e
    if (index < fromIndex) fromIndex = index;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//******************************************************************************************
Toshihiro Shimizu 890ddd
//    TXshSimpleLevel  impementation
Toshihiro Shimizu 890ddd
//******************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TXshSimpleLevel::m_rasterizePli        = false;
Toshihiro Shimizu 890ddd
bool TXshSimpleLevel::m_fillFullColorRaster = false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 3bfa54
TXshSimpleLevel::TXshSimpleLevel(const std::wstring &name)
Shinya Kitaoka 120a6e
    : TXshLevel(m_classCode, name)
Shinya Kitaoka 120a6e
    , m_properties(new LevelProperties)
Shinya Kitaoka 120a6e
    , m_palette(0)
Shinya Kitaoka 120a6e
    , m_idBase(std::to_string(idBaseCode++))
Shinya Kitaoka 120a6e
    , m_editableRangeUserInfo(L"")
Shinya Kitaoka 120a6e
    , m_isSubsequence(false)
Shinya Kitaoka 120a6e
    , m_16BitChannelLevel(false)
Shinya Kitaoka 120a6e
    , m_isReadOnly(false)
Shinya Kitaoka 120a6e
    , m_temporaryHookMerged(false) {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
TXshSimpleLevel::~TXshSimpleLevel() {
Shinya Kitaoka 120a6e
  clearFrames();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_palette) m_palette->release();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::setEditableRange(unsigned int from, unsigned int to,
Shinya Kitaoka 120a6e
                                       const std::wstring &userName) {
Shinya Kitaoka 120a6e
  assert(from <= to && to < (unsigned int)getFrameCount());
Shinya Kitaoka 120a6e
  unsigned int i;
Shinya Kitaoka 120a6e
  for (i = from; i <= to; i++) m_editableRange.insert(index2fid(i));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QString hostName        = TSystem::getHostName();
Shinya Kitaoka 120a6e
  m_editableRangeUserInfo = userName + L"_" + hostName.toStdWString();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::wstring fileName = getEditableFileName();
Shinya Kitaoka 120a6e
  TFilePath dstPath     = getScene()->decodeFilePath(m_path);
Shinya Kitaoka 120a6e
  dstPath = dstPath.withName(fileName).withType(dstPath.getType());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Load temporary level file (for pli and tlv types only)
Shinya Kitaoka 120a6e
  if (getType() != OVL_XSHLEVEL && TSystem::doesExistFileOrLevel(dstPath)) {
Shinya Kitaoka 120a6e
    TLevelReaderP lr(dstPath);
Shinya Kitaoka 120a6e
    TLevelP level = lr->loadInfo();
Shinya Kitaoka 120a6e
    setPalette(level->getPalette());
Shinya Kitaoka 120a6e
    for (TLevel::Iterator it = level->begin(); it != level->end(); it++) {
Shinya Kitaoka 120a6e
      TImageP img = lr->getFrameReader(it->first)->load();
Shinya Kitaoka 120a6e
      setFrame(it->first, img);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Merge temporary hook file with current hookset
Shinya Kitaoka 120a6e
  const TFilePath &hookFile = getHookPath(dstPath);
Shinya Kitaoka 120a6e
  mergeTemporaryHookFile(from, to, hookFile);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::mergeTemporaryHookFile(unsigned int from, unsigned int to,
Shinya Kitaoka 120a6e
                                             const TFilePath &hookFile) {
Shinya Kitaoka 120a6e
  if (!TFileStatus(hookFile).doesExist()) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  HookSet *tempHookSet = new HookSet;
Shinya Kitaoka 120a6e
  TIStream is(hookFile);
Shinya Kitaoka 120a6e
  std::string tagName;
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    if (is.matchTag(tagName) && tagName == "hooks") tempHookSet->loadData(is);
Shinya Kitaoka 120a6e
  } catch (...) {
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  HookSet *hookSet  = getHookSet();
Shinya Kitaoka 120a6e
  int tempHookCount = tempHookSet->getHookCount();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (tempHookCount == 0) {
Shinya Kitaoka 120a6e
    for (unsigned int f = from; f <= to; f++) {
Shinya Kitaoka 120a6e
      TFrameId fid = index2fid(f);
Shinya Kitaoka 120a6e
      hookSet->eraseFrame(fid);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    for (int i = 0; i < tempHookCount; i++) {
Shinya Kitaoka 120a6e
      Hook *hook    = tempHookSet->getHook(i);
Shinya Kitaoka 120a6e
      Hook *newHook = hookSet->touchHook(hook->getId());
Shinya Kitaoka 120a6e
      newHook->setTrackerObjectId(hook->getTrackerObjectId());
Shinya Kitaoka 120a6e
      newHook->setTrackerRegionHeight(hook->getTrackerRegionHeight());
Shinya Kitaoka 120a6e
      newHook->setTrackerRegionWidth(hook->getTrackerRegionWidth());
Shinya Kitaoka 120a6e
      for (unsigned int f = from; f <= to; f++) {
Shinya Kitaoka 120a6e
        TFrameId fid = index2fid(f);
Shinya Kitaoka 120a6e
        newHook->setAPos(fid, hook->getAPos(fid));
Shinya Kitaoka 120a6e
        newHook->setBPos(fid, hook->getBPos(fid));
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_temporaryHookMerged = true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::clearEditableRange() {
Shinya Kitaoka 120a6e
  m_editableRange.clear();
Shinya Kitaoka 120a6e
  m_editableRangeUserInfo = L"";
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
std::wstring TXshSimpleLevel::getEditableFileName() {
Toshihiro Shimizu 890ddd
#ifdef MACOSX
Shinya Kitaoka 120a6e
  std::wstring fileName = L"." + m_path.getWideName();
Toshihiro Shimizu 890ddd
#else
Shinya Kitaoka 120a6e
  std::wstring fileName = m_path.getWideName();
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
  fileName += L"_" + m_editableRangeUserInfo;
Shinya Kitaoka 120a6e
  int from, to;
Shinya Kitaoka 120a6e
  getIndexesRangefromFids(this, m_editableRange, from, to);
Shinya Kitaoka 120a6e
  if (from == -1 && to == -1) return L"";
Shinya Kitaoka 120a6e
  fileName += L"_" + std::to_wstring(from + 1) + L"-" + std::to_wstring(to + 1);
Shinya Kitaoka 120a6e
  return fileName;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
std::set<TFrameId> TXshSimpleLevel::getEditableRange() {
Shinya Kitaoka 120a6e
  return m_editableRange;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::setRenumberTable() {
Shinya Kitaoka 120a6e
  m_renumberTable.clear();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  FramesSet::iterator ft, fEnd = m_frames.end();
Shinya Kitaoka 120a6e
  for (ft = m_frames.begin(); ft != fEnd; ++ft) m_renumberTable[*ft] = *ft;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::setDirtyFlag(bool on) { m_properties->setDirtyFlag(on); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TXshSimpleLevel::getDirtyFlag() const {
Shinya Kitaoka 120a6e
  return m_properties->getDirtyFlag();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::touchFrame(const TFrameId &fid) {
Shinya Kitaoka 120a6e
  m_properties->setDirtyFlag(true);
Shinya Kitaoka 120a6e
  TContentHistory *ch = getContentHistory();
Shinya Kitaoka 120a6e
  if (!ch) {
Shinya Kitaoka 120a6e
    ch = new TContentHistory(true);
Shinya Kitaoka 120a6e
    setContentHistory(ch);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  ch->frameModifiedNow(fid);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (getType() == PLI_XSHLEVEL) {
Shinya Kitaoka 120a6e
    std::string id = rasterized(getImageId(fid));
Shinya Kitaoka 120a6e
    ImageManager::instance()->invalidate(id);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (getType() & FULLCOLOR_TYPE) {
Shinya Kitaoka 120a6e
    std::string id = filled(getImageId(fid));
Shinya Kitaoka 120a6e
    ImageManager::instance()->invalidate(id);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::onPaletteChanged() {
Shinya Kitaoka 120a6e
  FramesSet::iterator ft, fEnd = m_frames.end();
Shinya Kitaoka 120a6e
  for (ft = m_frames.begin(); ft != fEnd; ++ft) {
Shinya Kitaoka 120a6e
    const TFrameId &fid = *ft;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (getType() == PLI_XSHLEVEL) {
Shinya Kitaoka 120a6e
      std::string id = rasterized(getImageId(fid));
Shinya Kitaoka 120a6e
      ImageManager::instance()->invalidate(id);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (getType() & FULLCOLOR_TYPE) {
Shinya Kitaoka 120a6e
      std::string id = filled(getImageId(fid));
Shinya Kitaoka 120a6e
      ImageManager::instance()->invalidate(id);
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    texture_utils::invalidateTexture(this, fid);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::setScannedPath(const TFilePath &fp) {
Shinya Kitaoka 120a6e
  m_scannedPath = fp;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::setPath(const TFilePath &fp, bool keepFrames) {
Shinya Kitaoka 120a6e
  m_path = fp;
Shinya Kitaoka 120a6e
  if (!keepFrames) {
Shinya Kitaoka 120a6e
    clearFrames();
Shinya Kitaoka 120a6e
    assert(getScene());
Shinya Kitaoka 120a6e
    try {
Shinya Kitaoka 120a6e
      load();
Shinya Kitaoka 120a6e
    } catch (...) {
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (getType() != PLI_XSHLEVEL) {
Shinya Kitaoka 120a6e
    if (!m_frames.empty()) {
Shinya Kitaoka 120a6e
      std::string imageId = getImageId(getFirstFid());
Shinya Kitaoka 120a6e
      const TImageInfo *imageInfo =
Shinya Kitaoka 120a6e
          ImageManager::instance()->getInfo(imageId, ImageManager::none, 0);
Shinya Kitaoka 120a6e
      if (imageInfo) {
Shinya Kitaoka 120a6e
        TDimension imageRes(0, 0);
Shinya Kitaoka 120a6e
        TPointD imageDpi;
Shinya Kitaoka 120a6e
        imageRes.lx = imageInfo->m_lx;
Shinya Kitaoka 120a6e
        imageRes.ly = imageInfo->m_ly;
Shinya Kitaoka 120a6e
        imageDpi.x  = imageInfo->m_dpix;
Shinya Kitaoka 120a6e
        imageDpi.y  = imageInfo->m_dpiy;
Shinya Kitaoka 120a6e
        m_properties->setImageDpi(imageDpi);
Shinya Kitaoka 120a6e
        m_properties->setImageRes(imageRes);
Shinya Kitaoka 120a6e
        m_properties->setBpp(imageInfo->m_bitsPerSample *
Shinya Kitaoka 120a6e
                             imageInfo->m_samplePerPixel);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::clonePropertiesFrom(const TXshSimpleLevel *oldSl) {
Shinya Kitaoka 120a6e
  m_properties->setImageDpi(
Shinya Kitaoka 120a6e
      oldSl->m_properties
Shinya Kitaoka 120a6e
          ->getImageDpi());  // Watch out - may change dpi policy!
Shinya Kitaoka 120a6e
  m_properties->setDpi(oldSl->m_properties->getDpi());
Shinya Kitaoka 120a6e
  m_properties->setDpiPolicy(oldSl->m_properties->getDpiPolicy());
Shinya Kitaoka 120a6e
  m_properties->setImageRes(oldSl->m_properties->getImageRes());
Shinya Kitaoka 120a6e
  m_properties->setBpp(oldSl->m_properties->getBpp());
Shinya Kitaoka 120a6e
  m_properties->setSubsampling(oldSl->m_properties->getSubsampling());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TPalette *TXshSimpleLevel::getPalette() const { return m_palette; }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void TXshSimpleLevel::setPalette(TPalette *palette) {
Shinya Kitaoka 120a6e
  if (m_palette != palette) {
Shinya Kitaoka 120a6e
    if (m_palette) m_palette->release();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_palette = palette;
Shinya Kitaoka 120a6e
    if (m_palette) {
Shinya Kitaoka 120a6e
      m_palette->addRef();
Shinya Kitaoka 120a6e
      if (!(getType() & FULLCOLOR_TYPE)) m_palette->setPaletteName(getName());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::getFids(std::vector<TFrameId> &fids) const {
Shinya Kitaoka 120a6e
  fids.assign(m_frames.begin(), m_frames.end());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
std::vector<TFrameId> TXshSimpleLevel::getFids() const {
Shinya Kitaoka 120a6e
  return std::vector<TFrameId>(m_frames.begin(), m_frames.end());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TXshSimpleLevel::isFid(const TFrameId &fid) const {
Shinya Kitaoka 120a6e
  return m_frames.count(fid);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
const TFrameId &TXshSimpleLevel::getFrameId(int index) const {
Shinya Kitaoka 120a6e
  return *(m_frames.begin() += index);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFrameId TXshSimpleLevel::getFirstFid() const {
Shinya Kitaoka 120a6e
  return !isEmpty() ? *m_frames.begin() : TFrameId(TFrameId::NO_FRAME);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFrameId TXshSimpleLevel::getLastFid() const {
Shinya Kitaoka 120a6e
  return !isEmpty() ? *m_frames.rbegin() : TFrameId(TFrameId::NO_FRAME);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int TXshSimpleLevel::guessStep() const {
Shinya Kitaoka 120a6e
  int frameCount = m_frames.size();
Shinya Kitaoka 120a6e
  if (frameCount < 2)
Shinya Kitaoka 120a6e
    return 1;  // un livello con zero o un frame ha per def. step=1
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  FramesSet::const_iterator ft = m_frames.begin();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TFrameId firstFid = *ft++, secondFid = *ft++;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (firstFid.getLetter() != 0 || secondFid.getLetter() != 0) return 1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int step = secondFid.getNumber() - firstFid.getNumber();
Shinya Kitaoka 120a6e
  if (step == 1) return 1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // controllo subito se lo step vale per l'ultimo frame
Shinya Kitaoka 120a6e
  // (cerco di limitare il numero di volte in cui devo controllare tutta la
Shinya Kitaoka 120a6e
  // lista)
Shinya Kitaoka 120a6e
  TFrameId lastFid = *m_frames.rbegin();
Shinya Kitaoka 120a6e
  if (lastFid.getLetter() != 0) return 1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (lastFid.getNumber() != firstFid.getNumber() + step * (frameCount - 1))
Shinya Kitaoka 120a6e
    return 1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (int i = 2; ft != m_frames.end(); ++ft, ++i) {
Shinya Kitaoka 120a6e
    const TFrameId &fid = *ft;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (fid.getLetter() != 0) return 1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (fid.getNumber() != firstFid.getNumber() + step * i) return 1;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return step;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int TXshSimpleLevel::fid2index(const TFrameId &fid) const {
Shinya Kitaoka 120a6e
  FramesSet::const_iterator ft = m_frames.find(fid);
Shinya Kitaoka 120a6e
  return (ft != m_frames.end()) ? std::distance(m_frames.begin(), ft)
Shinya Kitaoka 120a6e
                                :  // Note: flat_set has random access
Shinya Kitaoka 120a6e
             -1;                   // iterators, so this is FAST
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int TXshSimpleLevel::guessIndex(const TFrameId &fid) const {
Shinya Kitaoka 120a6e
  if (m_frames.empty()) return 0;  // no frames, return 0 (by definition)
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  FramesSet::const_iterator ft = m_frames.lower_bound(fid);
Shinya Kitaoka 120a6e
  if (ft == m_frames.end()) {
Shinya Kitaoka 120a6e
    const TFrameId &maxFid = *m_frames.rbegin();
Shinya Kitaoka 120a6e
    assert(fid > maxFid);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // fid not in the table, but greater than the last one.
Shinya Kitaoka 120a6e
    // return a suitable index. (e.g. frames are 1,3,5,7; fid2index(11) should
Shinya Kitaoka 120a6e
    // return index=5)
Shinya Kitaoka 120a6e
    int step = guessStep();
Shinya Kitaoka 120a6e
    int i    = (fid.getNumber() - maxFid.getNumber()) / step;
Shinya Kitaoka 120a6e
    return m_frames.size() - 1 + i;
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    return std::distance(m_frames.begin(), ft);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFrameId TXshSimpleLevel::index2fid(int index) const {
Shinya Kitaoka 120a6e
  if (index < 0) return TFrameId(-2);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int frameCount = m_frames.size();
Shinya Kitaoka 120a6e
  if (frameCount == 0) return TFrameId(1);  // o_o?
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (index < frameCount) {
Shinya Kitaoka 120a6e
    FramesSet::const_iterator ft = m_frames.begin();
Shinya Kitaoka 120a6e
    std::advance(ft, index);
Shinya Kitaoka 120a6e
    return *ft;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    int step        = guessStep();
Shinya Kitaoka 120a6e
    TFrameId maxFid = *m_frames.rbegin();
Shinya Kitaoka 120a6e
    int d           = step * (index - frameCount + 1);
Shinya Kitaoka 120a6e
    return TFrameId(maxFid.getNumber() + d);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TImageP TXshSimpleLevel::getFrame(const TFrameId &fid, UCHAR imFlags,
Shinya Kitaoka 120a6e
                                  int subsampling) const {
Shinya Kitaoka 120a6e
  assert(m_type != UNKNOWN_XSHLEVEL);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // If the required frame is not in range, quit
Shinya Kitaoka 120a6e
  if (m_frames.count(fid) == 0) return TImageP();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const std::string &imgId = getImageId(fid);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ImageLoader::BuildExtData extData(this, fid, subsampling);
Shinya Kitaoka 120a6e
  TImageP img = ImageManager::instance()->getImage(imgId, imFlags, &extData);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (imFlags & ImageManager::toBeModified) {
Shinya Kitaoka 120a6e
    // The image will be modified. Perform any related invalidation.
Shinya Kitaoka 120a6e
    texture_utils::invalidateTexture(
Shinya Kitaoka 120a6e
        this, fid);  // We must rebuild associated textures
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return img;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TImageInfo *TXshSimpleLevel::getFrameInfo(const TFrameId &fid,
Shinya Kitaoka 120a6e
                                          bool toBeModified) {
Shinya Kitaoka 120a6e
  assert(m_type != UNKNOWN_XSHLEVEL);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // If the required frame is not in range, quit
Shinya Kitaoka 120a6e
  if (m_frames.count(fid) == 0) return 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const std::string &imgId = getImageId(fid);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TImageInfo *info = ImageManager::instance()->getInfo(
Shinya Kitaoka 120a6e
      imgId, toBeModified ? ImageManager::toBeModified : ImageManager::none, 0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return info;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TImageP TXshSimpleLevel::getFrameIcon(const TFrameId &fid) const {
Shinya Kitaoka 120a6e
  assert(m_type != UNKNOWN_XSHLEVEL);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_frames.count(fid) == 0) return TImageP();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // NOTE: Icons caching is DISABLED at this stage. It is now responsibility of
Shinya Kitaoka 120a6e
  // ToonzQt's IconGenerator class.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ImageLoader::BuildExtData extData(this, fid);
Shinya Kitaoka 120a6e
  extData.m_subs = 1, extData.m_icon = true;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const std::string &imgId = getImageId(fid);
Shinya Kitaoka 120a6e
  TImageP img              = ImageManager::instance()->getImage(
Shinya Kitaoka 120a6e
      imgId, ImageManager::dontPutInCache, &extData);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TToonzImageP timg = (TToonzImageP)img;
Shinya Kitaoka 120a6e
  if (timg && m_palette) timg->setPalette(m_palette);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return img;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
// load icon (and image) data of all frames into cache
Shinya Kitaoka 120a6e
void TXshSimpleLevel::loadAllIconsAndPutInCache(bool cacheImagesAsWell) {
Shinya Kitaoka 120a6e
  if (m_type != TZP_XSHLEVEL) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::vector<TFrameId> fids;
Shinya Kitaoka 120a6e
  getFids(fids);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::vector<std::string> iconIds;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (int i = 0; i < (int)fids.size(); i++) {
Shinya Kitaoka 120a6e
    iconIds.push_back(getIconId(fids[i]));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ImageManager::instance()->loadAllTlvIconsAndPutInCache(this, fids, iconIds,
Shinya Kitaoka 120a6e
                                                         cacheImagesAsWell);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TRasterImageP TXshSimpleLevel::getFrameToCleanup(const TFrameId &fid) const {
Shinya Kitaoka 120a6e
  assert(m_type != UNKNOWN_XSHLEVEL);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  FramesSet::const_iterator ft = m_frames.find(fid);
Shinya Kitaoka 120a6e
  if (ft == m_frames.end()) return TImageP();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  bool flag           = (m_scannedPath != TFilePath());
Shinya Kitaoka 120a6e
  std::string imageId = getImageId(fid, flag ? Scanned : 0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ImageLoader::BuildExtData extData(this, fid, 1);
Shinya Kitaoka 120a6e
  TRasterImageP img = ImageManager::instance()->getImage(
Shinya Kitaoka 120a6e
      imageId, ImageManager::dontPutInCache, &extData);
Shinya Kitaoka 120a6e
  if (!img) return img;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double x_dpi, y_dpi;
Shinya Kitaoka 120a6e
  img->getDpi(x_dpi, y_dpi);
Shinya Kitaoka 120a6e
  if (!x_dpi && !y_dpi) {
Shinya Kitaoka 120a6e
    TPointD dpi = m_properties->getDpi();
Shinya Kitaoka 120a6e
    img->setDpi(dpi.x, dpi.y);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return img;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TImageP TXshSimpleLevel::getFullsampledFrame(const TFrameId &fid,
Shinya Kitaoka 120a6e
                                             UCHAR imFlags) const {
Shinya Kitaoka 120a6e
  assert(m_type != UNKNOWN_XSHLEVEL);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  FramesSet::const_iterator it = m_frames.find(fid);
Shinya Kitaoka 120a6e
  if (it == m_frames.end()) return TRasterImageP();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::string imageId = getImageId(fid);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ImageLoader::BuildExtData extData(this, fid, 1);
Shinya Kitaoka 120a6e
  TImageP img = ImageManager::instance()->getImage(imageId, imFlags, &extData);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (imFlags & ImageManager::toBeModified) {
Shinya Kitaoka 120a6e
    // The image will be modified. Perform any related invalidation.
Shinya Kitaoka 120a6e
    texture_utils::invalidateTexture(
Shinya Kitaoka 120a6e
        this, fid);  // We must rebuild associated textures
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return img;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
std::string TXshSimpleLevel::getIconId(const TFrameId &fid,
Shinya Kitaoka 120a6e
                                       int frameStatus) const {
Shinya Kitaoka 120a6e
  return "icon:" + getImageId(fid, frameStatus);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
std::string TXshSimpleLevel::getIconId(const TFrameId &fid,
Shinya Kitaoka 120a6e
                                       const TDimension &size) const {
Shinya Kitaoka 120a6e
  return getImageId(fid) + ":" + std::to_string(size.lx) + "x" +
Shinya Kitaoka 120a6e
         std::to_string(size.ly);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TAffine getAffine(const TDimension &srcSize, const TDimension &dstSize) {
Shinya Kitaoka 120a6e
  double scx = 1 * dstSize.lx / (double)srcSize.lx;
Shinya Kitaoka 120a6e
  double scy = 1 * dstSize.ly / (double)srcSize.ly;
Shinya Kitaoka 120a6e
  double sc  = std::min(scx, scy);
Shinya Kitaoka 120a6e
  double dx  = (dstSize.lx - srcSize.lx * sc) * 0.5;
Shinya Kitaoka 120a6e
  double dy  = (dstSize.ly - srcSize.ly * sc) * 0.5;
Shinya Kitaoka 120a6e
  return TScale(sc) *
Shinya Kitaoka 120a6e
         TTranslation(0.5 * TPointD(srcSize.lx, srcSize.ly) + TPointD(dx, dy));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*!Costruisce l'icona di dimesione \b size dell'immagine \b img.*/
Shinya Kitaoka 120a6e
TImageP buildIcon(const TImageP &img, const TDimension &size) {
Shinya Kitaoka 120a6e
  TRaster32P raster(size);
Shinya Kitaoka 120a6e
  if (TVectorImageP vi = img) {
Shinya Kitaoka 120a6e
    TOfflineGL *glContext = new TOfflineGL(size);
Shinya Kitaoka 120a6e
    // TDimension cameraSize(768, 576);
Shinya Kitaoka 120a6e
    TDimension cameraSize(1920, 1080);
Shinya Kitaoka 120a6e
    TPalette *vPalette = img->getPalette();
Shinya Kitaoka 120a6e
    assert(vPalette);
Shinya Kitaoka 120a6e
    const TVectorRenderData rd(getAffine(cameraSize, size), TRect(), vPalette,
Shinya Kitaoka 120a6e
                               0, false);
Shinya Kitaoka 120a6e
    glContext->clear(TPixel32::White);
Shinya Kitaoka 120a6e
    glContext->draw(vi, rd);
Shinya Kitaoka 120a6e
    raster->copy(glContext->getRaster());
Shinya Kitaoka 120a6e
    delete glContext;
Shinya Kitaoka 120a6e
  } else if (TToonzImageP ti = img) {
Shinya Kitaoka 120a6e
    raster->fill(TPixel32(255, 255, 255, 255));
Shinya Kitaoka 120a6e
    TRasterCM32P rasCM32 = ti->getRaster();
Shinya Kitaoka 120a6e
    TRect bbox;
Shinya Kitaoka 120a6e
    bbox = ti->getSavebox();
Shinya Kitaoka 120a6e
    if (!bbox.isEmpty()) {
Shinya Kitaoka 120a6e
      rasCM32   = rasCM32->extractT(bbox);
Shinya Kitaoka 120a6e
      double sx = raster->getLx() / (double)rasCM32->getLx();
Shinya Kitaoka 120a6e
      double sy = raster->getLy() / (double)rasCM32->getLy();
Shinya Kitaoka 120a6e
      double sc = std::min(sx, sy);
Shinya Kitaoka 120a6e
      TAffine aff =
Shinya Kitaoka 120a6e
          TScale(sc).place(rasCM32->getCenterD(), raster->getCenterD());
Shinya Kitaoka 120a6e
      TRop::resample(raster, rasCM32, ti->getPalette(), aff);
Shinya Kitaoka 120a6e
      raster->lock();
Shinya Kitaoka 120a6e
      for (int y = 0; y < raster->getLy(); y++) {
Shinya Kitaoka 120a6e
        TPixel32 *pix    = raster->pixels(y);
Shinya Kitaoka 120a6e
        TPixel32 *endPix = pix + raster->getLx();
Shinya Kitaoka 120a6e
        while (pix < endPix) {
Shinya Kitaoka 120a6e
          *pix = overPix(TPixel32::White, *pix);
Shinya Kitaoka 120a6e
          pix++;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      raster->unlock();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    TRasterImageP ri = img;
Shinya Kitaoka 120a6e
    if (ri) {
Shinya Kitaoka 120a6e
      ri->makeIcon(raster);
Shinya Kitaoka 120a6e
      TRop::addBackground(raster, TPixel32::White);
Shinya Kitaoka 120a6e
    } else
Shinya Kitaoka 120a6e
      raster->fill(TPixel32(127, 50, 20));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return TRasterImageP(raster);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
}  // anonymous namespace
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::setFrame(const TFrameId &fid, const TImageP &img) {
Shinya Kitaoka 120a6e
  assert(m_type != UNKNOWN_XSHLEVEL);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (img) img->setPalette(getPalette());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_frames.insert(fid);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TFilePath path = m_path;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int frameStatus                        = getFrameStatus(fid);
Shinya Kitaoka 120a6e
  static const int SCANNED_OR_CLEANUPPED = (Scanned | Cleanupped);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if ((frameStatus & SCANNED_OR_CLEANUPPED) == Scanned) path = m_scannedPath;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Deal with the ImageManger: ensure the identifiers are bound, and the
Shinya Kitaoka 120a6e
  // associated image is either modified to img or (if !img) invalidated.
Shinya Kitaoka 120a6e
  const std::string &imageId = getImageId(fid);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (!ImageManager::instance()->isBound(imageId)) {
Shinya Kitaoka 120a6e
    const TFilePath &decodedPath = getScene()->decodeFilePath(path);
Shinya Kitaoka 120a6e
    ImageManager::instance()->bind(imageId, new ImageLoader(decodedPath, fid));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ImageManager::instance()->setImage(imageId, img);  // Invalidates if !img
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (frameStatus == Normal) {
Shinya Kitaoka 120a6e
    // Only a normal frame can have these. Justified since:
Shinya Kitaoka 120a6e
    //  a) PLIs have nothing to share with cleanup stuff
Shinya Kitaoka 120a6e
    //  b) The latter is used only in LineTest - which does not have Cleanup
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (m_type == PLI_XSHLEVEL) {
Shinya Kitaoka 120a6e
      const std::string &imageId2 = rasterized(imageId);
Shinya Kitaoka 120a6e
      if (!ImageManager::instance()->isBound(imageId2))
Shinya Kitaoka 120a6e
        ImageManager::instance()->bind(imageId2, new ImageRasterizer);
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        ImageManager::instance()->invalidate(imageId2);
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (m_type == OVL_XSHLEVEL || m_type == TZI_XSHLEVEL) {
Shinya Kitaoka 120a6e
      const std::string &imageId2 = filled(imageId);
Shinya Kitaoka 120a6e
      if (!ImageManager::instance()->isBound(imageId2))
Shinya Kitaoka 120a6e
        ImageManager::instance()->bind(imageId2, new ImageFiller);
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        ImageManager::instance()->invalidate(imageId2);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::eraseFrame(const TFrameId &fid) {
Shinya Kitaoka 120a6e
  FramesSet::iterator ft = m_frames.find(fid);
Shinya Kitaoka 120a6e
  if (ft == m_frames.end()) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Erase the corresponding entry in the renumber table
Shinya Kitaoka 120a6e
  std::map<TFrameId, TFrameId>::iterator rt, rEnd(m_renumberTable.end());
Shinya Kitaoka 120a6e
  for (rt = m_renumberTable.begin(); rt != rEnd; ++rt) {
Shinya Kitaoka 120a6e
    if (rt->second == fid) {
Shinya Kitaoka 120a6e
      m_renumberTable.erase(rt->first);
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_frames.erase(ft);
Shinya Kitaoka 120a6e
  getHookSet()->eraseFrame(fid);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ImageManager *im = ImageManager::instance();
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    im->unbind(getImageId(fid, Normal));
Shinya Kitaoka 120a6e
    im->unbind(getImageId(fid, Scanned));
Shinya Kitaoka 120a6e
    im->unbind(getImageId(fid, CleanupPreview));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (m_type == PLI_XSHLEVEL) im->unbind(rasterized(getImageId(fid)));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (m_type == OVL_XSHLEVEL || m_type == TZI_XSHLEVEL)
Shinya Kitaoka 120a6e
      im->unbind(filled(getImageId(fid)));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    texture_utils::invalidateTexture(this, fid);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::clearFrames() {
Shinya Kitaoka 120a6e
  ImageManager *im = ImageManager::instance();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Unbind frames
Shinya Kitaoka 120a6e
  FramesSet::iterator ft, fEnd = m_frames.end();
Shinya Kitaoka 120a6e
  for (ft = m_frames.begin(); ft != fEnd; ++ft) {
Shinya Kitaoka 120a6e
    im->unbind(getImageId(*ft, Scanned));
Shinya Kitaoka 120a6e
    im->unbind(getImageId(*ft, Cleanupped));
Shinya Kitaoka 120a6e
    im->unbind(getImageId(*ft, CleanupPreview));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (m_type == PLI_XSHLEVEL) im->unbind(rasterized(getImageId(*ft)));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (m_type == OVL_XSHLEVEL || m_type == TZI_XSHLEVEL)
Shinya Kitaoka 120a6e
      im->unbind(filled(getImageId(*ft)));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    texture_utils::invalidateTexture(this, *ft);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Clear level
Shinya Kitaoka 120a6e
  m_frames.clear();
Shinya Kitaoka 120a6e
  m_editableRange.clear();
Shinya Kitaoka 120a6e
  m_editableRangeUserInfo.clear();
Shinya Kitaoka 120a6e
  m_renumberTable.clear();
Shinya Kitaoka 120a6e
  m_framesStatus.clear();
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void TXshSimpleLevel::loadData(TIStream &is) {
Shinya Kitaoka 120a6e
  std::string tagName;
Shinya Kitaoka 120a6e
  bool flag = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int type = UNKNOWN_XSHLEVEL;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (;;) {
Shinya Kitaoka 120a6e
    if (is.matchTag(tagName)) {
Shinya Kitaoka 120a6e
      if (tagName == "path") {
Shinya Kitaoka 120a6e
        is >> m_path;
Shinya Kitaoka 120a6e
        is.matchEndTag();
Shinya Kitaoka 120a6e
      } else if (tagName == "scannedPath") {
Shinya Kitaoka 120a6e
        is >> m_scannedPath;
Shinya Kitaoka 120a6e
        is.matchEndTag();
Shinya Kitaoka 120a6e
      } else if (tagName == "info") {
Shinya Kitaoka 120a6e
        std::string v;
Shinya Kitaoka 120a6e
        double xdpi = 0, ydpi = 0;
Shinya Kitaoka 120a6e
        int subsampling                      = 1;
Shinya Kitaoka 120a6e
        int doPremultiply                    = 0;
Shinya Kitaoka 120a6e
        int whiteTransp                      = 0;
Shinya Kitaoka 120a6e
        int antialiasSoftness                = 0;
Shinya Kitaoka 120a6e
        LevelProperties::DpiPolicy dpiPolicy = LevelProperties::DP_ImageDpi;
Shinya Kitaoka 120a6e
        if (is.getTagParam("dpix", v)) xdpi = std::stod(v);
Shinya Kitaoka 120a6e
        if (is.getTagParam("dpiy", v)) ydpi = std::stod(v);
Shinya Kitaoka 120a6e
        if (xdpi != 0 && ydpi != 0) dpiPolicy = LevelProperties::DP_CustomDpi;
Shinya Kitaoka 120a6e
        std::string dpiType                   = is.getTagAttribute("dpiType");
Shinya Kitaoka 120a6e
        if (dpiType == "image") dpiPolicy     = LevelProperties::DP_ImageDpi;
Shinya Kitaoka 120a6e
        if (is.getTagParam("type", v) && v == "s") type       = TZI_XSHLEVEL;
Shinya Kitaoka 120a6e
        if (is.getTagParam("subsampling", v)) subsampling     = std::stoi(v);
Shinya Kitaoka 120a6e
        if (is.getTagParam("premultiply", v)) doPremultiply   = std::stoi(v);
Shinya Kitaoka 120a6e
        if (is.getTagParam("antialias", v)) antialiasSoftness = std::stoi(v);
Shinya Kitaoka 120a6e
        if (is.getTagParam("whiteTransp", v)) whiteTransp     = std::stoi(v);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        m_properties->setDpiPolicy(dpiPolicy);
Shinya Kitaoka 120a6e
        m_properties->setDpi(TPointD(xdpi, ydpi));
Shinya Kitaoka 120a6e
        m_properties->setSubsampling(subsampling);
Shinya Kitaoka 120a6e
        m_properties->setDoPremultiply(doPremultiply);
Shinya Kitaoka 120a6e
        m_properties->setDoAntialias(antialiasSoftness);
Shinya Kitaoka 120a6e
        m_properties->setWhiteTransp(whiteTransp);
Shinya Kitaoka 120a6e
      } else
Shinya Kitaoka 120a6e
        throw TException("unexpected tag " + tagName);
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      if (flag) break;  // ci puo' essere un solo nome
Shinya Kitaoka 120a6e
      flag = true;
Shinya Kitaoka 120a6e
      std::wstring token;
Shinya Kitaoka 120a6e
      is >> token;
Shinya Kitaoka 120a6e
      if (token == L"__empty") {
Shinya Kitaoka 120a6e
        // empty = true;
Shinya Kitaoka 120a6e
        is >> token;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (token == L"_raster")  // obsoleto (Tab2.2)
Shinya Kitaoka 120a6e
      {
Shinya Kitaoka 120a6e
        double xdpi = 1, ydpi = 1;
Shinya Kitaoka 120a6e
        is >> xdpi >> ydpi >> m_name;
Shinya Kitaoka 120a6e
        setName(m_name);
Shinya Kitaoka 120a6e
        type = OVL_XSHLEVEL;
Shinya Kitaoka 120a6e
        m_properties->setDpi(TPointD(xdpi, ydpi));
Shinya Kitaoka 120a6e
        setType(type);
Shinya Kitaoka 120a6e
        setPath(
Shinya Kitaoka 120a6e
            TFilePath("+drawings/") + (getName() + L"." + ::to_wstring("bmp")),
Shinya Kitaoka 120a6e
            true);
Shinya Kitaoka 120a6e
      } else if (token == L"__raster")  // obsoleto (Tab2.2)
Shinya Kitaoka 120a6e
      {
Shinya Kitaoka 120a6e
        double xdpi = 1, ydpi = 1;
Shinya Kitaoka 120a6e
        std::string extension;
Shinya Kitaoka 120a6e
        is >> xdpi >> ydpi >> m_name >> extension;
Shinya Kitaoka 120a6e
        setName(m_name);
Shinya Kitaoka 120a6e
        type = OVL_XSHLEVEL;
Shinya Kitaoka 120a6e
        m_properties->setDpi(TPointD(xdpi, ydpi));
Shinya Kitaoka 120a6e
        setType(type);
Shinya Kitaoka 120a6e
        setPath(TFilePath("+drawings/") +
Shinya Kitaoka 120a6e
                    (getName() + L"." + ::to_wstring(extension)),
Shinya Kitaoka 120a6e
                true);
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        m_name = token;
Shinya Kitaoka 120a6e
        setName(m_name);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (type == UNKNOWN_XSHLEVEL) {
Shinya Kitaoka 120a6e
    std::string ext = m_path.getType();
Shinya Kitaoka 120a6e
    if (ext == "pli" || ext == "svg")
Shinya Kitaoka 120a6e
      type = PLI_XSHLEVEL;
Shinya Kitaoka 120a6e
    else if (ext == "tlv" || ext == "tzu" || ext == "tzp" || ext == "tzl")
Shinya Kitaoka 120a6e
      type = TZP_XSHLEVEL;
Shinya Kitaoka 120a6e
    else if (ext == "tzi")
Shinya Kitaoka 120a6e
      type = TZI_XSHLEVEL;
Shinya Kitaoka 120a6e
    else if (ext == "mesh")
Shinya Kitaoka 120a6e
      type = MESH_XSHLEVEL;
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      type = OVL_XSHLEVEL;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  setType(type);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Shinya Kitaoka 120a6e
class LoadingLevelRange {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  TFrameId m_fromFid, m_toFid;
Shinya Kitaoka 120a6e
  LoadingLevelRange() : m_fromFid(1), m_toFid(0) {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool match(const TFrameId &fid) const {
Shinya Kitaoka 120a6e
    /*-- ↓SubSequent範囲内にある条件		↓全部ロードする場合 --*/
Shinya Kitaoka 120a6e
    return m_fromFid <= fid && fid <= m_toFid || m_fromFid > m_toFid;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  bool isEnabled() const { return m_fromFid <= m_toFid; }
Shinya Kitaoka 120a6e
  void reset() {
Shinya Kitaoka 120a6e
    m_fromFid = TFrameId(1);
Shinya Kitaoka 120a6e
    m_toFid   = TFrameId(0);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} loadingLevelRange;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void setLoadingLevelRange(const TFrameId &fromFid, const TFrameId &toFid) {
Shinya Kitaoka 120a6e
  loadingLevelRange.m_fromFid = fromFid;
Shinya Kitaoka 120a6e
  loadingLevelRange.m_toFid   = toFid;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void getLoadingLevelRange(TFrameId &fromFid, TFrameId &toFid) {
Shinya Kitaoka 120a6e
  fromFid = loadingLevelRange.m_fromFid;
Shinya Kitaoka 120a6e
  toFid   = loadingLevelRange.m_toFid;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFilePath getLevelPathAndSetNameWithPsdLevelName(TXshSimpleLevel *xshLevel) {
Shinya Kitaoka 120a6e
  TFilePath retfp = xshLevel->getPath();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  QString name     = QString::fromStdWString(retfp.getWideName());
Shinya Kitaoka 120a6e
  QStringList list = name.split("#");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (list.size() >= 2 && list.at(1) != "frames") {
Shinya Kitaoka 120a6e
    bool hasLayerId;
Shinya Kitaoka 120a6e
    int layid                  = list.at(1).toInt(&hasLayerId);
Shinya Kitaoka 120a6e
    QTextCodec *layerNameCodec = QTextCodec::codecForName(
Shinya Kitaoka 120a6e
        Preferences::instance()->getLayerNameEncoding().c_str());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (hasLayerId) {
Shinya Kitaoka 120a6e
      // An explicit photoshop layer id must be converted to the associated
Shinya Kitaoka 120a6e
      // level name
Shinya Kitaoka 120a6e
      TPSDParser psdparser(xshLevel->getScene()->decodeFilePath(retfp));
Shinya Kitaoka 120a6e
      std::string levelName = psdparser.getLevelNameWithCounter(
Shinya Kitaoka 120a6e
          layid);  // o_o  what about UNICODE names??
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      list[1]                 = layerNameCodec->toUnicode(levelName.c_str());
Shinya Kitaoka 120a6e
      std::wstring wLevelName = list.join("#").toStdWString();
Shinya Kitaoka 120a6e
      retfp                   = retfp.withName(wLevelName);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      TLevelSet *levelSet = xshLevel->getScene()->getLevelSet();
Shinya Kitaoka 120a6e
      if (levelSet &&
Shinya Kitaoka 120a6e
          levelSet->hasLevel(
Shinya Kitaoka 120a6e
              wLevelName))  // levelSet should be asserted instead
Shinya Kitaoka 120a6e
        levelSet->renameLevel(xshLevel, wLevelName);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      xshLevel->setName(wLevelName);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return retfp;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Nota: load() NON fa clearFrames(). si limita ad aggiungere le informazioni
Toshihiro Shimizu 890ddd
// relative ai frames su disco
Shinya Kitaoka 120a6e
void TXshSimpleLevel::load() {
Shinya Kitaoka 120a6e
  getProperties()->setCreator("");
Shinya Kitaoka 120a6e
  QString creator;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(getScene());
Shinya Kitaoka 120a6e
  if (!getScene()) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_isSubsequence = loadingLevelRange.isEnabled();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TFilePath checkpath = getScene()->decodeFilePath(m_path);
Shinya Kitaoka 120a6e
  std::string type    = checkpath.getType();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_scannedPath != TFilePath()) {
Shinya Kitaoka 120a6e
    getProperties()->setDirtyFlag(
Shinya Kitaoka 120a6e
        false);  // Level is now supposedly loaded from disk
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    static const int ScannedCleanuppedMask = Scanned | Cleanupped;
Shinya Kitaoka 120a6e
    TFilePath path = getScene()->decodeFilePath(m_scannedPath);
Shinya Kitaoka 120a6e
    if (TSystem::doesExistFileOrLevel(path)) {
Shinya Kitaoka 120a6e
      TLevelReaderP lr(path);
Shinya Kitaoka 120a6e
      assert(lr);
Shinya Kitaoka 120a6e
      TLevelP level = lr->loadInfo();
Shinya Kitaoka 120a6e
      if (!checkCreatorString(creator = lr->getCreator()))
Shinya Kitaoka 120a6e
        getProperties()->setIsForbidden(true);
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        for (TLevel::Iterator it = level->begin(); it != level->end(); it++) {
Shinya Kitaoka 120a6e
          TFrameId fid = it->first;
Shinya Kitaoka 120a6e
          if (!loadingLevelRange.match(fid)) continue;
Shinya Kitaoka 120a6e
          setFrameStatus(
Shinya Kitaoka 120a6e
              fid, (getFrameStatus(fid) & ~ScannedCleanuppedMask) | Scanned);
Shinya Kitaoka 120a6e
          setFrame(fid, TImageP());
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    path = getScene()->decodeFilePath(m_path);
Shinya Kitaoka 120a6e
    if (TSystem::doesExistFileOrLevel(path)) {
Shinya Kitaoka 120a6e
      TLevelReaderP lr(path);
Shinya Kitaoka 120a6e
      assert(lr);
Shinya Kitaoka 120a6e
      TLevelP level = lr->loadInfo();
Shinya Kitaoka 120a6e
      if (getType() & FULLCOLOR_TYPE)
Shinya Kitaoka 120a6e
        setPalette(FullColorPalette::instance()->getPalette(getScene()));
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        setPalette(level->getPalette());
Shinya Kitaoka 120a6e
      if (!checkCreatorString(creator = lr->getCreator()))
Shinya Kitaoka 120a6e
        getProperties()->setIsForbidden(true);
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        for (TLevel::Iterator it = level->begin(); it != level->end(); it++) {
Shinya Kitaoka 120a6e
          TFrameId fid = it->first;
Shinya Kitaoka 120a6e
          if (!loadingLevelRange.match(fid)) continue;
Shinya Kitaoka 120a6e
          setFrameStatus(fid, getFrameStatus(fid) | Cleanupped);
Shinya Kitaoka 120a6e
          setFrame(fid, TImageP());
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      setContentHistory(
Shinya Kitaoka 120a6e
          lr->getContentHistory() ? lr->getContentHistory()->clone() : 0);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    // Not a scan + cleanup level
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (m_path.getType() == "psd" &&
Shinya Kitaoka 120a6e
        this->getScene()->getVersionNumber().first < 71)
Shinya Kitaoka 120a6e
      m_path = getLevelPathAndSetNameWithPsdLevelName(this);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TFilePath path = getScene()->decodeFilePath(m_path);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    getProperties()->setDirtyFlag(
Shinya Kitaoka 120a6e
        false);  // Level is now supposedly loaded from disk
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TLevelReaderP lr(path);  // May throw
Shinya Kitaoka 120a6e
    assert(lr);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TLevelP level = lr->loadInfo();
Shinya Kitaoka 120a6e
    if (level->getFrameCount() > 0) {
Shinya Kitaoka 120a6e
      const TImageInfo *info = lr->getImageInfo(level->begin()->first);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (info && info->m_samplePerPixel >= 5) {
Shinya Kitaoka 120a6e
        QString msg = QString(
Shinya Kitaoka 120a6e
                          "Failed to open %1.\nSamples per pixel is more than "
Shinya Kitaoka 120a6e
                          "4. It may containt more than one alpha channel.")
Shinya Kitaoka 120a6e
                          .arg(QString::fromStdWString(m_path.getWideString()));
Shinya Kitaoka 120a6e
        QMessageBox::warning(0, "Image format not supported", msg);
Shinya Kitaoka 120a6e
        return;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (info) set16BitChannelLevel(info->m_bitsPerSample == 16);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if ((getType() & FULLCOLOR_TYPE) && !is16BitChannelLevel())
Shinya Kitaoka 120a6e
      setPalette(FullColorPalette::instance()->getPalette(getScene()));
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      setPalette(level->getPalette());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!checkCreatorString(creator = lr->getCreator()))
Shinya Kitaoka 120a6e
      getProperties()->setIsForbidden(true);
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      for (TLevel::Iterator it = level->begin(); it != level->end(); it++) {
Shinya Kitaoka 120a6e
        m_renumberTable[it->first] = it->first;  // Voglio che la tabella
Shinya Kitaoka 120a6e
                                                 // contenga anche i frame che
Shinya Kitaoka 120a6e
                                                 // non vengono caricati
Shinya Kitaoka 120a6e
        if (!loadingLevelRange.match(it->first)) continue;
Shinya Kitaoka 120a6e
        setFrame(it->first, TImageP());
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    setContentHistory(lr->getContentHistory() ? lr->getContentHistory()->clone()
Shinya Kitaoka 120a6e
                                              : 0);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  getProperties()->setCreator(creator.toStdString());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  loadingLevelRange.reset();
Shinya Kitaoka 120a6e
  if (getType() != PLI_XSHLEVEL) {
Shinya Kitaoka 120a6e
    if (m_properties->getImageDpi() == TPointD() && !m_frames.empty()) {
Shinya Kitaoka 120a6e
      TDimension imageRes(0, 0);
Shinya Kitaoka 120a6e
      TPointD imageDpi;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      const TFrameId &firstFid = getFirstFid();
Shinya Kitaoka 120a6e
      std::string imageId      = getImageId(firstFid);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      const TImageInfo *imageInfo =
Shinya Kitaoka 120a6e
          ImageManager::instance()->getInfo(imageId, ImageManager::none, 0);
Shinya Kitaoka 120a6e
      if (imageInfo) {
Shinya Kitaoka 120a6e
        imageRes.lx = imageInfo->m_lx;
Shinya Kitaoka 120a6e
        imageRes.ly = imageInfo->m_ly;
Shinya Kitaoka 120a6e
        imageDpi.x  = imageInfo->m_dpix;
Shinya Kitaoka 120a6e
        imageDpi.y  = imageInfo->m_dpiy;
Shinya Kitaoka 120a6e
        m_properties->setImageDpi(imageDpi);
Shinya Kitaoka 120a6e
        m_properties->setImageRes(imageRes);
Shinya Kitaoka 120a6e
        m_properties->setBpp(imageInfo->m_bitsPerSample *
Shinya Kitaoka 120a6e
                             imageInfo->m_samplePerPixel);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    setRenumberTable();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (getPalette() && StudioPalette::isEnabled())
Shinya Kitaoka 120a6e
    StudioPalette::instance()->updateLinkedColors(getPalette());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TFilePath refImgName;
Shinya Kitaoka 120a6e
  if (m_palette) {
Shinya Kitaoka 120a6e
    refImgName           = m_palette->getRefImgPath();
Shinya Kitaoka 120a6e
    TFilePath refImgPath = refImgName;
Shinya Kitaoka 120a6e
    if (refImgName != TFilePath() && TFileStatus(refImgPath).doesExist()) {
Shinya Kitaoka 120a6e
      TLevelReaderP lr(refImgPath);
Shinya Kitaoka 120a6e
      if (lr) {
Shinya Kitaoka 120a6e
        TLevelP level = lr->loadInfo();
Shinya Kitaoka 120a6e
        if (level->getFrameCount() > 0) {
Shinya Kitaoka 120a6e
          TImageP img = lr->getFrameReader(level->begin()->first)->load();
Shinya Kitaoka 120a6e
          if (img && getPalette()) {
Shinya Kitaoka 120a6e
            img->setPalette(0);
Shinya Kitaoka 120a6e
            getPalette()->setRefImg(img);
Shinya Kitaoka 120a6e
            std::vector<TFrameId> fids;
Shinya Kitaoka 120a6e
            for (TLevel::Iterator it = level->begin(); it != level->end(); ++it)
Shinya Kitaoka 120a6e
              fids.push_back(it->first);
Shinya Kitaoka 120a6e
            getPalette()->setRefLevelFids(fids);
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Load hooks
Shinya Kitaoka 120a6e
  HookSet *hookSet = getHookSet();
Shinya Kitaoka 120a6e
  hookSet->clearHooks();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const TFilePath &hookFile =
Shinya Kitaoka 120a6e
      TXshSimpleLevel::getExistingHookFile(getScene()->decodeFilePath(m_path));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!hookFile.isEmpty()) {
Shinya Kitaoka 120a6e
    TIStream is(hookFile);
Shinya Kitaoka 120a6e
    std::string tagName;
Shinya Kitaoka 120a6e
    try {
Shinya Kitaoka 120a6e
      if (is.matchTag(tagName) && tagName == "hooks") hookSet->loadData(is);
Shinya Kitaoka 120a6e
    } catch (...) {
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  updateReadOnly();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::load(const std::vector<TFrameId> &fIds) {
Shinya Kitaoka 120a6e
  getProperties()->setCreator("");
Shinya Kitaoka 120a6e
  QString creator;
Shinya Kitaoka 120a6e
  assert(getScene());
Shinya Kitaoka 120a6e
  getProperties()->setDirtyFlag(false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_isSubsequence = loadingLevelRange.isEnabled();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // non e' un livello scan+cleanup
Shinya Kitaoka 120a6e
  TFilePath path = getScene()->decodeFilePath(m_path);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TLevelReaderP lr(path);
Shinya Kitaoka 120a6e
  assert(lr);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (!checkCreatorString(creator = lr->getCreator()))
Shinya Kitaoka 120a6e
    getProperties()->setIsForbidden(true);
Shinya Kitaoka 120a6e
  else {
Shinya Kitaoka 120a6e
    if (fIds.size() != 0) {
Shinya Kitaoka 120a6e
      for (int i = 0; i < (int)fIds.size(); i++) {
Shinya Kitaoka 120a6e
        m_renumberTable[fIds[i]] = fIds[i];
Shinya Kitaoka 120a6e
        if (!loadingLevelRange.match(fIds[i])) continue;
Shinya Kitaoka 120a6e
        setFrame(fIds[i], TImageP());
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      TLevelP level = lr->loadInfo();
Shinya Kitaoka 120a6e
      for (TLevel::Iterator it = level->begin(); it != level->end(); it++) {
Shinya Kitaoka 120a6e
        m_renumberTable[it->first] = it->first;
Shinya Kitaoka 120a6e
        if (!loadingLevelRange.match(it->first)) continue;
Shinya Kitaoka 120a6e
        setFrame(it->first, TImageP());
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  setContentHistory(lr->getContentHistory() ? lr->getContentHistory()->clone()
Shinya Kitaoka 120a6e
                                            : 0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  getProperties()->setCreator(creator.toStdString());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  loadingLevelRange.reset();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (getType() != PLI_XSHLEVEL) {
Shinya Kitaoka 120a6e
    if (m_properties->getImageDpi() == TPointD() && !m_frames.empty()) {
Shinya Kitaoka 120a6e
      TDimension imageRes(0, 0);
Shinya Kitaoka 120a6e
      TPointD imageDpi;
Shinya Kitaoka 120a6e
      std::string imageId = getImageId(getFirstFid());
Shinya Kitaoka 120a6e
      const TImageInfo *imageInfo =
Shinya Kitaoka 120a6e
          ImageManager::instance()->getInfo(imageId, ImageManager::none, 0);
Shinya Kitaoka 120a6e
      if (imageInfo) {
Shinya Kitaoka 120a6e
        imageRes.lx = imageInfo->m_lx;
Shinya Kitaoka 120a6e
        imageRes.ly = imageInfo->m_ly;
Shinya Kitaoka 120a6e
        imageDpi.x  = imageInfo->m_dpix;
Shinya Kitaoka 120a6e
        imageDpi.y  = imageInfo->m_dpiy;
Shinya Kitaoka 120a6e
        m_properties->setImageDpi(imageDpi);
Shinya Kitaoka 120a6e
        m_properties->setImageRes(imageRes);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    setRenumberTable();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void TXshSimpleLevel::updateReadOnly() {
Shinya Kitaoka 120a6e
  TFilePath path = getScene()->decodeFilePath(m_path);
Shinya Kitaoka 120a6e
  m_isReadOnly   = isAreadOnlyLevel(path);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::saveData(TOStream &os) {
Shinya Kitaoka 120a6e
  os << m_name;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::map<std::string, std::string> attr;
Shinya Kitaoka 120a6e
  if (getProperties()->getDpiPolicy() == LevelProperties::DP_CustomDpi) {
Shinya Kitaoka 120a6e
    TPointD dpi = getProperties()->getDpi();
Shinya Kitaoka 120a6e
    if (dpi.x != 0 && dpi.y != 0) {
Shinya Kitaoka 120a6e
      attr["dpix"] = std::to_string(dpi.x);
Shinya Kitaoka 120a6e
      attr["dpiy"] = std::to_string(dpi.y);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    attr["dpiType"] = "image";
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (getProperties()->getSubsampling() != 1) {
Shinya Kitaoka 120a6e
    attr["subsampling"] = std::to_string(getProperties()->getSubsampling());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (getProperties()->antialiasSoftness() > 0) {
Shinya Kitaoka 120a6e
    attr["antialias"] = std::to_string(getProperties()->antialiasSoftness());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (getProperties()->doPremultiply()) {
Shinya Kitaoka 120a6e
    attr["premultiply"] = std::to_string(getProperties()->doPremultiply());
Shinya Kitaoka 120a6e
  } else if (getProperties()->whiteTransp()) {
Shinya Kitaoka 120a6e
    attr["whiteTransp"] = std::to_string(getProperties()->whiteTransp());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_type == TZI_XSHLEVEL) attr["type"] = "s";
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  os.openCloseChild("info", attr);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  os.child("path") << m_path;  // fp;
Shinya Kitaoka 120a6e
  if (m_scannedPath != TFilePath())
Shinya Kitaoka 120a6e
    os.child("scannedPath") << m_scannedPath;  // fp;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::save() {
Shinya Kitaoka 120a6e
  assert(getScene());
Shinya Kitaoka 120a6e
  TFilePath path = getScene()->decodeFilePath(m_path);
Shinya Kitaoka 120a6e
  TSystem::outputDebug("save() : " + ::to_string(m_path) + " = " +
Shinya Kitaoka 120a6e
                       ::to_string(path) + "\n");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (getProperties()->getDirtyFlag() == false &&
Shinya Kitaoka 120a6e
      getPalette()->getDirtyFlag() == false &&
Shinya Kitaoka 120a6e
      TSystem::doesExistFileOrLevel(path))
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!TFileStatus(path.getParentDir()).doesExist()) {
Shinya Kitaoka 120a6e
    try {
Shinya Kitaoka 120a6e
      TSystem::mkDir(path.getParentDir());
Shinya Kitaoka 120a6e
    } catch (...) {
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  save(path);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void saveBackup(TFilePath path) {
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    TFilePath backup = path.withName(path.getName() + "_backup");
Shinya Kitaoka 120a6e
    if (TSystem::doesExistFileOrLevel(backup))
Shinya Kitaoka 120a6e
      TSystem::removeFileOrLevel_throw(backup);
Shinya Kitaoka 120a6e
    TSystem::copyFileOrLevel_throw(backup, path);
Shinya Kitaoka 120a6e
  } catch (...) {
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void TXshSimpleLevel::save(const TFilePath &fp, const TFilePath &oldFp,
Shinya Kitaoka 120a6e
                           bool overwritePalette) {
Shinya Kitaoka 120a6e
  TFilePath dOldPath =
Shinya Kitaoka 120a6e
      (!oldFp.isEmpty()) ? oldFp : getScene()->decodeFilePath(m_path);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TFilePath dDstPath = getScene()->decodeFilePath(fp);
Shinya Kitaoka 120a6e
  TSystem::touchParentDir(dDstPath);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // backup
Shinya Kitaoka 120a6e
  if (Preferences::instance()->isLevelsBackupEnabled() &&
Shinya Kitaoka 120a6e
      dOldPath == dDstPath && TSystem::doesExistFileOrLevel(dDstPath))
Shinya Kitaoka 120a6e
    saveBackup(dDstPath);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (isAreadOnlyLevel(dDstPath)) {
Shinya Kitaoka 120a6e
    if (m_editableRange.empty() &&
Shinya Kitaoka 120a6e
        !m_temporaryHookMerged)  // file interaly locked
Shinya Kitaoka 120a6e
      throw TSystemException(
Shinya Kitaoka 120a6e
          dDstPath, "The level cannot be saved: it is a read only level.");
Shinya Kitaoka 120a6e
    else if (getType() != OVL_XSHLEVEL) {
Shinya Kitaoka 120a6e
      // file partially unlocked
Shinya Kitaoka 120a6e
      std::wstring fileName = getEditableFileName();
Shinya Kitaoka 120a6e
      assert(!fileName.empty());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      TFilePath app = dDstPath.withName(fileName).withType(dDstPath.getType());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // removes old files
Shinya Kitaoka 120a6e
      if (TSystem::doesExistFileOrLevel(app)) TSystem::removeFileOrLevel(app);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      TFilePathSet oldFilePaths;
Shinya Kitaoka 120a6e
      getFiles(app, oldFilePaths);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      TFilePathSet::iterator it;
Shinya Kitaoka 120a6e
      for (it = oldFilePaths.begin(); it != oldFilePaths.end(); ++it) {
Shinya Kitaoka 120a6e
        if (TSystem::doesExistFileOrLevel(*it)) TSystem::removeFileOrLevel(*it);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // save new files
Shinya Kitaoka 120a6e
      TXshSimpleLevel *sl = new TXshSimpleLevel;
Shinya Kitaoka 120a6e
      sl->setScene(getScene());
Shinya Kitaoka 120a6e
      sl->setPalette(getPalette());
Shinya Kitaoka 120a6e
      sl->setPath(getScene()->codeFilePath(app));
Shinya Kitaoka 120a6e
      sl->setType(getType());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      std::set<TFrameId>::iterator eft, efEnd;
Shinya Kitaoka 120a6e
      for (eft = m_editableRange.begin(); eft != efEnd; ++eft) {
Shinya Kitaoka 120a6e
        const TFrameId &fid = *eft;
Shinya Kitaoka 120a6e
        sl->setFrame(fid, getFrame(fid, false));
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // Copy hooks
Shinya Kitaoka 120a6e
      HookSet *hookSet = sl->getHookSet();
Shinya Kitaoka 120a6e
      *hookSet         = *getHookSet();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      FramesSet::iterator ft, fEnd = m_frames.end();
Shinya Kitaoka 120a6e
      for (ft = m_frames.begin(); ft != fEnd; ++ft) {
Shinya Kitaoka 120a6e
        const TFrameId &fid = *ft;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (m_editableRange.find(fid) == m_editableRange.end())
Shinya Kitaoka 120a6e
          hookSet->eraseFrame(fid);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // Copy mesh level
Shinya Kitaoka 120a6e
      sl->save(app);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      // hides files
Shinya Kitaoka 120a6e
      oldFilePaths.clear();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      if (TSystem::doesExistFileOrLevel(app)) TSystem::hideFileOrLevel(app);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      getFiles(app, oldFilePaths);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      for (it = oldFilePaths.begin(); it != oldFilePaths.end(); ++it) {
Shinya Kitaoka 120a6e
        if (TSystem::doesExistFileOrLevel(*it)) TSystem::hideFileOrLevel(*it);
Shinya Kitaoka 120a6e
      }
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (dOldPath != dDstPath && m_path != TFilePath()) {
Shinya Kitaoka 120a6e
    const TFilePath &dSrcPath = dOldPath;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    try {
Shinya Kitaoka 120a6e
      if (TSystem::doesExistFileOrLevel(dSrcPath)) {
Shinya Kitaoka 120a6e
        if (TSystem::doesExistFileOrLevel(dDstPath))
Shinya Kitaoka 120a6e
          TSystem::removeFileOrLevel(dDstPath);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
        copyFiles(dDstPath, dSrcPath);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    } catch (...) {
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  // when saving the level palette with global name
Shinya Kitaoka 120a6e
  if (overwritePalette && getType() == TZP_XSHLEVEL && getPalette() &&
Shinya Kitaoka 120a6e
      getPalette()->getGlobalName() != L"") {
Shinya Kitaoka 120a6e
    overwritePalette      = false;
Shinya Kitaoka 120a6e
    TFilePath palettePath = dDstPath.withNoFrame().withType("tpl");
Shinya Kitaoka 120a6e
    StudioPalette::instance()->save(palettePath, getPalette());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  saveSimpleLevel(dDstPath, overwritePalette);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::saveSimpleLevel(const TFilePath &decodedFp,
Shinya Kitaoka 120a6e
                                      bool overwritePalette) {
Shinya Kitaoka 120a6e
  /* Precondition: Destination level with path decodedFp is supposed to already
Shinya Kitaoka 120a6e
             store those image frames not tagged as 'modified' in this level
Shinya Kitaoka 120a6e
             instance. */
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TFilePath oldPath  = m_path;
Shinya Kitaoka 120a6e
  TFilePath dOldPath = getScene()->decodeFilePath(oldPath);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Substitute m_path with decodedFp until the function quits.
Shinya Kitaoka 120a6e
  struct CopyOnExit {
Shinya Kitaoka 120a6e
    TFilePath &m_dstPath, &m_srcPath;
Shinya Kitaoka 120a6e
    ~CopyOnExit() { m_dstPath = m_srcPath; }
Shinya Kitaoka 120a6e
  } copyOnExit = {m_path = decodedFp,
Shinya Kitaoka 120a6e
                  oldPath};  // m_path substituted here until function quits
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool savingOriginal = (decodedFp == dOldPath), paletteNotSaved = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int imFlags = savingOriginal
Shinya Kitaoka 120a6e
                    ? ImageManager::dontPutInCache | ImageManager::toBeSaved
Shinya Kitaoka 120a6e
                    : ImageManager::dontPutInCache;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<TFrameId> fids;
Shinya Kitaoka 120a6e
  getFids(fids);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool isLevelModified                = getProperties()->getDirtyFlag();
Shinya Kitaoka 120a6e
  bool isPaletteModified              = false;
Shinya Kitaoka 120a6e
  if (getPalette()) isPaletteModified = getPalette()->getDirtyFlag();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (isLevelModified || isPaletteModified) {
Shinya Kitaoka 120a6e
    // gmt (8/8/08. provo a risolvere il pasticcio della scrittura dei tlv.
Shinya Kitaoka 120a6e
    // Dobbiamo
Shinya Kitaoka 120a6e
    // ripensarci con piu' calma. Per ora cerco di fare meno danno possibile).
Shinya Kitaoka 120a6e
    TDimension oldRes(0, 0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (TSystem::doesExistFileOrLevel(decodedFp)) {
Shinya Kitaoka 120a6e
      TLevelReaderP lr(decodedFp);
Shinya Kitaoka 120a6e
      const TImageInfo *imageInfo = m_frames.empty()
Shinya Kitaoka 120a6e
                                        ? lr->getImageInfo()
Shinya Kitaoka 120a6e
                                        : lr->getImageInfo(*(m_frames.begin()));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (imageInfo) {
Shinya Kitaoka 120a6e
        oldRes.lx = imageInfo->m_lx;
Shinya Kitaoka 120a6e
        oldRes.ly = imageInfo->m_ly;
Shinya Kitaoka 120a6e
        lr        = TLevelReaderP();
Shinya Kitaoka 120a6e
        if (getProperties()->getImageRes() != oldRes) {
Shinya Kitaoka 120a6e
          // Il comando canvas size cambia le dimensioni del livello!!!
Shinya Kitaoka 120a6e
          // Se il file già esiste, nel level writer vengono risettate le
Shinya Kitaoka 120a6e
          // dimesnioni del file esistente
Shinya Kitaoka 120a6e
          // e salva male
Shinya Kitaoka 120a6e
          TSystem::removeFileOrLevel(decodedFp);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    // overwrite tlv
Shinya Kitaoka 120a6e
    if (decodedFp.getType() == "tlv" &&
Shinya Kitaoka 120a6e
        TSystem::doesExistFileOrLevel(decodedFp)) {
Shinya Kitaoka 120a6e
      if (isLevelModified) {
Shinya Kitaoka 120a6e
        // in questo caso dovrei scrivere solo i frame modificati.
Shinya Kitaoka 120a6e
        // certamente NON DEVO scrivere quelli che non ho (e che dovrei
Shinya Kitaoka 120a6e
        // rileggere dallo stesso file che sto scrivendo
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        int oldSubs = getProperties()->getSubsampling();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        TLevelWriterP lw;
Shinya Kitaoka 120a6e
        try {
Shinya Kitaoka 120a6e
          lw = TLevelWriterP(decodedFp);
Shinya Kitaoka 120a6e
        } catch (...) {
Shinya Kitaoka 120a6e
          // revert subsampling
Shinya Kitaoka 120a6e
          m_properties->setSubsampling(oldSubs);
Shinya Kitaoka 120a6e
          m_path = oldPath;
Shinya Kitaoka 120a6e
          throw TSystemException(decodedFp,
Shinya Kitaoka 120a6e
                                 "can't fopen.\nSomeone may be saving the same "
Shinya Kitaoka 120a6e
                                 "file. Please wait a while and retry.");
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        lw->setOverwritePaletteFlag(overwritePalette);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        lw->setCreator(getCreatorString());
Shinya Kitaoka 120a6e
        lw->setPalette(getPalette());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        // Filter out of the renumber table all non-tlv frames (could happen if
Shinya Kitaoka 120a6e
        // the level
Shinya Kitaoka 120a6e
        // is a scan-cleanup mix). This is fine even on the temporarily
Shinya Kitaoka 120a6e
        // substituted m_path.
Shinya Kitaoka 120a6e
        std::map<TFrameId, TFrameId> renumberTable;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        for (auto it = m_renumberTable.rbegin(); it != m_renumberTable.rend();
Shinya Kitaoka 120a6e
             ++it) {
Shinya Kitaoka 120a6e
          TFrameId id = (*it).first;
Shinya Kitaoka 120a6e
          if ((getFrameStatus(id) != Scanned) &&
Shinya Kitaoka 120a6e
              (getFrameStatus(id) != CleanupPreview)) {
Shinya Kitaoka 120a6e
            renumberTable[id] = (*it).second;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        m_renumberTable.clear();
Shinya Kitaoka 120a6e
        m_renumberTable = renumberTable;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        lw->setIconSize(Preferences::instance()->getIconSize());
Shinya Kitaoka 120a6e
        if (!isSubsequence()) lw->renumberFids(m_renumberTable);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (getContentHistory())
Shinya Kitaoka 120a6e
          lw->setContentHistory(getContentHistory()->clone());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        ImageLoader::BuildExtData extData(this, TFrameId());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        for (auto const &fid : fids) {
Shinya Kitaoka 120a6e
          std::string imageId = getImageId(
Shinya Kitaoka 120a6e
              fid, Normal);  // Retrieve the actual level frames ("L_whatever")
Shinya Kitaoka 120a6e
          if (!ImageManager::instance()->isModified(imageId)) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          extData.m_fid = fid;
Shinya Kitaoka 120a6e
          TImageP img =
Shinya Kitaoka 120a6e
              ImageManager::instance()->getImage(imageId, imFlags, &extData);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          assert(img);
Shinya Kitaoka 120a6e
          if (!img) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          int subs = 1;
Shinya Kitaoka 120a6e
          if (TToonzImageP ti = img)
Shinya Kitaoka 120a6e
            subs = ti->getSubsampling();
Shinya Kitaoka 120a6e
          else if (TRasterImageP ri = img)
Shinya Kitaoka 120a6e
            subs = ri->getSubsampling();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          assert(subs == 1);
Shinya Kitaoka 120a6e
          if (subs != 1) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          if (TToonzImageP ti = img) {
Shinya Kitaoka 120a6e
            /*-
Shinya Kitaoka 120a6e
             * SaveBoxを塗り漏れ防止に使用している場合、実際の画像範囲とSaveBoxのサイズが異なるため、ここで更新しておく-*/
Shinya Kitaoka 120a6e
            TRect saveBox;
Shinya Kitaoka 120a6e
            TRop::computeBBox(ti->getRaster(), saveBox);
Shinya Kitaoka 120a6e
            ti->setSavebox(saveBox);
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          lw->getFrameWriter(fid)->save(img);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        lw = TLevelWriterP();  // TLevelWriterP's destructor saves the palette
Shinya Kitaoka 120a6e
      } else if (isPaletteModified && overwritePalette) {
Shinya Kitaoka 120a6e
        TFilePath palettePath = decodedFp.withNoFrame().withType("tpl");
Shinya Kitaoka 120a6e
        if (Preferences::instance()->isLevelsBackupEnabled() &&
Shinya Kitaoka 120a6e
            TSystem::doesExistFileOrLevel(palettePath))
Shinya Kitaoka 120a6e
          saveBackup(palettePath);
Shinya Kitaoka 120a6e
        TOStream os(palettePath);
Shinya Kitaoka 120a6e
        if (os.checkStatus())
Shinya Kitaoka 120a6e
          os << getPalette();
Shinya Kitaoka 120a6e
        else
Shinya Kitaoka 120a6e
          paletteNotSaved = true;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      // per ora faccio quello che facevo prima, ma dobbiamo rivedere tutta la
Shinya Kitaoka 120a6e
      // strategia
Shinya Kitaoka 120a6e
      LevelUpdater updater(this);
Shinya Kitaoka 120a6e
      updater.getLevelWriter()->setCreator(getCreatorString());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (isLevelModified) {
Shinya Kitaoka 120a6e
        // Apply the level's renumber table, before saving other files.
Shinya Kitaoka 120a6e
        // NOTE: This is currently NOT under LevelUpdater's responsibility, as
Shinya Kitaoka 120a6e
        // renumber tables
Shinya Kitaoka 120a6e
        // are set/manipulated heavily here. The approach should be re-designed,
Shinya Kitaoka 120a6e
        // though...
Shinya Kitaoka 120a6e
        updater.getLevelWriter()->renumberFids(m_renumberTable);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (!m_editableRange.empty())
Shinya Kitaoka 120a6e
          fids = std::vector<TFrameId>(m_editableRange.begin(),
Shinya Kitaoka 120a6e
                                       m_editableRange.end());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        ImageLoader::BuildExtData extData(this, TFrameId());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        for (auto const &fid : fids) {
Shinya Kitaoka 120a6e
          std::string imageId = getImageId(
Shinya Kitaoka 120a6e
              fid, Normal);  // Retrieve the actual level frames ("L_whatever")
Shinya Kitaoka 120a6e
          if (!ImageManager::instance()->isModified(imageId)) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          extData.m_fid = fid;
Shinya Kitaoka 120a6e
          TImageP img =
Shinya Kitaoka 120a6e
              ImageManager::instance()->getImage(imageId, imFlags, &extData);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          assert(img);
Shinya Kitaoka 120a6e
          if (!img) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          int subs = 1;
Shinya Kitaoka 120a6e
          if (TToonzImageP ti = img)
Shinya Kitaoka 120a6e
            subs = ti->getSubsampling();
Shinya Kitaoka 120a6e
          else if (TRasterImageP ri = img)
Shinya Kitaoka 120a6e
            subs = ri->getSubsampling();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          assert(subs == 1);
Shinya Kitaoka 120a6e
          if (subs != 1) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          updater.update(fid, img);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      updater.close();  // Needs the original level subs
Shinya Kitaoka 120a6e
      if ((getType() & FULLCOLOR_TYPE) && isPaletteModified)
Shinya Kitaoka 120a6e
        FullColorPalette::instance()->savePalette(getScene());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Save hooks
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TFilePath hookFile;
Shinya Kitaoka 120a6e
  HookSet *hookSet = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Save the hookSet in a temporary hook file
Shinya Kitaoka 120a6e
  if (getType() == OVL_XSHLEVEL && !m_editableRange.empty()) {
Shinya Kitaoka 120a6e
    hookSet = new HookSet(*getHookSet());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    FramesSet::const_iterator it;
Shinya Kitaoka 120a6e
    for (it = m_frames.begin(); it != m_frames.end(); ++it) {
Shinya Kitaoka 120a6e
      TFrameId fid = *it;
Shinya Kitaoka 120a6e
      if (m_editableRange.find(fid) == m_editableRange.end())
Shinya Kitaoka 120a6e
        hookSet->eraseFrame(fid);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // file partially unlocked
Shinya Kitaoka 120a6e
    std::wstring fileName = getEditableFileName();
Shinya Kitaoka 120a6e
    assert(!fileName.empty());
Shinya Kitaoka 120a6e
    TFilePath app = decodedFp.withName(fileName).withType(decodedFp.getType());
Shinya Kitaoka 120a6e
    hookFile      = getHookPath(app);
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    hookFile = getHookPath(decodedFp);
Shinya Kitaoka 120a6e
    hookSet  = getHookSet();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Shinya Kitaoka 120a6e
  // Remove the hidden attribute (since TOStream's fopen fails on hidden files)
Shinya Kitaoka 120a6e
  if (getType() == OVL_XSHLEVEL && !m_editableRange.empty())
Shinya Kitaoka 120a6e
    SetFileAttributesW(hookFile.getWideString().c_str(), FILE_ATTRIBUTE_NORMAL);
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (hookSet && hookSet->getHookCount() > 0) {
Shinya Kitaoka 120a6e
    TOStream os(hookFile);
Shinya Kitaoka 120a6e
    os.openChild("hooks");
Shinya Kitaoka 120a6e
    hookSet->saveData(os);
Shinya Kitaoka 120a6e
    os.closeChild();
Shinya Kitaoka 120a6e
  } else if (TFileStatus(hookFile).doesExist()) {
Shinya Kitaoka 120a6e
    try {
Shinya Kitaoka 120a6e
      TSystem::deleteFile(hookFile);
Shinya Kitaoka 120a6e
    } catch (...) {
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Shinya Kitaoka 120a6e
  if (getType() == OVL_XSHLEVEL && !m_editableRange.empty())
Shinya Kitaoka 120a6e
    TSystem::hideFileOrLevel(hookFile);
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (savingOriginal) {
Shinya Kitaoka 120a6e
    setRenumberTable();  // Since the renumber table refers to the
Shinya Kitaoka 120a6e
                         // 'original' frames saved on disk
Shinya Kitaoka 120a6e
    if (m_properties) m_properties->setDirtyFlag(false);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (getPalette() && overwritePalette) getPalette()->setDirtyFlag(false);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (paletteNotSaved)
Shinya Kitaoka 120a6e
    throw TSystemException(m_path,
Shinya Kitaoka 120a6e
                           "The palette of the level could not be saved.");
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
std::string TXshSimpleLevel::getImageId(const TFrameId &fid,
Shinya Kitaoka 120a6e
                                        int frameStatus) const {
Shinya Kitaoka 120a6e
  if (frameStatus < 0) frameStatus = getFrameStatus(fid);
Shinya Kitaoka 120a6e
  std::string prefix               = "L";
Shinya Kitaoka 120a6e
  if (frameStatus & CleanupPreview)
Shinya Kitaoka 120a6e
    prefix = "P";
Shinya Kitaoka 120a6e
  else if ((frameStatus & (Scanned | Cleanupped)) == Scanned)
Shinya Kitaoka 120a6e
    prefix            = "S";
Shinya Kitaoka 120a6e
  std::string imageId = m_idBase + "_" + prefix + fid.expand();
Shinya Kitaoka 120a6e
  return imageId;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int TXshSimpleLevel::getFrameStatus(const TFrameId &fid) const {
Shinya Kitaoka 120a6e
  std::map<TFrameId, int>::const_iterator it = m_framesStatus.find(fid);
Shinya Kitaoka 120a6e
  return (it != m_framesStatus.end()) ? it->second : Normal;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::setFrameStatus(const TFrameId &fid, int status) {
Shinya Kitaoka 120a6e
  assert((status & ~(Scanned | Cleanupped | CleanupPreview)) == 0);
Shinya Kitaoka 120a6e
  m_framesStatus[fid] = status;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*- CleanupPopup::setCurrentLevel / TCleanupper で使用 -*/
Shinya Kitaoka 120a6e
void TXshSimpleLevel::makeTlv(const TFilePath &tlvPath) {
Shinya Kitaoka 120a6e
  int ltype = getType();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (!(ltype & FULLCOLOR_TYPE)) {
Shinya Kitaoka 120a6e
    assert(ltype & FULLCOLOR_TYPE);
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  setType(TZP_XSHLEVEL);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_scannedPath = m_path;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  assert(tlvPath.getType() == "tlv");
Shinya Kitaoka 120a6e
  m_path = tlvPath;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  FramesSet::const_iterator it;
Shinya Kitaoka 120a6e
  for (it = m_frames.begin(); it != m_frames.end(); ++it) {
Shinya Kitaoka 120a6e
    TFrameId fid = *it;
Shinya Kitaoka 120a6e
    setFrameStatus(fid, Scanned);
Shinya Kitaoka 120a6e
    ImageManager::instance()->rebind(getImageId(fid, Scanned),
Shinya Kitaoka 120a6e
                                     getImageId(fid, 0));
Shinya Kitaoka 120a6e
    ImageManager::instance()->rebind(getIconId(fid, Scanned),
Shinya Kitaoka 120a6e
                                     getIconId(fid, 0));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::invalidateFrames() {
Shinya Kitaoka 120a6e
  FramesSet::iterator ft, fEnd = m_frames.end();
Shinya Kitaoka 120a6e
  for (ft = m_frames.begin(); ft != fEnd; ++ft)
Shinya Kitaoka 120a6e
    ImageManager::instance()->invalidate(getImageId(*ft));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*- 指定したFIdのみInvalidateする -*/
Shinya Kitaoka 120a6e
void TXshSimpleLevel::invalidateFrame(const TFrameId &fid) {
Shinya Kitaoka 120a6e
  std::string id = getImageId(fid);
Shinya Kitaoka 120a6e
  ImageManager::instance()->invalidate(id);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// crea un frame con tipo, dimensioni, dpi, ecc. compatibili con il livello
Shinya Kitaoka 120a6e
TImageP TXshSimpleLevel::createEmptyFrame() {
Shinya Kitaoka 120a6e
  TImageP result;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  switch (m_type) {
Shinya Kitaoka 120a6e
  case PLI_XSHLEVEL:
Shinya Kitaoka 120a6e
    result = new TVectorImage;
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  case MESH_XSHLEVEL:
Shinya Kitaoka 120a6e
    assert(false);  // Not implemented yet
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  default: {
Shinya Kitaoka 120a6e
    // normally the image must have the level->getProperties()->getImageDpi().
Shinya Kitaoka 120a6e
    // if this value is missing (for some reason - can this happen, ever?) then
Shinya Kitaoka 120a6e
    // we use the getDpi() (that is the current dpi, e.g. cameraDpi or
Shinya Kitaoka 120a6e
    // customDpi).
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TPointD dpi = getProperties()->getImageDpi();
Shinya Kitaoka 120a6e
    /*--
Shinya Kitaoka 120a6e
    tgaからtlvにconvertしたものをInsert Pasteしたとき、
Shinya Kitaoka 120a6e
    ペーストしたフレームにのみDPIが付いてしまうので、この処理は省く
Shinya Kitaoka 120a6e
    --*/
Shinya Kitaoka 120a6e
    // if(dpi.x==0.0 || dpi.y==0.0)
Shinya Kitaoka 120a6e
    //  dpi = getProperties()->getDpi();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TDimension res = getProperties()->getImageRes();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (m_type == TZP_XSHLEVEL) {
Shinya Kitaoka 120a6e
      TRasterCM32P raster(res);
Shinya Kitaoka 120a6e
      raster->fill(TPixelCM32());
Shinya Kitaoka 120a6e
      TToonzImageP ti(raster, TRect());
Shinya Kitaoka 120a6e
      ti->setDpi(dpi.x, dpi.y);
Shinya Kitaoka 120a6e
      ti->setSavebox(TRect(0, 0, res.lx - 1, res.ly - 1));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      result = ti;
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      TRaster32P raster(res);
Shinya Kitaoka 120a6e
      raster->fill(TPixel32(0, 0, 0, 0));
Shinya Kitaoka 120a6e
      TRasterImageP ri(raster);
Shinya Kitaoka 120a6e
      ri->setDpi(dpi.x, dpi.y);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      result = ri;
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return result;
Shinya Kitaoka 120a6e
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// ritorna la risoluzione dei frames del livello (se il livello non e'
Shinya Kitaoka 120a6e
// vettoriale)
Shinya Kitaoka 120a6e
TDimension TXshSimpleLevel::getResolution() {
Shinya Kitaoka 120a6e
  if (isEmpty() || getType() == PLI_XSHLEVEL) return TDimension();
Shinya Kitaoka 120a6e
  return m_properties->getImageRes();
Shinya Kitaoka 120a6e
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// ritorna il dpi letto da file
Shinya Kitaoka 120a6e
TPointD TXshSimpleLevel::getImageDpi(const TFrameId &fid, int frameStatus) {
Shinya Kitaoka 120a6e
  if (isEmpty() || getType() == PLI_XSHLEVEL) return TPointD();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const TFrameId &theFid =
Shinya Kitaoka 120a6e
      (fid == TFrameId::NO_FRAME || !isFid(fid)) ? getFirstFid() : fid;
Shinya Kitaoka 120a6e
  const std::string &imageId = getImageId(theFid, frameStatus);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const TImageInfo *imageInfo =
Shinya Kitaoka 120a6e
      ImageManager::instance()->getInfo(imageId, ImageManager::none, 0);
Shinya Kitaoka d4642c
Shinya Kitaoka 120a6e
  if (!imageInfo) return TPointD();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return TPointD(imageInfo->m_dpix, imageInfo->m_dpiy);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int TXshSimpleLevel::getImageSubsampling(const TFrameId &fid) const {
Shinya Kitaoka 120a6e
  if (isEmpty() || getType() == PLI_XSHLEVEL) return 1;
Shinya Kitaoka 120a6e
  TImageP img = TImageCache::instance()->get(getImageId(fid), false);
Shinya Kitaoka 120a6e
  if (!img) return 1;
Shinya Kitaoka 120a6e
  if (TRasterImageP ri = img) return ri->getSubsampling();
Shinya Kitaoka 120a6e
  if (TToonzImageP ti = img) return ti->getSubsampling();
Shinya Kitaoka 120a6e
  return 1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// ritorna il dpi corrente del livello
Shinya Kitaoka 120a6e
TPointD TXshSimpleLevel::getDpi(const TFrameId &fid, int frameStatus) {
Shinya Kitaoka 120a6e
  TPointD dpi;
Shinya Kitaoka 120a6e
  if (m_properties->getDpiPolicy() == LevelProperties::DP_ImageDpi)
Shinya Kitaoka 120a6e
    dpi = getImageDpi(fid, frameStatus);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    dpi = m_properties->getDpi();
Shinya Kitaoka 120a6e
  return dpi;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void TXshSimpleLevel::renumber(const std::vector<TFrameId> &fids) {
Shinya Kitaoka 120a6e
  assert(fids.size() == m_frames.size());
Shinya Kitaoka 120a6e
  int n = fids.size();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int i = 0;
Shinya Kitaoka 120a6e
  std::vector<TFrameId> oldFids;
Shinya Kitaoka 120a6e
  getFids(oldFids);
Shinya Kitaoka 120a6e
  std::map<TFrameId, TFrameId> table;
Shinya Kitaoka 120a6e
  std::map<TFrameId, TFrameId> newRenumberTable;
Shinya Kitaoka 120a6e
  for (std::vector<TFrameId>::iterator it = oldFids.begin();
Shinya Kitaoka 120a6e
       it != oldFids.end(); ++it) {
Shinya Kitaoka 120a6e
    TFrameId oldFrameId = *it;
Shinya Kitaoka 120a6e
    TFrameId newFrameId = fids[i++];
Shinya Kitaoka 120a6e
    table[oldFrameId]   = newFrameId;
Shinya Kitaoka 120a6e
    for (auto const &renumber : m_renumberTable) {
Shinya Kitaoka 120a6e
      if (renumber.second == oldFrameId) {
Shinya Kitaoka 120a6e
        newRenumberTable[renumber.first] = newFrameId;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  for (auto const &renumber : newRenumberTable) {
Shinya Kitaoka 120a6e
    m_renumberTable[renumber.first] = renumber.second;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_frames.clear();
Shinya Kitaoka 120a6e
  for (i = 0; i < n; ++i) {
Shinya Kitaoka 120a6e
    TFrameId fid(fids[i]);
Shinya Kitaoka 120a6e
    assert(m_frames.count(fid) == 0);
Shinya Kitaoka 120a6e
    m_frames.insert(fid);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ImageManager *im = ImageManager::instance();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::map<TFrameId, TFrameId>::iterator jt;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    for (i = 0, jt = table.begin(); jt != table.end(); ++jt, ++i)
Shinya Kitaoka 120a6e
      im->rebind(getImageId(jt->first), "^" + std::to_string(i));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    for (i = 0, jt = table.begin(); jt != table.end(); ++jt, ++i)
Shinya Kitaoka 120a6e
      im->rebind("^" + std::to_string(i), getImageId(jt->second));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (getType() == PLI_XSHLEVEL) {
Shinya Kitaoka 120a6e
    for (i = 0, jt = table.begin(); jt != table.end(); ++jt, ++i) {
Shinya Kitaoka 120a6e
      const std::string &id = rasterized(getImageId(jt->first));
Shinya Kitaoka 120a6e
      if (im->isBound(id)) im->rebind(id, rasterized("^" + std::to_string(i)));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    for (i = 0, jt = table.begin(); jt != table.end(); ++jt, ++i) {
Shinya Kitaoka 120a6e
      const std::string &id = rasterized("^" + std::to_string(i));
Shinya Kitaoka 120a6e
      if (im->isBound(id)) im->rebind(id, rasterized(getImageId(jt->second)));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (getType() & FULLCOLOR_TYPE) {
Shinya Kitaoka 120a6e
    for (i = 0, jt = table.begin(); jt != table.end(); ++jt, ++i) {
Shinya Kitaoka 120a6e
      const std::string &id = filled(getImageId(jt->first));
Shinya Kitaoka 120a6e
      if (im->isBound(id)) im->rebind(id, filled("^" + std::to_string(i)));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    for (i = 0, jt = table.begin(); jt != table.end(); ++jt, ++i) {
Shinya Kitaoka 120a6e
      const std::string &id = filled("^" + std::to_string(i));
Shinya Kitaoka 120a6e
      if (im->isBound(id)) im->rebind(id, filled(getImageId(jt->second)));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_properties->setDirtyFlag(true);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (getHookSet()) getHookSet()->renumber(table);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::copyFiles(const TFilePath &dst, const TFilePath &src) {
Shinya Kitaoka 120a6e
  if (dst == src) return;
Shinya Kitaoka 120a6e
  TSystem::touchParentDir(dst);
Shinya Kitaoka 120a6e
  TSystem::copyFileOrLevel_throw(dst, src);
Shinya Kitaoka 120a6e
  if (dst.getType() == "tlv") {
Shinya Kitaoka 120a6e
    // Copio la palette del livello
Shinya Kitaoka 120a6e
    TFilePath srcPltPath =
Shinya Kitaoka 120a6e
        src.getParentDir() + TFilePath(src.getWideName() + L".tpl");
Shinya Kitaoka 120a6e
    if (TFileStatus(srcPltPath).doesExist())
Shinya Kitaoka 120a6e
      TSystem::copyFile(
Shinya Kitaoka 120a6e
          dst.getParentDir() + TFilePath(dst.getWideName() + L".tpl"),
Shinya Kitaoka 120a6e
          srcPltPath, true);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (dst.getType() == "tzp" || dst.getType() == "tzu") {
Shinya Kitaoka 120a6e
    // Copio la palette del livello
Shinya Kitaoka 120a6e
    TFilePath srcPltPath =
Shinya Kitaoka 120a6e
        src.getParentDir() + TFilePath(src.getWideName() + L".plt");
Shinya Kitaoka 120a6e
    if (TFileStatus(srcPltPath).doesExist())
Shinya Kitaoka 120a6e
      TSystem::copyFile(
Shinya Kitaoka 120a6e
          dst.getParentDir() + TFilePath(dst.getWideName() + L".plt"),
Shinya Kitaoka 120a6e
          srcPltPath, true);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const TFilePath &srcHookFile = TXshSimpleLevel::getExistingHookFile(src);
Shinya Kitaoka 120a6e
  if (!srcHookFile.isEmpty()) {
Shinya Kitaoka 120a6e
    const TFilePath &dstHookFile = getHookPath(dst);
Shinya Kitaoka 120a6e
    TSystem::copyFile(dstHookFile, srcHookFile, true);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  TFilePath files = src.getParentDir() + (src.getName() + "_files");
Shinya Kitaoka 120a6e
  if (TFileStatus(files).doesExist() && TFileStatus(files).isDirectory())
Shinya Kitaoka 120a6e
    TSystem::copyDir(dst.getParentDir() + (src.getName() + "_files"), files);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::renameFiles(const TFilePath &dst, const TFilePath &src) {
Shinya Kitaoka 120a6e
  if (dst == src) return;
Shinya Kitaoka 120a6e
  TSystem::touchParentDir(dst);
Shinya Kitaoka 120a6e
  if (TSystem::doesExistFileOrLevel(dst)) TXshSimpleLevel::removeFiles(dst);
Shinya Kitaoka 120a6e
  TSystem::renameFileOrLevel_throw(dst, src);
Shinya Kitaoka 120a6e
  if (dst.getType() == "tlv")
Shinya Kitaoka 120a6e
    TSystem::renameFile(dst.withType("tpl"), src.withType("tpl"));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const TFilePath &srcHookFile = TXshSimpleLevel::getExistingHookFile(src);
Shinya Kitaoka 120a6e
  if (!srcHookFile.isEmpty()) {
Shinya Kitaoka 120a6e
    const TFilePath &dstHookFile = getHookPath(dst);
Shinya Kitaoka 120a6e
    TSystem::renameFile(dstHookFile, srcHookFile);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TFilePath files = src.getParentDir() + (src.getName() + "_files");
Shinya Kitaoka 120a6e
  if (TFileStatus(files).doesExist() && TFileStatus(files).isDirectory())
Shinya Kitaoka 120a6e
    TSystem::renameFile(dst.getParentDir() + (dst.getName() + "_files"), files);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::removeFiles(const TFilePath &fp) {
Shinya Kitaoka 120a6e
  TSystem::moveFileOrLevelToRecycleBin(fp);
Shinya Kitaoka 120a6e
  if (fp.getType() == "tlv") {
Shinya Kitaoka 120a6e
    TFilePath tpl = fp.withType("tpl");
Shinya Kitaoka 120a6e
    if (TFileStatus(tpl).doesExist()) TSystem::moveFileToRecycleBin(tpl);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Delete ALL hook files (ie from every Toonz version)
Shinya Kitaoka 120a6e
  const QStringList &hookFiles = TXshSimpleLevel::getHookFiles(fp);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int f, fCount = hookFiles.size();
Shinya Kitaoka 120a6e
  for (f = 0; f != fCount; ++f)
Shinya Kitaoka 120a6e
    TSystem::moveFileToRecycleBin(TFilePath(hookFiles[f].toStdWString()));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TFilePath files = fp.getParentDir() + (fp.getName() + "_files");
Shinya Kitaoka 120a6e
  if (TFileStatus(files).doesExist() && TFileStatus(files).isDirectory())
Shinya Kitaoka 120a6e
    TSystem::rmDirTree(files);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::getFiles(const TFilePath &fp, TFilePathSet &fpset) {
Shinya Kitaoka 120a6e
  if (fp.getType() == "tlv") {
Shinya Kitaoka 120a6e
    TFilePath tpl = fp.withType("tpl");
Shinya Kitaoka 120a6e
    if (TFileStatus(tpl).doesExist()) fpset.push_back(tpl);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Store the hooks file if any (NOTE: there could be more than one hooks
Shinya Kitaoka 120a6e
  // file. I'm retaining the behavior I've seen, but was this really intended?
Shinya Kitaoka 120a6e
  // Shouldn't we return ALL the hooks files?)
Shinya Kitaoka 120a6e
  const TFilePath &hookFile = getExistingHookFile(fp);
Shinya Kitaoka 120a6e
  if (!hookFile.isEmpty()) fpset.push_back(hookFile);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Needed for TAB Manga & Kids and not used in Toonz
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // TFilePath files = fp.getParentDir() + (fp.getName() + "_files");
Shinya Kitaoka 120a6e
  // if(TFileStatus(files).doesExist() && TFileStatus(files).isDirectory())
Shinya Kitaoka 120a6e
  //  TSystem::rmDirTree(files);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::setContentHistory(TContentHistory *contentHistory) {
Shinya Kitaoka 120a6e
  if (contentHistory != m_contentHistory.get())
Shinya Kitaoka 120a6e
    m_contentHistory.reset(contentHistory);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TXshSimpleLevel::setCompatibilityMasks(int writeMask, int neededMask,
Shinya Kitaoka 120a6e
                                            int forbiddenMask) {
Shinya Kitaoka 120a6e
  compatibility.writeMask     = writeMask;
Shinya Kitaoka 120a6e
  compatibility.neededMask    = neededMask;
Shinya Kitaoka 120a6e
  compatibility.forbiddenMask = forbiddenMask;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFilePath TXshSimpleLevel::getHookPath(const TFilePath &path) {
Shinya Kitaoka 120a6e
  // Translates:  levelName..ext  into  levelName_hooks..ext.xml
Shinya Kitaoka 120a6e
  //              levelName.ext   into  levelName_hooks.ext.xml
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Observe that retaining the original level extension IS IMPORTANT, as it
Shinya Kitaoka 120a6e
  // ensures
Shinya Kitaoka 120a6e
  // the UNICITY of the association between a level path and its hook path (ie
Shinya Kitaoka 120a6e
  // levels  test..png  and  test..tif  have separate hook files).
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return TFilePath(path.withName(path.getName() + "_hooks").getWideString() +
Shinya Kitaoka 120a6e
                   L".xml");
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QStringList TXshSimpleLevel::getHookFiles(const TFilePath &decodedLevelPath) {
Shinya Kitaoka 120a6e
  const TFilePath &dirPath = decodedLevelPath.getParentDir();
Shinya Kitaoka 120a6e
  QDir levelDir(QString::fromStdWString(dirPath.getWideString()));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  QStringList hookFileFilter(
Shinya Kitaoka 120a6e
      QString::fromStdWString(  // We have to scan for files of the
Shinya Kitaoka 120a6e
          decodedLevelPath.getWideName() +
Shinya Kitaoka 120a6e
          L"_hooks*.xml"));   // form  levelName_hooks*.xml  to
Shinya Kitaoka 120a6e
                              // retain backward compatibility
Shinya Kitaoka 120a6e
  return levelDir.entryList(  //
Shinya Kitaoka 120a6e
      hookFileFilter,
Shinya Kitaoka 120a6e
      QDir::Files | QDir::NoDotAndDotDot,  // Observe that we cleverly sort by
Shinya Kitaoka 120a6e
      QDir::Time);                         // mod date :)
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFilePath TXshSimpleLevel::getExistingHookFile(
Shinya Kitaoka 120a6e
    const TFilePath &decodedLevelPath) {
Shinya Kitaoka 120a6e
  static const int pCount              = 3;
Shinya Kitaoka 120a6e
  static const QRegExp pattern[pCount] = {
Shinya Kitaoka 120a6e
      // Prioritized in this order
Shinya Kitaoka 120a6e
      QRegExp(".*\\.\\.?.+\\.xml$"),  // whatever.(.)ext.xml
Shinya Kitaoka 120a6e
      QRegExp(".*\\.xml$"),           // whatever.xml
Shinya Kitaoka 120a6e
      QRegExp(".*\\.\\.?xml$")        // whatever.(.)xml
Shinya Kitaoka 120a6e
  };
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  struct locals {
Shinya Kitaoka 120a6e
    static inline int getPattern(const QString &fp) {
Shinya Kitaoka 120a6e
      for (int p = 0; p != pCount; ++p)
Shinya Kitaoka 120a6e
        if (pattern[p].exactMatch(fp)) return p;
Shinya Kitaoka 120a6e
      return -1;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  };  // locals
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const QStringList &hookFiles = getHookFiles(decodedLevelPath);
Shinya Kitaoka 120a6e
  if (hookFiles.empty()) return TFilePath();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Return the hook file with the most recent (smallest) identified
Shinya Kitaoka 120a6e
  // regexp pattern
Shinya Kitaoka 120a6e
  int fPattern, p = pCount, h = -1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int f, fCount = hookFiles.size();
Shinya Kitaoka 120a6e
  for (f = 0; f != fCount; ++f) {
Shinya Kitaoka 120a6e
    fPattern            = locals::getPattern(hookFiles[f]);
Shinya Kitaoka 120a6e
    if (fPattern < p) p = fPattern, h = f;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  assert(h >= 0);
Shinya Kitaoka 120a6e
  return (h < 0) ? TFilePath()
Shinya Kitaoka 120a6e
                 : decodedLevelPath.getParentDir() +
Shinya Kitaoka 120a6e
                       TFilePath(hookFiles[h].toStdWString());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TRectD TXshSimpleLevel::getBBox(const TFrameId &fid) const {
Shinya Kitaoka 120a6e
  TRectD bbox;
Shinya Kitaoka 120a6e
  double dpiX = Stage::inch, dpiY = dpiX;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Get the frame bbox in image coordinates
Shinya Kitaoka 120a6e
  switch (getType()) {
Shinya Kitaoka 120a6e
  case PLI_XSHLEVEL:
Shinya Kitaoka 120a6e
  case MESH_XSHLEVEL: {
Shinya Kitaoka 120a6e
    // Load the image and extract its bbox forcibly
Shinya Kitaoka 120a6e
    TImageP img = getFrame(fid, false);
Shinya Kitaoka 120a6e
    if (!img) return TRectD();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    bbox = img->getBBox();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (TMeshImageP mi = img) mi->getDpi(dpiX, dpiY);
Shinya Kitaoka d4642c
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  default: {
Shinya Kitaoka 120a6e
    // Raster case: retrieve the image info from the ImageManager
Shinya Kitaoka 120a6e
    const std::string &imageId = getImageId(fid);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    const TImageInfo *info =
Shinya Kitaoka 120a6e
        ImageManager::instance()->getInfo(imageId, ImageManager::none, 0);
Shinya Kitaoka 120a6e
    if (!info) return TRectD();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    bbox = TRectD(TPointD(info->m_x0, info->m_y0),
Shinya Kitaoka 120a6e
                  TDimensionD(info->m_lx,
Shinya Kitaoka 120a6e
                              info->m_ly)) -  // Using lx, ly is less ambiguous
Shinya Kitaoka 120a6e
           0.5 * TPointD(info->m_lx, info->m_ly);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (info->m_dpix > 0.0 && info->m_dpiy > 0.0)
Shinya Kitaoka 120a6e
      dpiX = info->m_dpix, dpiY = info->m_dpiy;
Shinya Kitaoka d4642c
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Get the frame's dpi and traduce the bbox to inch coordinates
Shinya Kitaoka 120a6e
  return TScale(1.0 / dpiX, 1.0 / dpiY) * bbox;
Toshihiro Shimizu 890ddd
}