| |
| |
| #include "toonz/studiopalette.h" |
| #include "tfiletype.h" |
| #include "tstream.h" |
| #include "tconvert.h" |
| #include "tlevel_io.h" |
| #include "trasterimage.h" |
| #include "traster.h" |
| #include "tsystem.h" |
| #include "tcolorstyles.h" |
| #include "toonz/toonzfolders.h" |
| #include "toonz/tproject.h" |
| #include "toonz/toonzscene.h" |
| #include "tpalette.h" |
| |
| #include <time.h> |
| #include <stdio.h> |
| #include <sys/types.h> |
| #include <sys/timeb.h> |
| #include <string.h> |
| |
| |
| |
| |
| namespace |
| { |
| |
| |
| TFilePath makeUniqueName(TFilePath fp) |
| { |
| if (TFileStatus(fp).doesExist() == false) |
| return fp; |
| wstring name = fp.getWideName(); |
| int index = 2; |
| int j = name.find_last_not_of(L"0123456789"); |
| if (j != (int)wstring::npos && j + 1 < (int)name.length()) { |
| index = toInt(name.substr(j + 1)) + 1; |
| name = name.substr(0, j + 1); |
| } |
| for (;;) { |
| fp = fp.withName(name + toWideString(index)); |
| if (TFileStatus(fp).doesExist() == false) |
| return fp; |
| index++; |
| } |
| } |
| |
| |
| |
| TPalette *loadPliPalette(const TFilePath &fp) |
| { |
| TLevelReaderP lr(fp); |
| TLevelP level = lr->loadInfo(); |
| int frameCount = level->getFrameCount(); |
| if (frameCount < 1) |
| return 0; |
| TPalette *palette = level->getPalette(); |
| if (!palette) |
| return 0; |
| return palette->clone(); |
| } |
| |
| |
| |
| TPalette *loadTplPalette(const TFilePath &fp) |
| { |
| TPersist *p = 0; |
| TIStream is(fp); |
| is >> p; |
| TPalette *palette = dynamic_cast<TPalette *>(p); |
| return palette; |
| } |
| |
| |
| |
| TPalette *loadToonz46Palette(const TFilePath &fp) |
| { |
| TImageP pltImg; |
| TImageReader::load(fp, pltImg); |
| if (!pltImg) |
| return 0; |
| TRasterImageP pltRasImg(pltImg); |
| if (!pltRasImg) |
| return 0; |
| TRaster32P rasPlt = pltRasImg->getRaster(); |
| if (!rasPlt) |
| return 0; |
| TPalette *palette = new TPalette(); |
| const int offset = 0; |
| assert(rasPlt->getLy() == 2); |
| rasPlt->lock(); |
| TPixel32 *pixelRow = rasPlt->pixels(0); |
| int x; |
| for (x = 1; x < rasPlt->getLx(); ++x) { |
| TPixel32 color = pixelRow[x]; |
| int styleId = offset + x; |
| if (styleId < palette->getStyleCount()) |
| palette->setStyle(styleId, color); |
| else { |
| int j = palette->addStyle(color); |
| assert(j == styleId); |
| } |
| } |
| |
| |
| |
| pixelRow = rasPlt->pixels(1); |
| TPalette::Page *page = palette->getPage(0); |
| for (x = 1; x < rasPlt->getLx(); ++x) { |
| if (pixelRow[x].r == 255) |
| page->addStyle(offset + x); |
| } |
| rasPlt->unlock(); |
| return palette; |
| } |
| |
| |
| |
| wstring readPaletteGlobalName(TFilePath path) |
| { |
| try { |
| TIStream is(path); |
| if (!is) |
| return L""; |
| string tagName; |
| if (!is.matchTag(tagName) || tagName != "palette") |
| return L""; |
| string name; |
| if (is.getTagParam("name", name)) |
| return toWideString(name); |
| } catch (...) { |
| } |
| return L""; |
| } |
| |
| |
| TFilePath searchPalette(TFilePath path, wstring paletteId) |
| { |
| TFilePathSet q; |
| try { |
| TSystem::readDirectory(q, path); |
| } catch (...) { |
| } |
| |
| for (TFilePathSet::iterator i = q.begin(); i != q.end(); ++i) { |
| TFilePath fp = *i; |
| if (fp.getType() == "tpl") { |
| wstring gname = readPaletteGlobalName(fp); |
| if (gname == paletteId) |
| return fp; |
| } else if (TFileStatus(fp).isDirectory()) { |
| TFilePath palettePath = searchPalette(fp, paletteId); |
| if (palettePath != TFilePath()) |
| return palettePath; |
| } |
| } |
| return TFilePath(); |
| } |
| |
| bool studioPaletteHasBeenReferred = false; |
| |
| static std::map<wstring, TFilePath> table; |
| |
| |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| StudioPalette::StudioPalette() |
| { |
| try { |
| m_root = ToonzFolder::getStudioPaletteFolder(); |
| } catch (...) { |
| return; |
| } |
| if (!TFileStatus(m_root).doesExist()) { |
| try { |
| TSystem::mkDir(m_root); |
| FolderListenerManager::instance()->notifyFolderChanged(m_root.getParentDir()); |
| } catch (...) { |
| } |
| try { |
| TSystem::mkDir(getLevelPalettesRoot()); |
| FolderListenerManager::instance()->notifyFolderChanged(getLevelPalettesRoot().getParentDir()); |
| } catch (...) { |
| } |
| } |
| } |
| |
| |
| |
| StudioPalette::~StudioPalette() |
| { |
| } |
| |
| |
| |
| bool StudioPalette::m_enabled = true; |
| |
| |
| |
| void StudioPalette::enable(bool enabled) |
| { |
| assert(studioPaletteHasBeenReferred == false); |
| m_enabled = enabled; |
| } |
| |
| |
| |
| StudioPalette *StudioPalette::instance() |
| { |
| static StudioPalette _instance; |
| studioPaletteHasBeenReferred = true; |
| assert(m_enabled); |
| return &_instance; |
| } |
| |
| |
| |
| TFilePath StudioPalette::getLevelPalettesRoot() |
| { |
| return m_root + "Toonz Palettes"; |
| } |
| |
| |
| |
| TFilePath StudioPalette::getProjectPalettesRoot() |
| { |
| TProjectP p = TProjectManager::instance()->getCurrentProject(); |
| TFilePath folderName = p->getFolder(TProject::Palettes); |
| if (folderName.isEmpty()) |
| return TFilePath(); |
| if (folderName.isAbsolute()) |
| return folderName; |
| return p->getProjectFolder() + folderName; |
| } |
| |
| |
| |
| bool loadRefImg(TPalette *palette, TFilePath dir) |
| { |
| assert(palette); |
| TFilePath fp = palette->getRefImgPath(); |
| if (fp == TFilePath() || !TSystem::doesExistFileOrLevel(fp)) |
| return false; |
| if (!fp.isAbsolute()) |
| fp = dir + fp; |
| TLevelReaderP lr(fp); |
| if (!lr) |
| return false; |
| TLevelP level = lr->loadInfo(); |
| if (!level || level->getFrameCount() == 0) |
| return false; |
| TLevel::Iterator it = level->begin(); |
| TImageP img = lr->getFrameReader(it->first)->load(); |
| if (!img) |
| return false; |
| img->setPalette(0); |
| palette->setRefImg(img); |
| return true; |
| } |
| |
| |
| |
| TPalette *StudioPalette::getPalette( |
| const TFilePath &path, |
| bool loadRefImgFlag) |
| { |
| try { |
| if (path.getType() != "tpl") |
| return 0; |
| TPalette *palette = load(path); |
| if (!palette) |
| return 0; |
| if (loadRefImgFlag) |
| loadRefImg(palette, path.getParentDir()); |
| |
| return palette; |
| } catch (...) { |
| return 0; |
| } |
| } |
| |
| |
| |
| void StudioPalette::movePalette(const TFilePath &dstPath, const TFilePath &srcPath) |
| { |
| try { |
| TSystem::renameFile(dstPath, srcPath); |
| } catch (...) { |
| return; |
| } |
| wstring id = readPaletteGlobalName(dstPath); |
| table.erase(id); |
| FolderListenerManager::instance()->notifyFolderChanged(dstPath.getParentDir()); |
| notifyMove(dstPath, srcPath); |
| } |
| |
| |
| |
| int StudioPalette::getChildren(std::vector<TFilePath> &fps, const TFilePath &folderPath) |
| { |
| TFilePathSet q; |
| if (TFileStatus(folderPath).isDirectory()) { |
| try { |
| TSystem::readDirectory(q, folderPath, false, false); |
| } catch (...) { |
| } |
| } |
| |
| for (TFilePathSet::iterator i = q.begin(); i != q.end(); ++i) |
| if (isFolder(*i) || isPalette(*i)) |
| fps.push_back(*i); |
| |
| return fps.size(); |
| } |
| |
| |
| |
| int StudioPalette::getChildCount(const TFilePath &folderPath) |
| { |
| TFilePathSet q; |
| try { |
| TSystem::readDirectory(q, folderPath); |
| } catch (...) { |
| } |
| return q.size(); |
| } |
| |
| |
| |
| bool StudioPalette::isFolder(const TFilePath &path) |
| { |
| return TFileStatus(path).isDirectory(); |
| } |
| |
| |
| |
| bool StudioPalette::isReadOnly(const TFilePath &path) |
| { |
| return !TFileStatus(path).isWritable(); |
| } |
| |
| |
| |
| bool StudioPalette::isPalette(const TFilePath &path) |
| { |
| return path.getType() == "tpl"; |
| } |
| |
| |
| |
| |
| bool StudioPalette::hasGlobalName(const TFilePath &path) |
| { |
| return (readPaletteGlobalName(path) != L""); |
| } |
| |
| |
| |
| bool StudioPalette::isLevelPalette(const TFilePath &path) |
| { |
| TPalette *palette = getPalette(path); |
| if (!palette) |
| return false; |
| bool ret = !palette->isCleanupPalette(); |
| delete palette; |
| return ret; |
| } |
| |
| |
| |
| TFilePath StudioPalette::createFolder(const TFilePath &parentFolderPath) |
| { |
| TFilePath path = makeUniqueName(parentFolderPath + "new folder"); |
| try { |
| TSystem::mkDir(path); |
| } catch (...) { |
| return TFilePath(); |
| } |
| FolderListenerManager::instance()->notifyFolderChanged(parentFolderPath); |
| notifyTreeChange(); |
| return path; |
| } |
| |
| |
| |
| void StudioPalette::createFolder(const TFilePath &parentFolderPath, wstring name) |
| { |
| TFilePath fp = parentFolderPath + name; |
| if (TFileStatus(fp).doesExist()) |
| return; |
| try { |
| TSystem::mkDir(fp); |
| } catch (...) { |
| return; |
| } |
| FolderListenerManager::instance()->notifyFolderChanged(parentFolderPath); |
| notifyTreeChange(); |
| } |
| |
| |
| |
| TFilePath StudioPalette::createPalette(const TFilePath &folderPath, string name) |
| { |
| TPalette *palette = 0; |
| if (name == "") |
| name = "new palette"; |
| palette = new TPalette(); |
| TFilePath fp = makeUniqueName(folderPath + (name + ".tpl")); |
| time_t ltime; |
| time(<ime); |
| wstring gname = toWideString((int)ltime) + L"_" + toWideString(rand()); |
| palette->setGlobalName(gname); |
| setStylesGlobalNames(palette); |
| save(fp, palette); |
| delete palette; |
| notifyTreeChange(); |
| return fp; |
| } |
| |
| |
| |
| void StudioPalette::setPalette(const TFilePath &palettePath, const TPalette *plt, bool notifyPaletteChanged) |
| { |
| assert(palettePath.getType() == "tpl"); |
| TPalette *palette = plt->clone(); |
| palette->setIsLocked(plt->isLocked()); |
| palette->addRef(); |
| wstring pgn = palette->getGlobalName(); |
| if (TFileStatus(palettePath).doesExist()) |
| pgn = readPaletteGlobalName(palettePath); |
| palette->setGlobalName(pgn); |
| setStylesGlobalNames(palette); |
| save(palettePath, palette); |
| palette->release(); |
| if (notifyPaletteChanged) |
| notifyPaletteChange(palettePath); |
| } |
| |
| |
| |
| void StudioPalette::deletePalette(const TFilePath &palettePath) |
| { |
| assert(palettePath.getType() == "tpl"); |
| try { |
| TSystem::deleteFile(palettePath); |
| } catch (...) { |
| return; |
| } |
| notifyTreeChange(); |
| } |
| |
| |
| |
| void StudioPalette::deleteFolder(const TFilePath &path) |
| { |
| try { |
| TSystem::rmDirTree(path); |
| } catch (...) { |
| } |
| notifyTreeChange(); |
| } |
| |
| |
| |
| TFilePath StudioPalette::importPalette( |
| const TFilePath &dstFolder, |
| const TFilePath &srcPath) |
| { |
| TPaletteP palette; |
| string ext = srcPath.getType(); |
| try { |
| if (ext == "plt") |
| palette = loadToonz46Palette(srcPath); |
| else if (ext == "pli") |
| palette = loadPliPalette(srcPath); |
| else if (ext == "tpl") |
| palette = loadTplPalette(srcPath); |
| } catch (...) { |
| } |
| |
| if (!palette) |
| return TFilePath(); |
| wstring name = srcPath.getWideName(); |
| |
| assert(!palette->isCleanupPalette()); |
| |
| |
| TFilePath fp = makeUniqueName(dstFolder + (name + L".tpl")); |
| time_t ltime; |
| time(<ime); |
| wstring gname = toWideString((int)ltime) + L"_" + toWideString(rand()); |
| palette->setGlobalName(gname); |
| setStylesGlobalNames(palette.getPointer()); |
| TSystem::touchParentDir(fp); |
| save(fp, palette.getPointer()); |
| notifyTreeChange(); |
| return fp; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| void foobar(wstring paletteId) |
| { |
| table.erase(paletteId); |
| } |
| |
| TFilePath StudioPalette::getPalettePath(wstring paletteId) |
| { |
| std::map<wstring, TFilePath>::iterator it = table.find(paletteId); |
| if (it != table.end()) |
| return it->second; |
| TFilePath fp = searchPalette(m_root, paletteId); |
| if (fp == TFilePath()) { |
| fp = searchPalette(getProjectPalettesRoot(), paletteId); |
| } |
| table[paletteId] = fp; |
| return fp; |
| } |
| |
| |
| |
| TPalette *StudioPalette::getPalette(wstring paletteId) |
| { |
| TFilePath palettePath = getPalettePath(paletteId); |
| if (palettePath != TFilePath()) |
| return getPalette(palettePath); |
| else |
| return 0; |
| } |
| |
| |
| |
| TColorStyle *StudioPalette::getStyle(wstring styleId) |
| { |
| |
| return 0; |
| } |
| |
| |
| |
| std::pair<TFilePath, int> StudioPalette::getSourceStyle(TColorStyle *cs) |
| { |
| std::pair<TFilePath, int> ret(TFilePath(), -1); |
| if (!cs) |
| return ret; |
| wstring gname = cs->getGlobalName(); |
| if (gname == L"") |
| return ret; |
| int k = gname.find_first_of(L'-', 1); |
| if (k == (int)wstring::npos) |
| return ret; |
| wstring paletteId = gname.substr(1, k - 1); |
| ret.first = getPalettePath(paletteId) - m_root; |
| ret.second = toInt(gname.substr(k + 1)); |
| return ret; |
| } |
| |
| |
| |
| |
| bool StudioPalette::updateLinkedColors(TPalette *palette) |
| { |
| bool paletteIsChanged = false; |
| std::map<wstring, TPaletteP> table; |
| |
| for (int i = 0; i < palette->getStyleCount(); i++) { |
| TColorStyle *cs = palette->getStyle(i); |
| wstring gname = cs->getGlobalName(); |
| if (gname == L"" || gname[0] != L'+') |
| continue; |
| int k = gname.find_first_of(L'-', 1); |
| if (k == (int)wstring::npos) |
| continue; |
| wstring paletteId = gname.substr(1, k - 1); |
| std::map<wstring, TPaletteP>::iterator it; |
| it = table.find(paletteId); |
| TPalette *spPalette = 0; |
| if (it == table.end()) { |
| spPalette = |
| StudioPalette::instance() |
| ->getPalette(paletteId); |
| if (!spPalette) |
| continue; |
| table[paletteId] = spPalette; |
| |
| assert(spPalette->getRefCount() == 1); |
| } else |
| spPalette = it->second.getPointer(); |
| |
| int j = toInt(gname.substr(k + 1)); |
| if (spPalette && 0 <= j && j < spPalette->getStyleCount()) { |
| TColorStyle *spStyle = spPalette->getStyle(j); |
| assert(spStyle); |
| spStyle = spStyle->clone(); |
| spStyle->setGlobalName(gname); |
| |
| |
| spStyle->setOriginalName(spStyle->getName()); |
| |
| spStyle->setName(cs->getName()); |
| |
| palette->setStyle(i, spStyle); |
| |
| paletteIsChanged = true; |
| } |
| } |
| return paletteIsChanged; |
| } |
| |
| |
| |
| void StudioPalette::setStylesGlobalNames(TPalette *palette) |
| { |
| for (int i = 0; i < palette->getStyleCount(); i++) { |
| TColorStyle *cs = palette->getStyle(i); |
| |
| if (cs->getGlobalName() == L"") { |
| wstring gname = L"-" + palette->getGlobalName() + L"-" + toWideString(i); |
| cs->setGlobalName(gname); |
| } |
| } |
| } |
| |
| |
| |
| void StudioPalette::save(const TFilePath &path, TPalette *palette) |
| { |
| TOStream os(path); |
| std::map<string, string> attr; |
| attr["name"] = toString(palette->getGlobalName()); |
| os.openChild("palette", attr); |
| palette->saveData(os); |
| os.closeChild(); |
| } |
| |
| |
| |
| TPalette *StudioPalette::load(const TFilePath &path) |
| { |
| try { |
| TIStream is(path); |
| if (!is) |
| return 0; |
| string tagName; |
| if (!is.matchTag(tagName) || tagName != "palette") |
| return 0; |
| string gname; |
| is.getTagParam("name", gname); |
| TPalette *palette = new TPalette(); |
| palette->loadData(is); |
| palette->setGlobalName(toWideString(gname)); |
| is.matchEndTag(); |
| palette->setPaletteName(path.getWideName()); |
| return palette; |
| } catch (...) { |
| return 0; |
| } |
| } |
| |
| |
| |
| void StudioPalette::addListener(Listener *listener) |
| { |
| if (std::find(m_listeners.begin(), m_listeners.end(), listener) == m_listeners.end()) |
| m_listeners.push_back(listener); |
| } |
| |
| |
| |
| void StudioPalette::removeListener(Listener *listener) |
| { |
| m_listeners.erase( |
| std::remove(m_listeners.begin(), m_listeners.end(), listener), |
| m_listeners.end()); |
| } |
| |
| |
| |
| void StudioPalette::notifyTreeChange() |
| { |
| for (std::vector<Listener *>::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it) |
| (*it)->onStudioPaletteTreeChange(); |
| } |
| |
| |
| |
| void StudioPalette::notifyMove(const TFilePath &dstPath, const TFilePath &srcPath) |
| { |
| for (std::vector<Listener *>::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it) |
| (*it)->onStudioPaletteMove(dstPath, srcPath); |
| } |
| |
| |
| |
| void StudioPalette::notifyPaletteChange(const TFilePath &palette) |
| { |
| for (std::vector<Listener *>::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it) |
| (*it)->onStudioPaletteChange(palette); |
| } |
| |