From d2f7b6e916b9aba8d3576b09013522d8f627dcf3 Mon Sep 17 00:00:00 2001 From: shun-iwasawa Date: Mon, 8 Mar 2021 14:29:00 +0900 Subject: [PATCH 01/24] premultiply on loading PNG images --- toonz/sources/image/png/tiio_png.cpp | 62 ++++++++++++++---------- toonz/sources/include/toonz/toonzscene.h | 14 +++--- toonz/sources/tcomposer/tcomposer.cpp | 44 +++++++++++++++-- toonz/sources/toonz/iocommand.cpp | 35 +++++++++++++ toonz/sources/toonzlib/preferences.cpp | 33 +++++++++++-- toonz/sources/toonzlib/toonzscene.cpp | 22 +++++---- 6 files changed, 163 insertions(+), 47 deletions(-) diff --git a/toonz/sources/image/png/tiio_png.cpp b/toonz/sources/image/png/tiio_png.cpp index dc2808eb..fc3d8b68 100644 --- a/toonz/sources/image/png/tiio_png.cpp +++ b/toonz/sources/image/png/tiio_png.cpp @@ -204,7 +204,8 @@ public: png_set_palette_to_rgb(m_png_ptr); // treat the image as RGBA from now on - m_info.m_samplePerPixel = 4; // there are 4 channels per pixel (R, G, B, and A) + m_info.m_samplePerPixel = + 4; // there are 4 channels per pixel (R, G, B, and A) // if there is no alpha channel, then fill it with "255" (full opacity) png_set_filler(m_png_ptr, 0xFF, PNG_FILLER_AFTER); @@ -349,7 +350,8 @@ public: void writeRow(char *buffer) { if (m_color_type == PNG_COLOR_TYPE_RGB_ALPHA || m_color_type == PNG_COLOR_TYPE_GRAY_ALPHA || - m_color_type == PNG_COLOR_TYPE_PALETTE) { // PNG_COLOR_TYPE_PALETTE is expanded to RGBA + m_color_type == PNG_COLOR_TYPE_PALETTE) { // PNG_COLOR_TYPE_PALETTE is + // expanded to RGBA if (m_bit_depth == 16) { TPixel32 *pix = (TPixel32 *)buffer; int i = -2; @@ -377,6 +379,9 @@ public: #else #error "unknown channel order" #endif + + // premultiply here + premult(pix[j]); } } else { TPixel32 *pix = (TPixel32 *)buffer; @@ -388,23 +393,25 @@ public: pix[j].g = m_rowBuffer[i++]; pix[j].b = m_rowBuffer[i++]; #elif defined(TNZ_MACHINE_CHANNEL_ORDER_RGBM) - pix[j].r = m_rowBuffer[i++]; - pix[j].g = m_rowBuffer[i++]; - pix[j].b = m_rowBuffer[i++]; - pix[j].m = m_rowBuffer[i++]; + pix[j].r = m_rowBuffer[i++]; + pix[j].g = m_rowBuffer[i++]; + pix[j].b = m_rowBuffer[i++]; + pix[j].m = m_rowBuffer[i++]; #elif defined(TNZ_MACHINE_CHANNEL_ORDER_BGRM) - pix[j].b = m_rowBuffer[i++]; - pix[j].g = m_rowBuffer[i++]; - pix[j].r = m_rowBuffer[i++]; - pix[j].m = m_rowBuffer[i++]; + pix[j].b = m_rowBuffer[i++]; + pix[j].g = m_rowBuffer[i++]; + pix[j].r = m_rowBuffer[i++]; + pix[j].m = m_rowBuffer[i++]; #elif defined(TNZ_MACHINE_CHANNEL_ORDER_MBGR) - pix[j].m = m_rowBuffer[i++]; - pix[j].b = m_rowBuffer[i++]; - pix[j].g = m_rowBuffer[i++]; - pix[j].r = m_rowBuffer[i++]; + pix[j].m = m_rowBuffer[i++]; + pix[j].b = m_rowBuffer[i++]; + pix[j].g = m_rowBuffer[i++]; + pix[j].r = m_rowBuffer[i++]; #else #error "unknown channel order" #endif + // premultiply here + premult(pix[j]); } } } else // qui gestisce RGB senza alpha. @@ -439,9 +446,9 @@ public: pix[j].b = m_rowBuffer[i++]; #elif defined(TNZ_MACHINE_CHANNEL_ORDER_MBGR) || \ defined(TNZ_MACHINE_CHANNEL_ORDER_BGRM) - pix[j].b = m_rowBuffer[i++]; - pix[j].g = m_rowBuffer[i++]; - pix[j].r = m_rowBuffer[i++]; + pix[j].b = m_rowBuffer[i++]; + pix[j].g = m_rowBuffer[i++]; + pix[j].r = m_rowBuffer[i++]; #else #error "unknown channel order" #endif @@ -454,7 +461,8 @@ public: void writeRow(short *buffer) { if (m_color_type == PNG_COLOR_TYPE_RGB_ALPHA || m_color_type == PNG_COLOR_TYPE_GRAY_ALPHA || - m_color_type == PNG_COLOR_TYPE_PALETTE) { // PNG_COLOR_TYPE_PALETTE is expanded to RGBA + m_color_type == PNG_COLOR_TYPE_PALETTE) { // PNG_COLOR_TYPE_PALETTE is + // expanded to RGBA TPixel64 *pix = (TPixel64 *)buffer; int i = -2; // 0; for (int j = 0; j < m_info.m_lx; j++) { @@ -474,6 +482,9 @@ public: #error "unknown channel order" #endif // pix[j].m = 255; + + // premultiply here + premult(pix[j]); } } else // qui gestisce RGB senza alpha. { // grayscale e' gestito come RGB perche' si usa png_set_gray_to_rgb @@ -849,7 +860,7 @@ void PngWriter::open(FILE *file, const TImageInfo &info) { png_set_PLTE(m_png_ptr, m_info_ptr, palette, m_colormap->size()); } -// png_set_dither(m_png_ptr, palette, 256, 256, 0, 1); + // png_set_dither(m_png_ptr, palette, 256, 256, 0, 1); #if defined(TNZ_MACHINE_CHANNEL_ORDER_MBGR) png_set_bgr(m_png_ptr); @@ -862,7 +873,6 @@ void PngWriter::open(FILE *file, const TImageInfo &info) { #error "unknownchannel order" #endif - png_write_info(m_png_ptr, m_info_ptr); png_set_pHYs(m_png_ptr, m_info_ptr, x_pixels_per_meter, y_pixels_per_meter, 1); @@ -873,6 +883,8 @@ void PngWriter::open(FILE *file, const TImageInfo &info) { bgcolor.index = 0; png_set_tRNS(m_png_ptr, m_info_ptr, alpha, 1, &bgcolor); } + + png_write_info(m_png_ptr, m_info_ptr); } //--------------------------------------------------------- @@ -945,10 +957,10 @@ void PngWriter::writeLine(char *buffer) { tmp[k++] = depremult_pix.g; tmp[k++] = depremult_pix.r; #elif defined(TNZ_MACHINE_CHANNEL_ORDER_BGRM) - tmp[k++] = depremult_pix.b; - tmp[k++] = depremult_pix.g; - tmp[k++] = depremult_pix.r; - tmp[k++] = depremult_pix.m; + tmp[k++] = depremult_pix.b; + tmp[k++] = depremult_pix.g; + tmp[k++] = depremult_pix.r; + tmp[k++] = depremult_pix.m; #else #error "unknown channel order" #endif @@ -961,7 +973,7 @@ void PngWriter::writeLine(char *buffer) { int k = 0; for (int j = 0; j < m_info.m_lx; j++) { -// tmp = (pix->r&0xe0)|((pix->g&0xe0)>>3) | ((pix->b&0xc0)>>6); + // tmp = (pix->r&0xe0)|((pix->g&0xe0)>>3) | ((pix->b&0xc0)>>6); #if defined(TNZ_MACHINE_CHANNEL_ORDER_MRGB) || \ defined(TNZ_MACHINE_CHANNEL_ORDER_RGBM) diff --git a/toonz/sources/include/toonz/toonzscene.h b/toonz/sources/include/toonz/toonzscene.h index 3c0c97be..8bedae4c 100644 --- a/toonz/sources/include/toonz/toonzscene.h +++ b/toonz/sources/include/toonz/toonzscene.h @@ -112,9 +112,9 @@ public: /*! \return The \a coded path to be used for import. */ - TFilePath getImportedLevelPath(const TFilePath path) - const; //!< Builds the path to be used during a level import - //!< operation. + TFilePath getImportedLevelPath( + const TFilePath path) const; //!< Builds the path to be used during a + //!< level import operation. /*! \details If convertion is required, a new level file will be created and \p levelPath will be substituted with its new path. @@ -267,9 +267,11 @@ private: TLevelSet *m_levelSet; TProject *m_project; TContentHistory *m_contentHistory; - bool m_isUntitled; //!< Whether the scene is untitled. - //! \sa The setUntitled() member function. - VersionNumber m_versionNumber; + bool m_isUntitled; //!< Whether the scene is untitled. + //! \sa The setUntitled() member function. + VersionNumber m_versionNumber; // last saved scene file version. Note that + // currently it is not match with OT version. + // TODO: Revise VersionNumber with OT version private: // noncopyable diff --git a/toonz/sources/tcomposer/tcomposer.cpp b/toonz/sources/tcomposer/tcomposer.cpp index 32be6285..23765cdf 100644 --- a/toonz/sources/tcomposer/tcomposer.cpp +++ b/toonz/sources/tcomposer/tcomposer.cpp @@ -30,6 +30,9 @@ #include "toutputproperties.h" #include "toonz/imagestyles.h" #include "tproperty.h" +#include "toonz/levelset.h" +#include "toonz/txshsimplelevel.h" +#include "toonz/levelproperties.h" // TnzSound includes #include "tnzsound.h" @@ -226,6 +229,35 @@ void tcomposerRunOutOfContMemHandler(unsigned long size) { TImageCache::instance()->clear(true); exit(2); } + +// Check if the scene saved with the previous version AND the premultiply option +// is set to PNG level setting +void UnsetPremultiplyOptionsInPngLevels(ToonzScene *scene) { + if (scene->getVersionNumber() < + VersionNumber(71, 1)) { // V1.4 = 71.0 , V1.5 = 71.1 + QStringList modifiedPNGLevelNames; + std::vector levels; + scene->getLevelSet()->listLevels(levels); + for (auto level : levels) { + if (!level || !level->getSimpleLevel()) continue; + TFilePath path = level->getPath(); + if (path.isEmpty() || path.getType() != "png") continue; + if (level->getSimpleLevel()->getProperties()->doPremultiply()) { + level->getSimpleLevel()->getProperties()->setDoPremultiply(false); + modifiedPNGLevelNames.append(QString::fromStdWString(level->getName())); + } + } + if (!modifiedPNGLevelNames.isEmpty()) { + std::string msg = + "The Premultiply options in the following levels are disabled, since " + "PNG files are premultiplied on loading in the current version:" + + modifiedPNGLevelNames.join(", ").toStdString(); + cout << msg << endl; + m_userLog->info(msg); + } + } +} + } // namespace //============================================================================================== @@ -406,7 +438,7 @@ static std::pair generateMovie(ToonzScene *scene, const TFilePath &fp, r0 = r0 - 1; r1 = r1 - 1; - if (r0 < 0) r0 = 0; + if (r0 < 0) r0 = 0; if (r1 < 0 || r1 >= scene->getFrameCount()) r1 = scene->getFrameCount() - 1; string msg; assert(r1 >= r0); @@ -725,7 +757,7 @@ int main(int argc, char *argv[]) { TVectorBrushStyle::setRootDir(libraryFolder); TPalette::setRootDir(libraryFolder); TImageStyle::setLibraryDir(libraryFolder); - TFilePath cacheRoot = ToonzFolder::getCacheRootFolder(); + TFilePath cacheRoot = ToonzFolder::getCacheRootFolder(); if (cacheRoot.isEmpty()) cacheRoot = TEnv::getStuffDir() + "cache"; TImageCache::instance()->setRootDir(cacheRoot); // #endif @@ -820,6 +852,10 @@ int main(int argc, char *argv[]) { // return false; } + // Check if the scene saved with the previous version AND the premultiply + // option is set to PNG level setting + UnsetPremultiplyOptionsInPngLevels(scene); + msg = "scene loaded"; cout << "scene loaded" << endl; m_userLog->info(msg); @@ -992,8 +1028,8 @@ int main(int argc, char *argv[]) { DVGui::info(QString::fromStdString(msg)); TImageCache::instance()->clear(true); } catch (TException &e) { - msg = "Untrapped exception: " + ::to_string(e.getMessage()), cout << msg - << endl; + msg = "Untrapped exception: " + ::to_string(e.getMessage()), + cout << msg << endl; m_userLog->error(msg); TImageCache::instance()->clear(true); } catch (...) { diff --git a/toonz/sources/toonz/iocommand.cpp b/toonz/sources/toonz/iocommand.cpp index 73933311..0b8162c9 100644 --- a/toonz/sources/toonz/iocommand.cpp +++ b/toonz/sources/toonz/iocommand.cpp @@ -671,6 +671,16 @@ void ChildLevelResourceImporter::process(TXshSimpleLevel *sl) { sl->load(); } catch (...) { } + + // Check if the scene saved with the previous version AND the premultiply + // option is set to PNG level setting + if (m_childScene->getVersionNumber() < + VersionNumber(71, 1)) { // V1.4 = 71.0 , V1.5 = 71.1 + if (!path.isEmpty() && path.getType() == "png" && + sl->getProperties()->doPremultiply()) + sl->getProperties()->setDoPremultiply(false); + } + sl->release(); } @@ -1994,6 +2004,31 @@ bool IoCmd::loadScene(const TFilePath &path, bool updateRecentFile, } } + // Check if the scene saved with the previous version AND the premultiply + // option is set to PNG level setting + if (scene->getVersionNumber() < + VersionNumber(71, 1)) { // V1.4 = 71.0 , V1.5 = 71.1 + QStringList modifiedPNGLevelNames; + std::vector levels; + scene->getLevelSet()->listLevels(levels); + for (auto level : levels) { + if (!level || !level->getSimpleLevel()) continue; + TFilePath path = level->getPath(); + if (path.isEmpty() || path.getType() != "png") continue; + if (level->getSimpleLevel()->getProperties()->doPremultiply()) { + level->getSimpleLevel()->getProperties()->setDoPremultiply(false); + modifiedPNGLevelNames.append(QString::fromStdWString(level->getName())); + } + } + if (!modifiedPNGLevelNames.isEmpty()) { + DVGui::info(QObject::tr("The Premultiply options in the following levels " + "are disabled, since PNG files are premultiplied " + "on loading in the current version: %1") + .arg(modifiedPNGLevelNames.join(", "))); + app->getCurrentScene()->setDirtyFlag(true); + } + } + printf("%s:%s loadScene() completed :\n", __FILE__, __FUNCTION__); return true; } diff --git a/toonz/sources/toonzlib/preferences.cpp b/toonz/sources/toonzlib/preferences.cpp index 3223d07d..81199ccd 100644 --- a/toonz/sources/toonzlib/preferences.cpp +++ b/toonz/sources/toonzlib/preferences.cpp @@ -109,9 +109,10 @@ void getDefaultLevelFormats(LevelFormatVector &lfv) { lfv[1].m_options.m_premultiply = true; // for all PNG files, set premultiply by default - lfv[2].m_name = Preferences::tr("PNG"); - lfv[2].m_pathFormat = QRegExp("..*\\.png", Qt::CaseInsensitive); - lfv[2].m_options.m_premultiply = true; + // UPDATE : from V1.5, PNG images are premultiplied on loading + // lfv[2].m_name = Preferences::tr("PNG"); + // lfv[2].m_pathFormat = QRegExp("..*\\.png", + // Qt::CaseInsensitive); lfv[2].m_options.m_premultiply = true; } } @@ -193,6 +194,32 @@ void getValue(QSettings &settings, getValue(settings, lfv[lf]); } settings.endArray(); + + // from OT V1.5, PNG images are premultiplied on loading. + // Leaving the premultiply option will cause unwanted double operation. + // So, check the loaded options and modify it "silently". + bool changed = false; + LevelFormatVector::iterator it = lfv.begin(); + while (it != lfv.end()) { + if ((*it).m_name == Preferences::tr("PNG") && + (*it).m_pathFormat == QRegExp("..*\\.png", Qt::CaseInsensitive) && + (*it).m_options.m_premultiply == true) { + LevelOptions defaultValue; + defaultValue.m_premultiply = true; + // if other parameters are the same as deafault, just erase the item + if ((*it).m_options == defaultValue) it = lfv.erase(it); + // if there are some adjustments by user, then disable only premultiply + // option + else { + (*it).m_options.m_premultiply = false; + ++it; + } + changed = true; + } else + ++it; + } + // overwrite the setting + if (changed) _setValue(settings, lfv); } } // namespace diff --git a/toonz/sources/toonzlib/toonzscene.cpp b/toonz/sources/toonzlib/toonzscene.cpp index 3bc0d96b..d9ccae2a 100644 --- a/toonz/sources/toonzlib/toonzscene.cpp +++ b/toonz/sources/toonzlib/toonzscene.cpp @@ -60,8 +60,11 @@ TOfflineGL *currentOfflineGL = 0; // Utility functions //============================================================================= namespace { - -const VersionNumber l_currentVersion(71, 0); +// tentatively update the scene file version from 71.0 to 71.1 in order to +// manage PNG level settings +const VersionNumber l_currentVersion(71, 1); +// TODO: Revise VersionNumber with OT version (converting 71.0 -> 14.0 , 71.1 +// -> 15.0) //----------------------------------------------------------------------------- @@ -345,12 +348,9 @@ bool ToonzScene::isUntitled() const { //----------------------------------------------------------------------------- void ToonzScene::load(const TFilePath &path, bool withProgressDialog) { - loadNoResources(path); // This loads a version number .. - loadResources(withProgressDialog); // .. this uses the version number .. - - setVersionNumber( - VersionNumber()); // .. but scene instances in memory do not retain -} // a version number beyond resource loading + loadNoResources(path); + loadResources(withProgressDialog); +} //----------------------------------------------------------------------------- @@ -456,7 +456,9 @@ void ToonzScene::loadTnzFile(const TFilePath &fp) { while (is.matchTag(tagName)) { if (tagName == "generator") { std::string program = is.getString(); - reading22 = program.find("2.2") != std::string::npos; + // TODO: This obsolete condition should be removed before releasing OT + // v2.2 ! + reading22 = program.find("2.2") != std::string::npos; } else if (tagName == "properties") m_properties->loadData(is, false); else if (tagName == "palette") // per compatibilita' beta1 @@ -685,6 +687,8 @@ void ToonzScene::save(const TFilePath &fp, TXsheet *subxsh) { } else { if (wasUntitled) deleteUntitledScene(oldScenePath.getParentDir()); } + // update the last saved version + setVersionNumber(l_currentVersion); } //----------------------------------------------------------------------------- From 43955919e697bb485feece649926ed7d56fea826 Mon Sep 17 00:00:00 2001 From: shun-iwasawa Date: Wed, 17 Mar 2021 08:10:53 +0900 Subject: [PATCH 02/24] fix fullscreen feature --- toonz/sources/toonzqt/imageutils.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/toonz/sources/toonzqt/imageutils.cpp b/toonz/sources/toonzqt/imageutils.cpp index 4a7a8c28..6e0eec55 100644 --- a/toonz/sources/toonzqt/imageutils.cpp +++ b/toonz/sources/toonzqt/imageutils.cpp @@ -924,9 +924,8 @@ bool FullScreenWidget::toggleFullScreen( // Define some constants for setting and clearing window flags. const Qt::WindowFlags kwfFullScreenWidgetFlags = - Qt::Window | // <-- Make the widget become a window. - Qt::WindowStaysOnTopHint | // <-- Ensure the window stays on top. - Qt::FramelessWindowHint; // <-- Full screen windows have no border. + Qt::Window | // <-- Make the widget become a window. + Qt::FramelessWindowHint; // <-- Full screen windows have no border. const Qt::WindowFlags kwfFullScreenWidgetExcludedFlagsMask = (Qt::WindowFlags)~Qt::WindowTitleHint; // <-- Full screen windows have no @@ -1028,8 +1027,7 @@ bool FullScreenWidget::toggleFullScreen( // effect. this->show(); #else - this->setWindowFlags(this->windowFlags() | Qt::Window | - Qt::WindowStaysOnTopHint); + this->setWindowFlags(this->windowFlags() | Qt::Window); this->window()->windowHandle()->setScreen(ptrScreenThisWindowIsOn); // http://doc.qt.io/qt-5/windows-issues.html#fullscreen-opengl-based-windows From 105c4111d91f3b19b813ebe482af15b97f7c96ff Mon Sep 17 00:00:00 2001 From: shun-iwasawa Date: Wed, 17 Mar 2021 10:06:19 +0900 Subject: [PATCH 03/24] fix mainwindow fullscreen --- toonz/sources/toonz/mainwindow.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/toonz/sources/toonz/mainwindow.cpp b/toonz/sources/toonz/mainwindow.cpp index 3a76c97e..477e4e30 100644 --- a/toonz/sources/toonz/mainwindow.cpp +++ b/toonz/sources/toonz/mainwindow.cpp @@ -55,6 +55,9 @@ #include #include #include +#ifdef _WIN32 +#include +#endif TEnv::IntVar ViewCameraToggleAction("ViewCameraToggleAction", 1); TEnv::IntVar ViewTableToggleAction("ViewTableToggleAction", 0); @@ -1263,9 +1266,16 @@ void MainWindow::maximizePanel() { void MainWindow::fullScreenWindow() { if (isFullScreen()) - setWindowState(Qt::WindowMaximized); - else - setWindowState(Qt::WindowFullScreen); + showNormal(); + else { +#if defined(_WIN32) + // http://doc.qt.io/qt-5/windows-issues.html#fullscreen-opengl-based-windows + this->winId(); + QWindowsWindowFunctions::setHasBorderInFullScreen(this->windowHandle(), + true); +#endif + this->showFullScreen(); + } } //----------------------------------------------------------------------------- From 745db64038769beae3d3d313310a5d2332e59a1c Mon Sep 17 00:00:00 2001 From: shun-iwasawa Date: Wed, 17 Mar 2021 10:48:43 +0900 Subject: [PATCH 04/24] fix raster brush refresh viewer --- toonz/sources/tnztools/fullcolorbrushtool.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/toonz/sources/tnztools/fullcolorbrushtool.cpp b/toonz/sources/tnztools/fullcolorbrushtool.cpp index 2a7fae35..ae7000f2 100644 --- a/toonz/sources/tnztools/fullcolorbrushtool.cpp +++ b/toonz/sources/tnztools/fullcolorbrushtool.cpp @@ -19,6 +19,7 @@ #include "toonz/txsheethandle.h" #include "toonz/txshlevelhandle.h" #include "toonz/tobjecthandle.h" +#include "toonz/tframehandle.h" #include "toonz/ttileset.h" #include "toonz/ttilesaver.h" #include "toonz/strokegenerator.h" @@ -291,7 +292,13 @@ bool FullColorBrushTool::askWrite(const TRect &rect) { bool FullColorBrushTool::preLeftButtonDown() { touchImage(); - if (m_isFrameCreated) setWorkAndBackupImages(); + if (m_isFrameCreated) { + setWorkAndBackupImages(); + // When the xsheet frame is selected, whole viewer will be updated from + // SceneViewer::onXsheetChanged() on adding a new frame. + // We need to take care of a case when the level frame is selected. + if (m_application->getCurrentFrame()->isEditingLevel()) invalidate(); + } return true; } @@ -308,7 +315,7 @@ void FullColorBrushTool::leftButtonDown(const TPointD &pos, if (!viewer) return; TRasterImageP ri = (TRasterImageP)getImage(true); - if (!ri) ri = (TRasterImageP)touchImage(); + if (!ri) ri = (TRasterImageP)touchImage(); if (!ri) return; From 1b6a664606028760ca6b8f734d1646f92648d3b4 Mon Sep 17 00:00:00 2001 From: shun-iwasawa Date: Wed, 17 Mar 2021 22:27:04 +0900 Subject: [PATCH 05/24] fix xdts popup duplicate fields --- toonz/sources/toonz/xdtsio.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/toonz/sources/toonz/xdtsio.cpp b/toonz/sources/toonz/xdtsio.cpp index 2c6f20f5..a3dbecfe 100644 --- a/toonz/sources/toonz/xdtsio.cpp +++ b/toonz/sources/toonz/xdtsio.cpp @@ -463,6 +463,8 @@ bool XdtsIo::loadXdtsScene(ToonzScene *scene, const TFilePath &scenePath) { // obtain level names QStringList levelNames = xdtsData.getLevelNames(); + // in case multiple columns have the same name + levelNames.removeDuplicates(); scene->clear(); From 363834928612bd33cf401bcd03c05b6e3a030a43 Mon Sep 17 00:00:00 2001 From: shun-iwasawa Date: Thu, 18 Mar 2021 17:36:39 +0900 Subject: [PATCH 06/24] fix palette bugs --- toonz/sources/toonz/filmstripcommand.cpp | 5 ++++- toonz/sources/toonzlib/studiopalettecmd.cpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/toonz/sources/toonz/filmstripcommand.cpp b/toonz/sources/toonz/filmstripcommand.cpp index 41df0025..4be7780d 100644 --- a/toonz/sources/toonz/filmstripcommand.cpp +++ b/toonz/sources/toonz/filmstripcommand.cpp @@ -412,8 +412,11 @@ std::map clearFramesWithoutUndo( "-" + QString::number(it->getNumber()); TImageCache::instance()->add(id, sl->getFrame(frameId, false)); clearedFrames[frameId] = id; + // empty frame must be created BEFORE erasing frame or it may initialize + // palette. + TImageP emptyFrame = sl->createEmptyFrame(); sl->eraseFrame(frameId); - sl->setFrame(*it, sl->createEmptyFrame()); + sl->setFrame(*it, emptyFrame); } invalidateIcons(sl.getPointer(), frames); TApp::instance()->getCurrentLevel()->notifyLevelChange(); diff --git a/toonz/sources/toonzlib/studiopalettecmd.cpp b/toonz/sources/toonzlib/studiopalettecmd.cpp index 043c827b..fe558114 100644 --- a/toonz/sources/toonzlib/studiopalettecmd.cpp +++ b/toonz/sources/toonzlib/studiopalettecmd.cpp @@ -591,7 +591,7 @@ void StudioPaletteCmd::mergeIntoCurrentPalette(TPaletteHandle *paletteHandle, TUndoManager::manager()->add( new PaletteAssignUndo(current, old, current->clone(), paletteHandle)); - palette->setDirtyFlag(true); + current->setDirtyFlag(true); paletteHandle->notifyPaletteChanged(); } From 589ae93f6b91ea068cd95810c7fc6182a60e9d5f Mon Sep 17 00:00:00 2001 From: shun-iwasawa Date: Thu, 18 Mar 2021 19:29:35 +0900 Subject: [PATCH 07/24] fix alt drag fx insertion --- toonz/sources/toonzqt/fxschematicscene.cpp | 135 +++++++++++---------- 1 file changed, 68 insertions(+), 67 deletions(-) diff --git a/toonz/sources/toonzqt/fxschematicscene.cpp b/toonz/sources/toonzqt/fxschematicscene.cpp index 533b260a..2707d593 100644 --- a/toonz/sources/toonzqt/fxschematicscene.cpp +++ b/toonz/sources/toonzqt/fxschematicscene.cpp @@ -490,7 +490,7 @@ void FxSchematicScene::updateEditedGroups( const QMap> &editedGroup) { QMap>::const_iterator it; for (it = editedGroup.begin(); it != editedGroup.end(); it++) { - int zValue = 2; + int zValue = 2; QMap>::const_iterator it2 = editedGroup.begin(); while (it2 != editedGroup.end()) { FxSchematicNode *placedFxNode = @@ -626,7 +626,7 @@ void FxSchematicScene::updatePosition(FxSchematicNode *node, //------------------------------------------------------------------ /*! create node depends on the fx type -*/ + */ FxSchematicNode *FxSchematicScene::createFxSchematicNode(TFx *fx) { if (TLevelColumnFx *lcFx = dynamic_cast(fx)) return new FxSchematicColumnNode(this, lcFx); @@ -644,7 +644,7 @@ FxSchematicNode *FxSchematicScene::createFxSchematicNode(TFx *fx) { //------------------------------------------------------------------ /*! place nodes of which positions are not specified manually -*/ + */ void FxSchematicScene::placeNode(FxSchematicNode *node) { if (!node) return; int step = m_gridDimension == eLarge ? 100 : 50; @@ -872,7 +872,7 @@ void FxSchematicScene::updateLink() { } TZeraryColumnFx *zfx = dynamic_cast(fx); - if (zfx) fx = zfx->getZeraryFx(); + if (zfx) fx = zfx->getZeraryFx(); if (fx) { int j; for (j = 0; j < fx->getInputPortCount(); j++) { @@ -1026,7 +1026,7 @@ QPointF FxSchematicScene::nearestPoint(const QPointF &point) { if (item) return rect.bottomRight(); item = itemAt(rect.topLeft()); if (item) return rect.topLeft(); - item = itemAt(rect.topRight()); + item = itemAt(rect.topRight()); #endif if (item) return rect.topRight(); return QPointF(); @@ -1471,8 +1471,8 @@ void FxSchematicScene::setEnableCache(bool toggle) { for (int i = 0; i < selectedFxs.size(); i++) { TFx *fx = selectedFxs[i].getPointer(); TZeraryColumnFx *zcfx = dynamic_cast(fx); - if (zcfx) fx = zcfx->getZeraryFx(); - TFxAttributes *attr = fx->getAttributes(); + if (zcfx) fx = zcfx->getZeraryFx(); + TFxAttributes *attr = fx->getAttributes(); if (!attr->isGrouped() || attr->isGroupEditing()) { if (toggle) { TPassiveCacheManager::instance()->enableCache(fx); @@ -1490,9 +1490,9 @@ void FxSchematicScene::setEnableCache(bool toggle) { TPassiveCacheManager::instance()->enableCache(fx); } else { TPassiveCacheManager::instance()->disableCache(fx); - } - } - } + } + } + } group->update(); } } @@ -1589,7 +1589,7 @@ void FxSchematicScene::mousePressEvent(QGraphicsSceneMouseEvent *me) { #if QT_VERSION >= 0x050000 QGraphicsItem *item = itemAt(me->scenePos(), QTransform()); #else - QGraphicsItem *item = itemAt(me->scenePos()); + QGraphicsItem *item = itemAt(me->scenePos()); #endif FxSchematicPort *port = dynamic_cast(item); FxSchematicLink *link = dynamic_cast(item); @@ -1646,7 +1646,7 @@ void FxSchematicScene::mouseMoveEvent(QGraphicsSceneMouseEvent *me) { SchematicLink *link = dynamic_cast(itemAt(m_lastPos, QTransform())); #else - SchematicLink *link = dynamic_cast(itemAt(m_lastPos)); + SchematicLink *link = dynamic_cast(itemAt(m_lastPos)); #endif if (link && (link->getEndPort() && link->getStartPort())) { TFxCommand::Link fxLink = m_selection->getBoundingFxs(link); @@ -1710,8 +1710,8 @@ void FxSchematicScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *me) { if (port == outputNode->getInputPort(i)) break; TFxCommand::Link fxLink; - fxLink.m_outputFx = outputNode->getFx(); - fxLink.m_inputFx = inputNode->getFx(); + fxLink.m_outputFx = outputNode->getFx(); + fxLink.m_inputFx = inputNode->getFx(); if (!outputNode->isA(eXSheetFx)) fxLink.m_index = i; TFxCommand::connectFxs(fxLink, m_selection->getFxs().toStdList(), @@ -1880,7 +1880,7 @@ void FxSchematicScene::simulateDisconnectSelection(bool disconnect) { if (selectedFxs.isEmpty()) return; QMap visitedFxs; int i; - for (i = 0; i < selectedFxs.size(); i++) + for (i = 0; i < selectedFxs.size(); i++) visitedFxs[selectedFxs[i].getPointer()] = false; TFx *inputFx = 0, *outputFx = 0; @@ -1935,61 +1935,62 @@ void FxSchematicScene::simulateDisconnectSelection(bool disconnect) { void FxSchematicScene::simulateInsertSelection(SchematicLink *link, bool connect) { - if (!link || !connect) { - m_connectionLinks.showBridgeLinks(); - m_connectionLinks.hideInputLinks(); - m_connectionLinks.hideOutputLinks(); - m_connectionLinks.removeBridgeLinks(); - m_connectionLinks.removeInputLinks(true); - m_connectionLinks.removeOutputLinks(true); - } else { - if (m_disconnectionLinks.isABridgeLink(link) || m_selection->isEmpty()) - return; + // first, remove all connected links + m_connectionLinks.showBridgeLinks(); + m_connectionLinks.hideInputLinks(); + m_connectionLinks.hideOutputLinks(); + m_connectionLinks.removeBridgeLinks(); + m_connectionLinks.removeInputLinks(true); + m_connectionLinks.removeOutputLinks(true); + if (!link || !connect) return; - m_connectionLinks.addBridgeLink(link); - m_connectionLinks.hideBridgeLinks(); + if (m_disconnectionLinks.isABridgeLink(link) || m_selection->isEmpty()) + return; - SchematicPort *inputPort = 0, *outputPort = 0; - if (link) { - if (link->getStartPort()->getType() == eFxInputPort) { - inputPort = link->getStartPort(); - outputPort = link->getEndPort(); - } else { - inputPort = link->getEndPort(); - outputPort = link->getStartPort(); - } + m_connectionLinks.addBridgeLink(link); + m_connectionLinks.hideBridgeLinks(); + + SchematicPort *inputPort = 0, *outputPort = 0; + if (link) { + if (link->getStartPort()->getType() == eFxInputPort) { + inputPort = link->getStartPort(); + outputPort = link->getEndPort(); + } else { + inputPort = link->getEndPort(); + outputPort = link->getStartPort(); } - - QMap visitedFxs; - QList selectedFxs = m_selection->getFxs(); - if (selectedFxs.isEmpty()) return; - int i; - for (i = 0; i < selectedFxs.size(); i++) - visitedFxs[selectedFxs[i].getPointer()] = false; - - TFx *inputFx = 0, *outputFx = 0; - findBoundariesFxs(inputFx, outputFx, visitedFxs); - FxSchematicNode *inputNode = m_table[inputFx]; - FxSchematicNode *outputNode = m_table[outputFx]; - assert(inputNode && outputNode); - - if (inputNode->getInputPortCount() > 0) { - SchematicPort *inputNodePort = inputNode->getInputPort(0); - if (inputNodePort && outputPort) - m_connectionLinks.addInputLink(inputNodePort->makeLink(outputPort)); - } - - SchematicPort *outputNodePort = outputNode->getOutputPort(); - if (outputNodePort && inputPort) - m_connectionLinks.addOutputLink(inputPort->makeLink(outputNodePort)); - - m_connectionLinks.showInputLinks(); - m_connectionLinks.showOutputLinks(); } + + QMap visitedFxs; + QList selectedFxs = m_selection->getFxs(); + if (selectedFxs.isEmpty()) return; + int i; + for (i = 0; i < selectedFxs.size(); i++) + visitedFxs[selectedFxs[i].getPointer()] = false; + + TFx *inputFx = 0, *outputFx = 0; + findBoundariesFxs(inputFx, outputFx, visitedFxs); + FxSchematicNode *inputNode = m_table[inputFx]; + FxSchematicNode *outputNode = m_table[outputFx]; + assert(inputNode && outputNode); + + if (inputNode->getInputPortCount() > 0) { + SchematicPort *inputNodePort = inputNode->getInputPort(0); + if (inputNodePort && outputPort) + m_connectionLinks.addInputLink(inputNodePort->makeLink(outputPort)); + } + + SchematicPort *outputNodePort = outputNode->getOutputPort(); + if (outputNodePort && inputPort) + m_connectionLinks.addOutputLink(inputPort->makeLink(outputNodePort)); + + m_connectionLinks.showInputLinks(); + m_connectionLinks.showOutputLinks(); } + //------------------------------------------------------------ /*! in order to select nods after pasting the copied fx nodes from FxSelection -*/ + */ void FxSchematicScene::selectNodes(QList &fxs) { clearSelection(); for (int i = 0; i < (int)fxs.size(); i++) { @@ -2021,7 +2022,7 @@ void FxSchematicScene::updateNestedGroupEditors(FxSchematicNode *node, #if QT_VERSION >= 0x050000 rect = rect.united(app); #else - rect = rect.unite(app); + rect = rect.unite(app); #endif } } @@ -2035,7 +2036,7 @@ void FxSchematicScene::updateNestedGroupEditors(FxSchematicNode *node, #if QT_VERSION >= 0x050000 rect = rect.united(app); #else - rect = rect.unite(app); + rect = rect.unite(app); #endif } } @@ -2046,7 +2047,7 @@ void FxSchematicScene::updateNestedGroupEditors(FxSchematicNode *node, rect = rect.united(m_groupEditorTable[groupIdStack[i]]->sceneBoundingRect()); #else - rect = rect.unite(m_groupEditorTable[groupIdStack[i]]->sceneBoundingRect()); + rect = rect.unite(m_groupEditorTable[groupIdStack[i]]->sceneBoundingRect()); #endif QRectF app = m_groupEditorTable[groupIdStack[i]]->boundingSceneRect(); if (m_groupEditorTable[groupIdStack[i]]->scenePos() != app.topLeft()) @@ -2059,7 +2060,7 @@ void FxSchematicScene::updateNestedGroupEditors(FxSchematicNode *node, #if QT_VERSION >= 0x050000 rect = rect.united(app); #else - rect = rect.unite(app); + rect = rect.unite(app); #endif app = editor->boundingSceneRect(); if (editor->scenePos() != app.topLeft()) editor->setPos(app.topLeft()); From eada04487efee2629abe6e7ad47f7ce74e2916f4 Mon Sep 17 00:00:00 2001 From: shun-iwasawa Date: Fri, 19 Mar 2021 10:56:41 +0900 Subject: [PATCH 08/24] fix crash on inserting new frame this fixes erasing level frame to remove icon cache as well --- toonz/sources/toonzlib/txshsimplelevel.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/toonz/sources/toonzlib/txshsimplelevel.cpp b/toonz/sources/toonzlib/txshsimplelevel.cpp index 981991c6..0a56cac1 100644 --- a/toonz/sources/toonzlib/txshsimplelevel.cpp +++ b/toonz/sources/toonzlib/txshsimplelevel.cpp @@ -840,10 +840,15 @@ void TXshSimpleLevel::eraseFrame(const TFrameId &fid) { getHookSet()->eraseFrame(fid); ImageManager *im = ImageManager::instance(); + TImageCache *ic = TImageCache::instance(); { im->unbind(getImageId(fid, Normal)); im->unbind(getImageId(fid, Scanned)); im->unbind(getImageId(fid, CleanupPreview)); + // remove icon cache as well + ic->remove(getIconId(fid, Normal)); + ic->remove(getIconId(fid, Scanned)); + ic->remove(getIconId(fid, CleanupPreview)); if (m_type == PLI_XSHLEVEL) im->unbind(rasterized(getImageId(fid))); @@ -858,13 +863,17 @@ void TXshSimpleLevel::eraseFrame(const TFrameId &fid) { void TXshSimpleLevel::clearFrames() { ImageManager *im = ImageManager::instance(); - + TImageCache *ic = TImageCache::instance(); // Unbind frames FramesSet::iterator ft, fEnd = m_frames.end(); for (ft = m_frames.begin(); ft != fEnd; ++ft) { im->unbind(getImageId(*ft, Scanned)); im->unbind(getImageId(*ft, Cleanupped)); im->unbind(getImageId(*ft, CleanupPreview)); + // remove icon cache as well + ic->remove(getIconId(*ft, Normal)); + ic->remove(getIconId(*ft, Scanned)); + ic->remove(getIconId(*ft, CleanupPreview)); if (m_type == PLI_XSHLEVEL) im->unbind(rasterized(getImageId(*ft))); From 9413771ac6423228a50c69c88a2afffe221fbbbb Mon Sep 17 00:00:00 2001 From: shun-iwasawa Date: Fri, 19 Mar 2021 13:23:20 +0900 Subject: [PATCH 09/24] fix opengl line smoothing --- toonz/sources/common/tgl/tgl.cpp | 17 +++++++++-------- toonz/sources/tnzext/meshutils.cpp | 2 +- toonz/sources/tnztools/plastictool.cpp | 6 +++--- toonz/sources/toonzlib/stagevisitor.cpp | 2 ++ 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/toonz/sources/common/tgl/tgl.cpp b/toonz/sources/common/tgl/tgl.cpp index c4bcd70e..17f72c51 100644 --- a/toonz/sources/common/tgl/tgl.cpp +++ b/toonz/sources/common/tgl/tgl.cpp @@ -66,7 +66,7 @@ double tglGetPixelSize2() { glMatrixMode(GL_MODELVIEW); glGetDoublev(GL_MODELVIEW_MATRIX, mat); - double det = fabs(mat[0] * mat[5] - mat[1] * mat[4]); + double det = fabs(mat[0] * mat[5] - mat[1] * mat[4]); if (det < TConsts::epsilon) det = TConsts::epsilon; return 1.0 / det; } @@ -245,6 +245,7 @@ void tglEnableBlending(GLenum src, GLenum dst) { void tglEnableLineSmooth(bool enable, double lineSize) { if (enable) { + tglEnableBlending(); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); glEnable(GL_LINE_SMOOTH); glLineWidth(lineSize); @@ -431,7 +432,7 @@ void tglDraw(const TRectD &rect, const std::vector &textures, unsigned int level = 1; while (pixelSize2 * level * level <= 1.0) level <<= 1; - unsigned int texturesCount = (int)textures.size(); + unsigned int texturesCount = (int)textures.size(); if (level > texturesCount) level = texturesCount; level = texturesCount - level; @@ -467,8 +468,8 @@ void tglDraw(const TRectD &rect, const TRaster32P &tex, bool blending) { texture = TRaster32P(texWidth, texHeight); texture->fill(TPixel32(0, 0, 0, 0)); texture->copy(tex); - lwTex = (texLx) / (double)(texWidth); - lhTex = (texLy) / (double)(texHeight); + lwTex = (texLx) / (double)(texWidth); + lhTex = (texLy) / (double)(texHeight); if (lwTex > 1.0) lwTex = 1.0; if (lhTex > 1.0) lhTex = 1.0; } else @@ -587,10 +588,10 @@ void tglBuildMipmaps(std::vector &rasters, ly >>= 1; if (lx < 1) lx = 1; if (ly < 1) ly = 1; - rasters[i] = TRaster32P(lx, ly); - sx = (double)lx / (double)ras2Lx; - sy = (double)ly / (double)ras2Ly; - rasters[i] = TRaster32P(lx, ly); + rasters[i] = TRaster32P(lx, ly); + sx = (double)lx / (double)ras2Lx; + sy = (double)ly / (double)ras2Ly; + rasters[i] = TRaster32P(lx, ly); #ifndef SCALE_BY_GLU TRop::resample(rasters[i], ras2, TScale(sx, sy), resampleFilter); #else diff --git a/toonz/sources/tnzext/meshutils.cpp b/toonz/sources/tnzext/meshutils.cpp index c21f09cc..7d3b0e98 100644 --- a/toonz/sources/tnzext/meshutils.cpp +++ b/toonz/sources/tnzext/meshutils.cpp @@ -326,7 +326,7 @@ void tglDraw(const TMeshImage &meshImage, const DrawableTextureData &texData, GL_HINT_BIT); // Preserve original status bits glEnable(GL_BLEND); - + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_LINE_SMOOTH); glLineWidth(1.0f); diff --git a/toonz/sources/tnztools/plastictool.cpp b/toonz/sources/tnztools/plastictool.cpp index 2c2985e8..9787069b 100644 --- a/toonz/sources/tnztools/plastictool.cpp +++ b/toonz/sources/tnztools/plastictool.cpp @@ -1973,9 +1973,8 @@ void PlasticTool::drawOnionSkinSkeletons_animate(double pixelSize) { PlasticSkeleton skel; m_sd->storeDeformedSkeleton(m_sd->skeletonId(sdFrame), sdFrame, skel); - UCHAR alpha = - 255 - - 255.0 * OnionSkinMask::getOnionSkinFade(abs(osRows[r] - currentRow)); + UCHAR alpha = 255 - 255.0 * OnionSkinMask::getOnionSkinFade( + abs(osRows[r] - currentRow)); drawSkeleton(skel, pixelSize, alpha); } } @@ -2114,6 +2113,7 @@ void PlasticTool::draw() { glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT); glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_LINE_SMOOTH); switch (m_mode.getIndex()) { diff --git a/toonz/sources/toonzlib/stagevisitor.cpp b/toonz/sources/toonzlib/stagevisitor.cpp index fee3a22c..60ab51a5 100644 --- a/toonz/sources/toonzlib/stagevisitor.cpp +++ b/toonz/sources/toonzlib/stagevisitor.cpp @@ -1405,6 +1405,7 @@ void onMeshImage(TMeshImage *mi, const Stage::Player &player, // Prepare OpenGL glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_LINE_SMOOTH); // Push mesh coordinates @@ -1581,6 +1582,7 @@ void onPlasticDeformedImage(TStageObject *playerObj, // Set up OpenGL stuff glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_LINE_SMOOTH); // Push mesh coordinates From 5a08ce299766481a0eb59c165b5887b91dc611be Mon Sep 17 00:00:00 2001 From: andeon Date: Fri, 19 Mar 2021 18:21:36 -0300 Subject: [PATCH 10/24] feat: FxParticles preset simulating the Flock effect (birds, insects, fishes) --- stuff/fxs/presets/STD_particlesFx/Flock.fx | 716 +++++++++++++++++++++ 1 file changed, 716 insertions(+) create mode 100644 stuff/fxs/presets/STD_particlesFx/Flock.fx diff --git a/stuff/fxs/presets/STD_particlesFx/Flock.fx b/stuff/fxs/presets/STD_particlesFx/Flock.fx new file mode 100644 index 00000000..06a6fa60 --- /dev/null +++ b/stuff/fxs/presets/STD_particlesFx/Flock.fx @@ -0,0 +1,716 @@ + + + + 0 0 + + + 25 25 + + + 0 0 + +
+ + + 444.444 + + + + + 0 + + +
+ + + 4.44444 + + + + + 480 + + + + + 1 + + + + + + 900 + + + + + 900 + + + + + 0 0 + + + 0 0 + + + 1 1 + + + 1 1 + + + + 0 + + + + + 0 + + + + 0 0 + + + + 0 + + + + 0 0 + + + + 0 + + + + + 0 + + + + 1 + + + + + 0 + + + + + 0 + + + + + + + 0.444444 + + + + + 11.1111 + + + + + 0 0 + + + 0 0 + + + + + 15 + + + + + 45 + + + + + + + 20 + + + + + 26.6667 + + + + + 0 0 + + + + + -105 + + + + + -60 + + + + + 0 0 + + + 0 0 + + + 0 0 + + + 4 + + + + + 1 + + + + + 1 + + + + + + + 30 + + + + + 75 + + + + + 0 0 + + + 0 0 + + + + + 0 + + + + + 0 + + + + + 0 0 + + + + + 0 + + + + + 0 + + + + + + 0 + + + + 0 + + + + 0 + + + + + + 0 + + + + + 0 + + + + + + + 0 + + + + + 0 + + + + + 0 0 + + + + + 0 + + + + + 100 + + + + + 0 0 + + + + + 0 + + + + + 100 + + + + + + + -2 + + + + + 3 + + + + + 0 0 + + + + 0 + + + + + 0 + + + + 3 + + + 1 1 + + + + + + 0 + + + + 0 0 1 0 + + + + + + + 1 + + + + 0 1 1 0 + + + + + + 0 + + + + 0 0 1 0 + + + + + + 0 + + + + 0 0 1 0 + + + + + + 1 + + + + 0 1 1 0 + + + + + + + 1 + + + + 0 1 1 0 + + + + + + + 1 + + + + 0 1 1 0 + + + + + + 0 + + + + 0 0 1 0 + + + + + + 0 + + + + 0 0 1 0 + + + + + + 1 + + + + 0 1 1 0 + + + + + + + + 0 0 + + + + 0 + + + + + 0 + + + + + + + 0 + + + + 0 0 1 0 + + + + + + + 0 + + + + 0 0 1 0 + + + + + + 1 + + + + 0 1 1 0 + + + + + + 0 + + + + 0 0 1 0 + + + + + + 1 + + + + 0 1 1 0 + + + + + + + 1 + + + + 0 1 1 0 + + + + + + + 0 + + + + 0 0 1 0 + + + + + + 1 + + + + 0 1 1 0 + + + + + + 0 + + + + 0 0 1 0 + + + + + + 1 + + + + 0 1 1 0 + + + + + + + + 0 0 + + + + 0 + + + + + 0 + + + + + 0 + + + + + + + 0 + + + + 0 0 1 0 + + + + + + + 0 + + + + 0 0 1 0 + + + + + + 0 + + + + 0 0 1 0 + + + + + + 1 + + + + 0 1 1 0 + + + + + + 1 + + + + 0 1 1 0 + + + + + + + 1 + + + + 0 1 1 0 + + + + + + + 0 + + + + 0 0 1 0 + + + + + + 0 + + + + 0 0 1 0 + + + + + + 1 + + + + 0 1 1 0 + + + + + + 1 + + + + 0 1 1 0 + + + + + + + + 0 0 + + + + 0 + + + + + 0 + + + + + 0 + + + + 0 0 + + + 0 0 + + + 0 0 + +
+
From 7cab85a38d95c6026a311fe245b7544cdc8fa13d Mon Sep 17 00:00:00 2001 From: Anderson Prado Date: Fri, 19 Mar 2021 20:13:34 -0300 Subject: [PATCH 11/24] Parameters added to mimic the sense of depth shun-iwasawa's suggestion --- stuff/fxs/presets/STD_particlesFx/Flock.fx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stuff/fxs/presets/STD_particlesFx/Flock.fx b/stuff/fxs/presets/STD_particlesFx/Flock.fx index 06a6fa60..f2be4c3a 100644 --- a/stuff/fxs/presets/STD_particlesFx/Flock.fx +++ b/stuff/fxs/presets/STD_particlesFx/Flock.fx @@ -170,10 +170,10 @@ 0 0 - 0 0 + 0 1 - 4 + 3 @@ -710,7 +710,7 @@ 0 0 - 0 0 + 0 1 From c3e4dc69ac0aed618fb1096b49d22e8819570b31 Mon Sep 17 00:00:00 2001 From: shun-iwasawa Date: Sat, 20 Mar 2021 06:48:09 +0900 Subject: [PATCH 12/24] fix wrong blending --- toonz/sources/common/tgl/tgl.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/toonz/sources/common/tgl/tgl.cpp b/toonz/sources/common/tgl/tgl.cpp index 17f72c51..254fd9f1 100644 --- a/toonz/sources/common/tgl/tgl.cpp +++ b/toonz/sources/common/tgl/tgl.cpp @@ -245,7 +245,6 @@ void tglEnableBlending(GLenum src, GLenum dst) { void tglEnableLineSmooth(bool enable, double lineSize) { if (enable) { - tglEnableBlending(); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); glEnable(GL_LINE_SMOOTH); glLineWidth(lineSize); From 7e404d10697ac1f069a899f44293b141429d614a Mon Sep 17 00:00:00 2001 From: shun-iwasawa Date: Sat, 20 Mar 2021 19:38:48 +0900 Subject: [PATCH 13/24] fix cleanup to set image data --- toonz/sources/toonz/cleanuppopup.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/toonz/sources/toonz/cleanuppopup.cpp b/toonz/sources/toonz/cleanuppopup.cpp index 03115508..1458370e 100644 --- a/toonz/sources/toonz/cleanuppopup.cpp +++ b/toonz/sources/toonz/cleanuppopup.cpp @@ -310,6 +310,9 @@ CleanupPopup::CleanupPopup() m_imgViewBox->setChecked(false); m_imageViewer->setVisible(false); m_imageViewer->resize(406, 306); + ImagePainter::VisualSettings settings; + settings.m_bg = 0x80000; // set to white regardless of the flipbook bg + m_imageViewer->setVisual(settings); //---layout QVBoxLayout *mainLayout = new QVBoxLayout(); @@ -563,7 +566,8 @@ bool CleanupPopup::analyzeCleanupList() { } // Prompt user for file conflict resolution - clt.m_resolution = Resolution(m_overwriteDialog->execute(&clt.m_outputPath)); + clt.m_resolution = + Resolution(m_overwriteDialog->execute(&clt.m_outputPath)); switch (clt.m_resolution) { case CANCEL: return false; @@ -1253,7 +1257,9 @@ void CleanupPopup::cleanupFrame() { // Update the level data about the cleanupped frame sl->setFrameStatus(fid, sl->getFrameStatus(fid) | TXshSimpleLevel::Cleanupped); - sl->setFrame(fid, TImageP()); // Invalidate the old image data + + // sl->setFrame(fid, TImageP()); // Invalidate the old image data + sl->setFrame(fid, ti); // replace with the new image data // Output the cleanupped image to disk try { From 909c04ab5b8f0834041cc60f37a93f8d2ce5fb03 Mon Sep 17 00:00:00 2001 From: shun-iwasawa Date: Tue, 23 Mar 2021 16:43:41 +0900 Subject: [PATCH 14/24] fix color model pick mode --- toonz/sources/tnztools/fingertool.cpp | 2 +- toonz/sources/toonz/colormodelviewer.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/toonz/sources/tnztools/fingertool.cpp b/toonz/sources/tnztools/fingertool.cpp index f7b501f3..38fae90a 100644 --- a/toonz/sources/tnztools/fingertool.cpp +++ b/toonz/sources/tnztools/fingertool.cpp @@ -565,7 +565,7 @@ void FingerTool::pick(const TPointD &pos) { int styleId = picker.pickStyleId(TScale(1.0 / subsampling) * pos + TPointD(-0.5, -0.5), - getPixelSize() * getPixelSize(), modeValue); + getPixelSize() * getPixelSize(), 1.0, modeValue); if (styleId < 0) return; diff --git a/toonz/sources/toonz/colormodelviewer.cpp b/toonz/sources/toonz/colormodelviewer.cpp index 6149c487..26f6fde2 100644 --- a/toonz/sources/toonz/colormodelviewer.cpp +++ b/toonz/sources/toonz/colormodelviewer.cpp @@ -303,11 +303,13 @@ void ColorModelViewer::pick(const QPoint &p) { TPointD(viewP.x() - m_imageViewer->width() / 2, -viewP.y() + m_imageViewer->height() / 2); + double scale2 = m_imageViewer->getViewAff().det(); /*--- カレントToolに合わせてPickモードを変更 0=Area, 1=Line, 2=Line&Areas(default) ---*/ - int styleIndex = picker.pickStyleId(pos + TPointD(-0.5, -0.5), 1, m_mode); + int styleIndex = + picker.pickStyleId(pos + TPointD(-0.5, -0.5), 1, scale2, m_mode); if (styleIndex < 0) return; From 1c796dd055970f008771029e42d10cef42767b20 Mon Sep 17 00:00:00 2001 From: shun-iwasawa Date: Thu, 18 Mar 2021 15:28:59 +0900 Subject: [PATCH 15/24] enable to specify cmake_prefix_path --- toonz/sources/CMakeLists.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/toonz/sources/CMakeLists.txt b/toonz/sources/CMakeLists.txt index b4f31e34..b3c305cc 100644 --- a/toonz/sources/CMakeLists.txt +++ b/toonz/sources/CMakeLists.txt @@ -145,7 +145,7 @@ if(BUILD_ENV_MSVC) return() endif() set(QT_LIB_PATH ${QT_PATH}) - set(CMAKE_PREFIX_PATH "${QT_PATH}/lib/cmake/") + set(CMAKE_PREFIX_PATH "${CMAKE_PREFIX_PATH};${QT_PATH}/lib/cmake/") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4251") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4251") add_definitions( @@ -159,12 +159,12 @@ elseif(BUILD_ENV_APPLE) endif() message("PLATFORM:" ${PLATFORM}) if(PLATFORM EQUAL 64) - set(QT_PATH "~/Qt5.9.2/5.9.2/clang_64/lib" CACHE PATH "Qt installation directory") - # set(QT_PATH "/usr/local/Cellar/qt/5.15.0/lib" CACHE PATH "Qt installation directory") + set(QT_PATH "~/Qt5.9.2/5.9.2/clang_${PLATFORM}/lib" CACHE PATH "Qt installation directory") set(QT_LIB_PATH "${QT_PATH}/") - set(CMAKE_PREFIX_PATH "${QT_LIB_PATH}cmake/") - - message("CMAKE_PREFIX_PATH:" ${CMAKE_PREFIX_PATH}) + set(CMAKE_PREFIX_PATH "${CMAKE_PREFIX_PATH};${QT_LIB_PATH}cmake/") + foreach(path ${CMAKE_PREFIX_PATH}) + message("CMAKE_PREFIX_PATH: " ${path}) + endforeach(path) add_definitions( -DMACOSX -Di386 From 2b95cf72d0b176fd154eecc1f263184a10d124f6 Mon Sep 17 00:00:00 2001 From: shun-iwasawa Date: Sat, 20 Mar 2021 00:02:31 +0900 Subject: [PATCH 16/24] fix pasting raster to cell --- toonz/sources/toonz/cellselection.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/toonz/sources/toonz/cellselection.cpp b/toonz/sources/toonz/cellselection.cpp index 44858c8d..75bd8abe 100644 --- a/toonz/sources/toonz/cellselection.cpp +++ b/toonz/sources/toonz/cellselection.cpp @@ -779,6 +779,8 @@ bool pasteRasterImageInCellWithoutUndo(int row, int col, app->getCurrentLevel()->setLevel(sl); app->getCurrentLevel()->notifyLevelChange(); sl->save(); + // after saving you need to obtain the image again + img = sl->getFrame(fid, true); } else { img = sl->createEmptyFrame(); assert(img); @@ -788,6 +790,8 @@ bool pasteRasterImageInCellWithoutUndo(int row, int col, sl->setFrame(fid, img); } xsh->setCell(row, col, TXshCell(sl, fid)); + // to let the undo to know which frame is edited + TTool::m_cellsData.push_back({row, row, TTool::CellOps::BlankToNew}); } else { sl = cell.getSimpleLevel(); fid = cell.getFrameId(); @@ -1785,6 +1789,8 @@ static void pasteRasterImageInCell(int row, int col, bool newLevel = false) { TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); + // to let the undo to know which frame is edited + TTool::m_cellsData.clear(); bool createdFrame = false; bool isLevelCreated = false; TPaletteP oldPalette = 0; @@ -4085,4 +4091,4 @@ void TCellSelection::fillEmptyCell() { if (initUndo) TUndoManager::manager()->endBlock(); TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); -} \ No newline at end of file +} From c6848d21756039751e0b139161013283e3133394 Mon Sep 17 00:00:00 2001 From: shun-iwasawa Date: Mon, 22 Mar 2021 18:54:46 +0900 Subject: [PATCH 17/24] fix crash on launch with shrinked imageviewer --- toonz/sources/toonz/imageviewer.cpp | 5 +++++ toonz/sources/toonz/sceneviewer.cpp | 5 +++++ toonz/sources/toonzqt/styleeditor.cpp | 2 ++ 3 files changed, 12 insertions(+) diff --git a/toonz/sources/toonz/imageviewer.cpp b/toonz/sources/toonz/imageviewer.cpp index 90d13bf9..45c884a1 100644 --- a/toonz/sources/toonz/imageviewer.cpp +++ b/toonz/sources/toonz/imageviewer.cpp @@ -1345,6 +1345,8 @@ void ImageViewer::onContextAboutToBeDestroyed() { makeCurrent(); m_lutCalibrator->cleanup(); doneCurrent(); + disconnect(context(), SIGNAL(aboutToBeDestroyed()), this, + SLOT(onContextAboutToBeDestroyed())); } //----------------------------------------------------------------------------- @@ -1352,6 +1354,9 @@ void ImageViewer::onContextAboutToBeDestroyed() { void ImageViewer::onPreferenceChanged(const QString& prefName) { if (prefName == "ColorCalibration") { if (Preferences::instance()->isColorCalibrationEnabled()) { + // if the window is so shriked that the gl widget is empty, + // showEvent can be called before creating the context. + if (!context()) return; makeCurrent(); if (!m_lutCalibrator) m_lutCalibrator = new LutCalibrator(); diff --git a/toonz/sources/toonz/sceneviewer.cpp b/toonz/sources/toonz/sceneviewer.cpp index 59dc9f40..2b5c4f5f 100644 --- a/toonz/sources/toonz/sceneviewer.cpp +++ b/toonz/sources/toonz/sceneviewer.cpp @@ -1209,6 +1209,9 @@ void SceneViewer::onStopMotionLiveViewStopped() { void SceneViewer::onPreferenceChanged(const QString &prefName) { if (prefName == "ColorCalibration") { if (Preferences::instance()->isColorCalibrationEnabled()) { + // if the window is so shriked that the gl widget is empty, + // showEvent can be called before creating the context. + if (!context()) return; makeCurrent(); if (!m_lutCalibrator) m_lutCalibrator = new LutCalibrator(); @@ -3555,6 +3558,8 @@ void SceneViewer::onContextAboutToBeDestroyed() { makeCurrent(); m_lutCalibrator->cleanup(); doneCurrent(); + disconnect(context(), SIGNAL(aboutToBeDestroyed()), this, + SLOT(onContextAboutToBeDestroyed())); } //----------------------------------------------------------------------------- diff --git a/toonz/sources/toonzqt/styleeditor.cpp b/toonz/sources/toonzqt/styleeditor.cpp index 77ee2ab1..539bc0b7 100644 --- a/toonz/sources/toonzqt/styleeditor.cpp +++ b/toonz/sources/toonzqt/styleeditor.cpp @@ -989,6 +989,8 @@ void HexagonalColorWheel::onContextAboutToBeDestroyed() { makeCurrent(); m_lutCalibrator->cleanup(); doneCurrent(); + disconnect(context(), SIGNAL(aboutToBeDestroyed()), this, + SLOT(onContextAboutToBeDestroyed())); } //***************************************************************************** From f3723672e641fff70d6bfdd4bc7d054229e64172 Mon Sep 17 00:00:00 2001 From: shun-iwasawa Date: Tue, 23 Mar 2021 12:32:10 +0900 Subject: [PATCH 18/24] fix style shortcut when full screen --- toonz/sources/toonz/sceneviewerevents.cpp | 13 ++++++++++++- .../sources/toonz/styleshortcutswitchablepanel.cpp | 7 ++++++- toonz/sources/toonz/styleshortcutswitchablepanel.h | 2 ++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/toonz/sources/toonz/sceneviewerevents.cpp b/toonz/sources/toonz/sceneviewerevents.cpp index cebfd9f3..83593d43 100644 --- a/toonz/sources/toonz/sceneviewerevents.cpp +++ b/toonz/sources/toonz/sceneviewerevents.cpp @@ -16,6 +16,8 @@ #include "comboviewerpane.h" #include "locatorpopup.h" #include "cellselection.h" +#include "styleshortcutswitchablepanel.h" + #include "stopmotion.h" #include "tstopwatch.h" @@ -1634,6 +1636,15 @@ void SceneViewer::keyPressEvent(QKeyEvent *event) { event->modifiers() == Qt::KeypadModifier) && ((Qt::Key_0 <= key && key <= Qt::Key_9) || key == Qt::Key_Tab || key == Qt::Key_Backtab)) { + // When the viewer is in full screen mode, directly call the style + // shortcut function since the viewer is retrieved from the parent + // panel. + if (parentWidget() && + parentWidget()->windowState() & Qt::WindowFullScreen) { + StyleShortcutSwitchablePanel::onKeyPress(event); + return true; + } + event->ignore(); return true; } @@ -2037,4 +2048,4 @@ void SceneViewer::resetNavigation() { invalidateToolStatus(); } } -} \ No newline at end of file +} diff --git a/toonz/sources/toonz/styleshortcutswitchablepanel.cpp b/toonz/sources/toonz/styleshortcutswitchablepanel.cpp index 2ad36072..5e77f314 100644 --- a/toonz/sources/toonz/styleshortcutswitchablepanel.cpp +++ b/toonz/sources/toonz/styleshortcutswitchablepanel.cpp @@ -21,7 +21,7 @@ //----------------------------------------------------------------------------- -void StyleShortcutSwitchablePanel::keyPressEvent(QKeyEvent *event) { +void StyleShortcutSwitchablePanel::onKeyPress(QKeyEvent *event) { if (!Preferences::instance()->isUseNumpadForSwitchingStylesEnabled()) return; TTool *tool = TApp::instance()->getCurrentTool()->getTool(); if (!tool) return; @@ -57,6 +57,11 @@ void StyleShortcutSwitchablePanel::keyPressEvent(QKeyEvent *event) { event->accept(); } } +//----------------------------------------------------------------------------- + +void StyleShortcutSwitchablePanel::keyPressEvent(QKeyEvent *event) { + StyleShortcutSwitchablePanel::onKeyPress(event); +} //----------------------------------------------------------------------------- diff --git a/toonz/sources/toonz/styleshortcutswitchablepanel.h b/toonz/sources/toonz/styleshortcutswitchablepanel.h index ce689331..3867fc98 100644 --- a/toonz/sources/toonz/styleshortcutswitchablepanel.h +++ b/toonz/sources/toonz/styleshortcutswitchablepanel.h @@ -26,6 +26,8 @@ public: TDockWidget::Orientation orientation = TDockWidget::vertical) : TPanel(parent, flags, orientation) {} + static void onKeyPress(QKeyEvent *event); + protected: void keyPressEvent(QKeyEvent *event) override; void showEvent(QShowEvent *) override; From bd80672d2545843d11f875af616db82e3ffadca9 Mon Sep 17 00:00:00 2001 From: shun-iwasawa Date: Fri, 26 Mar 2021 18:24:13 +0900 Subject: [PATCH 19/24] fix windows audio recording --- toonz/sources/toonz/audiorecordingpopup.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/toonz/sources/toonz/audiorecordingpopup.cpp b/toonz/sources/toonz/audiorecordingpopup.cpp index ef09761c..b8667b4f 100644 --- a/toonz/sources/toonz/audiorecordingpopup.cpp +++ b/toonz/sources/toonz/audiorecordingpopup.cpp @@ -175,11 +175,11 @@ AudioRecordingPopup::AudioRecordingPopup() m_probe->setSource(m_audioRecorder); QAudioEncoderSettings audioSettings; audioSettings.setCodec("audio/PCM"); -#ifdef MACOSX - audioSettings.setSampleRate(-1); - #else - audioSettings.setSampleRate(44100); - #endif + // setting the sample rate to some value (like 44100) + // may cause divide-by-zero crash in QAudioDeviceInfo::nearestFormat() + // so here we set the value to -1, as the documentation says; + // "A value of -1 indicates the encoder should make an optimal choice" + audioSettings.setSampleRate(-1); audioSettings.setChannelCount(1); audioSettings.setBitRate(16); audioSettings.setEncodingMode(QMultimedia::ConstantBitRateEncoding); From 4cb2f6fd4039086fe6e0ba85493c57c0020a7343 Mon Sep 17 00:00:00 2001 From: shun-iwasawa Date: Wed, 17 Mar 2021 18:22:05 +0900 Subject: [PATCH 20/24] fix removing entire cells in the column --- toonz/sources/toonz/cellselection.cpp | 270 +++++++++----------------- toonz/sources/toonz/columncommand.cpp | 19 +- toonz/sources/toonz/columncommand.h | 2 +- toonz/sources/toonzqt/treemodel.cpp | 9 +- 4 files changed, 114 insertions(+), 186 deletions(-) diff --git a/toonz/sources/toonz/cellselection.cpp b/toonz/sources/toonz/cellselection.cpp index 75bd8abe..b9dc7015 100644 --- a/toonz/sources/toonz/cellselection.cpp +++ b/toonz/sources/toonz/cellselection.cpp @@ -14,6 +14,7 @@ #include "tapp.h" #include "xsheetviewer.h" #include "levelcommand.h" +#include "columncommand.h" // TnzTools includes #include "tools/toolutils.h" @@ -120,8 +121,13 @@ void deleteCellsWithoutUndo(int &r0, int &c0, int &r1, int &c1) { TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); int c; for (c = c0; c <= c1; c++) { + if (xsh->isColumnEmpty(c)) continue; xsh->clearCells(r0, c, r1 - r0 + 1); - TXshColumn *column = xsh->getColumn(c); + // when the column becomes empty after deletion, + // ColumnCmd::DeleteColumn() will take care of column related operations + // like disconnecting from fx nodes etc. + /* + TXshColumn* column = xsh->getColumn(c); if (column && column->isEmpty()) { column->resetColumnProperties(); TFx *fx = column->getFx(); @@ -135,8 +141,8 @@ void deleteCellsWithoutUndo(int &r0, int &c0, int &r1, int &c1) { xsh->getStageObjectTree()->removeStageObject( TStageObjectId::ColumnId(c)); } + */ } - TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); } catch (...) { DVGui::error(QObject::tr("It is not possible to delete the selection.")); } @@ -149,25 +155,52 @@ void cutCellsWithoutUndo(int &r0, int &c0, int &r1, int &c1) { int c; for (c = c0; c <= c1; c++) { xsh->removeCells(r0, c, r1 - r0 + 1); - TXshColumn *column = xsh->getColumn(c); + // when the column becomes empty after deletion, + // ColumnCmd::DeleteColumn() will take care of column related operations + // like disconnecting from fx nodes etc. + /* + TXshColumn* column = xsh->getColumn(c); if (column && column->isEmpty()) { column->resetColumnProperties(); - TFx *fx = column->getFx(); + TFx* fx = column->getFx(); if (!fx) continue; int i; for (i = fx->getOutputConnectionCount() - 1; i >= 0; i--) { - TFxPort *port = fx->getOutputConnection(i); + TFxPort* port = fx->getOutputConnection(i); port->setFx(0); } xsh->getStageObjectTree()->removeStageObject(TStageObjectId::ColumnId(c)); } + */ } // Se la selezione corrente e' TCellSelection svuoto la selezione. TCellSelection *cellSelection = dynamic_cast( TApp::instance()->getCurrentSelection()->getSelection()); if (cellSelection) cellSelection->selectNone(); - TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); +} + +//----------------------------------------------------------------------------- +// check if the operation may remove expression reference as column becomes +// empty and deleted after the operation. return true to continue the operation. + +bool checkColumnRemoval(const int r0, const int c0, const int r1, const int c1, + std::set &removedColIds) { + TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); + // std::set colIndicesToBeRemoved; + for (int c = c0; c <= c1; c++) { + TXshColumnP column = xsh->getColumn(c); + if (!column || column->isEmpty() || column->isLocked()) continue; + int tmp_r0, tmp_r1; + xsh->getCellRange(c, tmp_r0, tmp_r1); + if (r0 <= tmp_r0 && r1 >= tmp_r1) removedColIds.insert(c); + } + + if (removedColIds.empty() || + !Preferences::instance()->isModifyExpressionOnMovingReferencesEnabled()) + return true; + std::set dummy_fxs; + return ColumnCmd::checkExpressionReferences(removedColIds, dummy_fxs, true); } //============================================================================= @@ -239,15 +272,15 @@ public: //============================================================================= // DeleteCellsUndo +// Recovering the column information (such as reconnecting nodes) when +// undoing deletion of entire column will be done by DeleteColumnsUndo which +// will be called in the same undo block. So here we only need to recover the +// cell arrangement. //----------------------------------------------------------------------------- class DeleteCellsUndo final : public TUndo { TCellSelection *m_selection; QMimeData *m_data; - QMap> m_outputConnections; - QMap m_columns; - QMap> m_columnObjChildren; - QMap m_columnObjParents; public: DeleteCellsUndo(TCellSelection *selection, QMimeData *data) : m_data(data) { @@ -256,115 +289,26 @@ public: if (c0 < 0) c0 = 0; // Ignore camera column m_selection = new TCellSelection(); m_selection->selectCells(r0, c0, r1, c1); - - TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); - int i; - for (i = c0; i <= c1; i++) { - TXshColumn *col = xsh->getColumn(i); - if (!col || col->isEmpty()) continue; - int colr0, colr1; - col->getRange(colr0, colr1); - if (r0 <= colr0 && r1 >= colr1 && !col->getLevelColumn()) { - // la colonna verra' rimossa dall'xsheet - m_columns[i] = col; - col->addRef(); - } - - // Store TStageObject children in case column is emptied and we need to - // restore it - int pegbarsCount = xsh->getStageObjectTree()->getStageObjectCount(); - TStageObjectId id = TStageObjectId::ColumnId(i); - TStageObject *pegbar = xsh->getStageObject(id); - for (int k = 0; k < pegbarsCount; ++k) { - TStageObject *other = xsh->getStageObjectTree()->getStageObject(k); - if (other == pegbar) continue; - - if (other->getParent() == id) { - // other->setParent(pegbar->getParent()); - m_columnObjChildren[id].append(other->getId()); - } - } - - // Store TStageObject parent in case column is emptied and we need to - // restore it - m_columnObjParents[id] = pegbar->getParent(); - - TFx *fx = col->getFx(); - if (!fx) continue; - int j; - QList fxPorts; - for (j = 0; j < fx->getOutputConnectionCount(); j++) - fxPorts.append(fx->getOutputConnection(j)); - if (fxPorts.isEmpty()) continue; - m_outputConnections[i] = fxPorts; - } } - ~DeleteCellsUndo() { - delete m_selection; - QMap::iterator it; - for (it = m_columns.begin(); it != m_columns.end(); it++) - it.value()->release(); - } + ~DeleteCellsUndo() { delete m_selection; } void undo() const override { TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); - // devo rimettere le colonne che ho rimosso dall'xsheet - QMap::const_iterator colIt; - for (colIt = m_columns.begin(); colIt != m_columns.end(); colIt++) { - int index = colIt.key(); - TXshColumn *column = colIt.value(); - xsh->removeColumn(index); - xsh->insertColumn(index, column); - } - int r0, c0, r1, c1; m_selection->getSelectedCells(r0, c0, r1, c1); - QMap>::const_iterator it; - for (it = m_outputConnections.begin(); it != m_outputConnections.end(); - it++) { - TXshColumn *col = xsh->getColumn(it.key()); - QList fxPorts = it.value(); - int i; - for (i = 0; i < fxPorts.size(); i++) fxPorts[i]->setFx(col->getFx()); - } - - // Restore TStageObject parent - QMap::const_iterator it2; - for (it2 = m_columnObjParents.begin(); it2 != m_columnObjParents.end(); - it2++) { // Parents - TStageObject *obj = xsh->getStageObject(it2.key()); - if (obj) { - obj->setParent(it2.value()); - } - } - - // Restore TStageObject children - QMap>::const_iterator it3; - for (it3 = m_columnObjChildren.begin(); it3 != m_columnObjChildren.end(); - it3++) { // Children - QList children = it3.value(); - int i; - for (i = 0; i < children.size(); i++) { - TStageObject *child = xsh->getStageObject(children[i]); - if (child) { - child->setParent(it3.key()); - } - } - } const TCellData *cellData = dynamic_cast(m_data); pasteCellsWithoutUndo(cellData, r0, c0, r1, c1, false, false); - TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); - TApp::instance()->getCurrentObject()->notifyObjectIdSwitched(); } void redo() const override { int r0, c0, r1, c1; m_selection->getSelectedCells(r0, c0, r1, c1); deleteCellsWithoutUndo(r0, c0, r1, c1); + TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); } int getSize() const override { return sizeof(*this); } @@ -375,14 +319,14 @@ public: //============================================================================= // CutCellsUndo +// Just like DeleteCellsUndo, recovering the column information (such as +// reconnecting nodes) when undoing deletion of entire column will be done +// by DeleteColumnsUndo which will be called in the same undo block. //----------------------------------------------------------------------------- class CutCellsUndo final : public TUndo { TCellSelection *m_selection; TCellData *m_data; - QMap> m_outputConnections; - QMap> m_columnObjChildren; - QMap m_columnObjParents; public: CutCellsUndo(TCellSelection *selection) : m_data() { @@ -391,41 +335,6 @@ public: if (c0 < 0) c0 = 0; // Ignore camera column m_selection = new TCellSelection(); m_selection->selectCells(r0, c0, r1, c1); - - TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); - int i; - for (i = c0; i <= c1; i++) { - TXshColumn *col = xsh->getColumn(i); - if (!col || col->isEmpty()) continue; - - // Store TStageObject children in case column is emptied and we need to - // restore it - int pegbarsCount = xsh->getStageObjectTree()->getStageObjectCount(); - TStageObjectId id = TStageObjectId::ColumnId(i); - TStageObject *pegbar = xsh->getStageObject(id); - for (int k = 0; k < pegbarsCount; ++k) { - TStageObject *other = xsh->getStageObjectTree()->getStageObject(k); - if (other == pegbar) continue; - - if (other->getParent() == id) { - // other->setParent(pegbar->getParent()); - m_columnObjChildren[id].append(other->getId()); - } - } - - // Store TStageObject parent in case column is emptied and we need to - // restore it - m_columnObjParents[id] = pegbar->getParent(); - - TFx *fx = col->getFx(); - if (!fx) continue; - int j; - QList fxPorts; - for (j = 0; j < fx->getOutputConnectionCount(); j++) - fxPorts.append(fx->getOutputConnection(j)); - if (fxPorts.isEmpty()) continue; - m_outputConnections[i] = fxPorts; - } } void setCurrentData(int r0, int c0, int r1, int c1) { @@ -443,43 +352,8 @@ public: int r0, c0, r1, c1; m_selection->getSelectedCells(r0, c0, r1, c1); - TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); - QMap>::const_iterator it; - for (it = m_outputConnections.begin(); it != m_outputConnections.end(); - it++) { - TXshColumn *col = xsh->getColumn(it.key()); - QList fxPorts = it.value(); - int i; - for (i = 0; i < fxPorts.size(); i++) fxPorts[i]->setFx(col->getFx()); - } - - // Restore TStageObject parent - QMap::const_iterator it2; - for (it2 = m_columnObjParents.begin(); it2 != m_columnObjParents.end(); - it2++) { // Parents - TStageObject *obj = xsh->getStageObject(it2.key()); - if (obj) { - obj->setParent(it2.value()); - } - } - - // Restore TStageObject children - QMap>::const_iterator it3; - for (it3 = m_columnObjChildren.begin(); it3 != m_columnObjChildren.end(); - it3++) { // Children - QList children = it3.value(); - int i; - for (i = 0; i < children.size(); i++) { - TStageObject *child = xsh->getStageObject(children[i]); - if (child) { - child->setParent(it3.key()); - } - } - } - pasteCellsWithoutUndo(m_data, r0, c0, r1, c1, true); TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); - TApp::instance()->getCurrentObject()->notifyObjectIdSwitched(); } void redo() const override { @@ -491,6 +365,7 @@ public: cutCellsWithoutUndo(r0, c0, r1, c1); clipboard->setMimeData(currentData, QClipboard::Clipboard); + TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); } int getSize() const override { return sizeof(*this); } @@ -2605,12 +2480,36 @@ void TCellSelection::deleteCells() { TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); // if all the selected cells are already empty, then do nothing if (xsh->isRectEmpty(CellPosition(r0, c0), CellPosition(r1, c1))) return; + + std::set removedColIds; + // check if the operation may remove expression reference as column becomes + // empty and deleted after the operation. + if (!checkColumnRemoval(r0, c0, r1, c1, removedColIds)) return; + TCellData *data = new TCellData(); data->setCells(xsh, r0, c0, r1, c1); + + // clear empty column + if (!removedColIds.empty()) { + TUndoManager::manager()->beginBlock(); + // remove, then insert empty column + for (auto colId : removedColIds) { + ColumnCmd::deleteColumn(colId, true); + ColumnCmd::insertEmptyColumn(colId); + } + } + DeleteCellsUndo *undo = new DeleteCellsUndo(new TCellSelection(m_range), data); deleteCellsWithoutUndo(r0, c0, r1, c1); + + TUndoManager::manager()->add(undo); + + if (!removedColIds.empty()) { + TUndoManager::manager()->endBlock(); + } + // emit selectionChanged() signal so that the rename field will update // accordingly if (Preferences::instance()->isUseArrowKeyToShiftCellSelectionEnabled()) @@ -2618,8 +2517,8 @@ void TCellSelection::deleteCells() { else selectNone(); - TUndoManager::manager()->add(undo); TApp::instance()->getCurrentScene()->setDirtyFlag(true); + TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); } //----------------------------------------------------------------------------- @@ -2637,11 +2536,32 @@ void TCellSelection::cutCells(bool withoutCopy) { getSelectedCells(r0, c0, r1, c1); if (c0 < 0) c0 = 0; // Ignore camera column + std::set removedColIds; + // check if the operation may remove expression reference as column becomes + // empty and deleted after the operation. + if (!checkColumnRemoval(r0, c0, r1, c1, removedColIds)) return; + undo->setCurrentData(r0, c0, r1, c1); if (!withoutCopy) copyCellsWithoutUndo(r0, c0, r1, c1); + + // clear empty column + if (!removedColIds.empty()) { + TUndoManager::manager()->beginBlock(); + // remove, then insert empty column + for (auto colId : removedColIds) { + ColumnCmd::deleteColumn(colId, true); + ColumnCmd::insertEmptyColumn(colId); + } + } + cutCellsWithoutUndo(r0, c0, r1, c1); TUndoManager::manager()->add(undo); + + if (!removedColIds.empty()) { + TUndoManager::manager()->endBlock(); + } + // cutCellsWithoutUndo will clear the selection, so select cells again if (Preferences::instance()->isUseArrowKeyToShiftCellSelectionEnabled()) { selectCells(r0, c0, r1, c1); diff --git a/toonz/sources/toonz/columncommand.cpp b/toonz/sources/toonz/columncommand.cpp index c0e7f952..504fb98a 100644 --- a/toonz/sources/toonz/columncommand.cpp +++ b/toonz/sources/toonz/columncommand.cpp @@ -539,10 +539,13 @@ class DeleteColumnsUndo final : public TUndo { QMap m_columnObjParents; mutable std::unique_ptr m_data; + bool m_onlyColumns; public: - DeleteColumnsUndo(const std::set &indices) - : m_indices(indices), m_data(new StageObjectsData) { + DeleteColumnsUndo(const std::set &indices, bool onlyColumns) + : m_indices(indices) + , m_data(new StageObjectsData) + , m_onlyColumns(onlyColumns) { TApp *app = TApp::instance(); TXsheet *xsh = app->getCurrentXsheet()->getXsheet(); @@ -597,7 +600,7 @@ public: m_data->storeColumnFxs(m_indices, xsh, 0); std::set indices = m_indices; - deleteColumnsWithoutUndo(&indices); + deleteColumnsWithoutUndo(&indices, m_onlyColumns); } void undo() const override { @@ -816,8 +819,8 @@ void ColumnCmd::deleteColumns(std::set &indices, bool onlyColumns, indices.erase(-1); // Ignore camera column if (indices.empty()) return; - if (!withoutUndo && !onlyColumns) - TUndoManager::manager()->add(new DeleteColumnsUndo(indices)); + if (!withoutUndo) + TUndoManager::manager()->add(new DeleteColumnsUndo(indices, onlyColumns)); deleteColumnsWithoutUndo(&indices, onlyColumns); TApp::instance()->getCurrentScene()->setDirtyFlag(true); @@ -827,10 +830,10 @@ void ColumnCmd::deleteColumns(std::set &indices, bool onlyColumns, // deleteColumn //============================================================================= -void ColumnCmd::deleteColumn(int index) { +void ColumnCmd::deleteColumn(int index, bool onlyColumns) { std::set ii; ii.insert(index); - ColumnCmd::deleteColumns(ii, false, false); + ColumnCmd::deleteColumns(ii, onlyColumns, false); } //============================================================================= @@ -845,7 +848,7 @@ static void cutColumnsWithoutUndo(std::set *indices) { void ColumnCmd::cutColumns(std::set &indices) { if (indices.empty()) return; - TUndoManager::manager()->add(new DeleteColumnsUndo(indices)); + TUndoManager::manager()->add(new DeleteColumnsUndo(indices, false)); cutColumnsWithoutUndo(&indices); TApp::instance()->getCurrentScene()->setDirtyFlag(true); diff --git a/toonz/sources/toonz/columncommand.h b/toonz/sources/toonz/columncommand.h index e41ef011..a0754c56 100644 --- a/toonz/sources/toonz/columncommand.h +++ b/toonz/sources/toonz/columncommand.h @@ -24,7 +24,7 @@ void cutColumns(std::set &indices); //! deleted void deleteColumns(std::set &indices, bool onlyColumns, bool withoutUndo); //! helper function: deletes a single column, with undo -void deleteColumn(int index); +void deleteColumn(int index, bool onlyColumns = false); //! if data==0 then uses clipboard void pasteColumns(std::set &indices, const StageObjectsData *data = 0); //! helper function: copies srcIndex column and pastes it before dstIndex. Does diff --git a/toonz/sources/toonzqt/treemodel.cpp b/toonz/sources/toonzqt/treemodel.cpp index 336bedc7..60c54f59 100644 --- a/toonz/sources/toonzqt/treemodel.cpp +++ b/toonz/sources/toonzqt/treemodel.cpp @@ -185,6 +185,10 @@ void TreeModel::endRefresh() { int i; QList::iterator it; + // comment out as no subclass of TreeModel reimplement removeRows() for now + // and it causes assertion failure on calling beginRemoveRows() when deleting + // the last column in the xsheet + /* for (i = m_itemsToDelete.size() - 1; i >= 0; i--) { int row = m_itemsToDelete[i]->getRow(); Item *parentItem = m_itemsToDelete[i]->getParent(); @@ -192,10 +196,11 @@ void TreeModel::endRefresh() { parentItem ? parentItem->createIndex() : QModelIndex(); beginRemoveRows(parentIndex, row, row); - removeRow(row, parentIndex); // NOTE: This is currently doing NOTHING? (see + removeRows(row, 1, parentIndex); // NOTE: This is currently doing NOTHING? + (see // Qt's manual) endRemoveRows(); - } + }*/ qDeleteAll(m_itemsToDelete); m_itemsToDelete.clear(); From 8358fc99cea2cc9a4b56e724ca6384240512cb86 Mon Sep 17 00:00:00 2001 From: shun-iwasawa Date: Sun, 28 Mar 2021 07:27:03 +0900 Subject: [PATCH 21/24] fix geometric tool / type tool offset --- toonz/sources/tnztools/geometrictool.cpp | 20 ++++++++++++-------- toonz/sources/tnztools/typetool.cpp | 17 ++++++++++++----- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/toonz/sources/tnztools/geometrictool.cpp b/toonz/sources/tnztools/geometrictool.cpp index fb1e413c..82a82833 100644 --- a/toonz/sources/tnztools/geometrictool.cpp +++ b/toonz/sources/tnztools/geometrictool.cpp @@ -1032,19 +1032,23 @@ public: } } + bool preLeftButtonDown() override { + if (getViewer() && getViewer()->getGuidedStrokePickerMode()) return false; + + if (!getApplication()->getCurrentObject()->isSpline()) + // NEEDS to be done even if(m_active), due + // to the HORRIBLE m_frameCreated / m_levelCreated + // mechanism. touchImage() is the ONLY function + // resetting them to false... >_< + m_active = !!touchImage(); + return true; + } + void leftButtonDown(const TPointD &p, const TMouseEvent &e) override { if (getViewer() && getViewer()->getGuidedStrokePickerMode()) { getViewer()->doPickGuideStroke(p); return; } - - /* m_active = getApplication()->getCurrentObject()->isSpline() || - (bool) getImage(true);*/ - if (!getApplication()->getCurrentObject()->isSpline()) - m_active = touchImage(); // NEEDS to be done even if(m_active), due - if (!m_active) // to the HORRIBLE m_frameCreated / m_levelCreated - return; // mechanism. touchImage() is the ONLY function - // resetting them to false... >_< if (m_primitive) m_primitive->leftButtonDown(p, e); invalidate(); } diff --git a/toonz/sources/tnztools/typetool.cpp b/toonz/sources/tnztools/typetool.cpp index d495d254..d62bffc3 100644 --- a/toonz/sources/tnztools/typetool.cpp +++ b/toonz/sources/tnztools/typetool.cpp @@ -358,6 +358,7 @@ public: void setCursorIndexFromPoint(TPointD point); void mouseMove(const TPointD &pos, const TMouseEvent &) override; + bool preLeftButtonDown() override; void leftButtonDown(const TPointD &pos, const TMouseEvent &) override; void rightButtonDown(const TPointD &pos, const TMouseEvent &) override; bool keyDown(QKeyEvent *event) override; @@ -1201,6 +1202,16 @@ void TypeTool::mouseMove(const TPointD &pos, const TMouseEvent &) { //--------------------------------------------------------- +bool TypeTool::preLeftButtonDown() { + if (getViewer() && getViewer()->getGuidedStrokePickerMode()) return false; + + if (m_validFonts && !m_active) + touchImage(); + return true; +} + +//--------------------------------------------------------- + void TypeTool::leftButtonDown(const TPointD &pos, const TMouseEvent &) { TSelection::setCurrent(0); @@ -1211,11 +1222,7 @@ void TypeTool::leftButtonDown(const TPointD &pos, const TMouseEvent &) { if (!m_validFonts) return; - TImageP img; - if (!m_active) - img = touchImage(); - else - img = getImage(true); + TImageP img = getImage(true); TVectorImageP vi = img; TToonzImageP ti = img; From 79b261ac7adc1dc01a860165db9fbede3ac8a962 Mon Sep 17 00:00:00 2001 From: shun-iwasawa Date: Sun, 28 Mar 2021 17:34:35 +0900 Subject: [PATCH 22/24] fix arc/multiarc start point offset and undo --- toonz/sources/tnztools/geometrictool.cpp | 35 ++++++++++++++++++++---- toonz/sources/tnztools/typetool.cpp | 7 ++--- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/toonz/sources/tnztools/geometrictool.cpp b/toonz/sources/tnztools/geometrictool.cpp index 82a82833..25cadb74 100644 --- a/toonz/sources/tnztools/geometrictool.cpp +++ b/toonz/sources/tnztools/geometrictool.cpp @@ -567,6 +567,7 @@ public: bool getSmooth() { return m_param->m_smooth.getValue(); } virtual TStroke *makeStroke() const = 0; + virtual bool canTouchImageOnPreLeftClick() { return true; } }; //----------------------------------------------------------------------------- @@ -739,6 +740,9 @@ public: void onImageChanged() override; void setVertexes(const std::vector &vertex) { m_vertex = vertex; }; void setSpeedMoved(bool speedMoved) { m_speedMoved = speedMoved; }; + + // Only execute touchImage when clicking the first point of the polyline + bool canTouchImageOnPreLeftClick() override { return m_vertex.empty(); } }; //----------------------------------------------------------------------------- @@ -849,6 +853,7 @@ public: TStroke *makeStroke() const override; void draw() override; + void leftButtonDown(const TPointD &pos, const TMouseEvent &) override; void leftButtonUp(const TPointD &pos, const TMouseEvent &) override; void mouseMove(const TPointD &pos, const TMouseEvent &e) override; void leftButtonDoubleClick(const TPointD &, const TMouseEvent &e) override; @@ -879,6 +884,9 @@ public: void decreaseUndo() { --m_undoCount; } void increaseUndo() { ++m_undoCount; } + + // Only execute touchImage when clicking the first point of the multi arc + bool canTouchImageOnPreLeftClick() override { return m_clickNumber == 0; } }; //----------------------------------------------------------------------------- @@ -1034,13 +1042,17 @@ public: bool preLeftButtonDown() override { if (getViewer() && getViewer()->getGuidedStrokePickerMode()) return false; + if (getApplication()->getCurrentObject()->isSpline()) return true; - if (!getApplication()->getCurrentObject()->isSpline()) - // NEEDS to be done even if(m_active), due - // to the HORRIBLE m_frameCreated / m_levelCreated - // mechanism. touchImage() is the ONLY function - // resetting them to false... >_< - m_active = !!touchImage(); + // in the halfway through the drawing of Polyline / MultiArc primitive, OT + // should not call touchImage or the m_frameCreated / m_levelCreated flags + // will be reset. + if (m_primitive && !m_primitive->canTouchImageOnPreLeftClick()) return true; + // NEEDS to be done even if(m_active), due + // to the HORRIBLE m_frameCreated / m_levelCreated + // mechanism. touchImage() is the ONLY function + // resetting them to false... >_< + m_active = !!touchImage(); return true; } @@ -2401,6 +2413,17 @@ TStroke *MultiArcPrimitive::makeStroke() const { //----------------------------------------------------------------------------- +void MultiArcPrimitive::leftButtonDown(const TPointD &pos, + const TMouseEvent &) { + if (m_clickNumber == 0) { + TPointD newPos = calculateSnap(pos); + newPos = checkGuideSnapping(pos); + m_startPoint = newPos; + } +} + +//----------------------------------------------------------------------------- + void MultiArcPrimitive::leftButtonUp(const TPointD &pos, const TMouseEvent &) { TTool::Application *app = TTool::getApplication(); if (!app) return; diff --git a/toonz/sources/tnztools/typetool.cpp b/toonz/sources/tnztools/typetool.cpp index d62bffc3..490418fc 100644 --- a/toonz/sources/tnztools/typetool.cpp +++ b/toonz/sources/tnztools/typetool.cpp @@ -1205,8 +1205,7 @@ void TypeTool::mouseMove(const TPointD &pos, const TMouseEvent &) { bool TypeTool::preLeftButtonDown() { if (getViewer() && getViewer()->getGuidedStrokePickerMode()) return false; - if (m_validFonts && !m_active) - touchImage(); + if (m_validFonts && !m_active) touchImage(); return true; } @@ -1222,7 +1221,7 @@ void TypeTool::leftButtonDown(const TPointD &pos, const TMouseEvent &) { if (!m_validFonts) return; - TImageP img = getImage(true); + TImageP img = getImage(true); TVectorImageP vi = img; TToonzImageP ti = img; @@ -1615,7 +1614,7 @@ bool TypeTool::keyDown(QKeyEvent *event) { invalidate(); break; - /////////////////// end cursors + /////////////////// end cursors case Qt::Key_Escape: resetInputMethod(); From 7312812d83c24de1323b7a57108dd0c51e9d210b Mon Sep 17 00:00:00 2001 From: manongjohn Date: Sun, 28 Mar 2021 22:11:27 -0400 Subject: [PATCH 23/24] Fix OT patch 3828 (geometric tool offset) --- toonz/sources/tnztools/geometrictool.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/toonz/sources/tnztools/geometrictool.cpp b/toonz/sources/tnztools/geometrictool.cpp index 25cadb74..61d70d82 100644 --- a/toonz/sources/tnztools/geometrictool.cpp +++ b/toonz/sources/tnztools/geometrictool.cpp @@ -853,7 +853,7 @@ public: TStroke *makeStroke() const override; void draw() override; - void leftButtonDown(const TPointD &pos, const TMouseEvent &) override; + void leftButtonDown(const TPointD &pos, const TMouseEvent &e) override; void leftButtonUp(const TPointD &pos, const TMouseEvent &) override; void mouseMove(const TPointD &pos, const TMouseEvent &e) override; void leftButtonDoubleClick(const TPointD &, const TMouseEvent &e) override; @@ -2414,10 +2414,10 @@ TStroke *MultiArcPrimitive::makeStroke() const { //----------------------------------------------------------------------------- void MultiArcPrimitive::leftButtonDown(const TPointD &pos, - const TMouseEvent &) { + const TMouseEvent &e) { if (m_clickNumber == 0) { - TPointD newPos = calculateSnap(pos); - newPos = checkGuideSnapping(pos); + TPointD newPos = calculateSnap(pos, e); + newPos = checkGuideSnapping(pos, e); m_startPoint = newPos; } } From 75b62139db718b5adeb066ffa622fb9f0b149092 Mon Sep 17 00:00:00 2001 From: Kite Date: Tue, 23 Mar 2021 18:21:46 -0700 Subject: [PATCH 24/24] Fix Hdpi Icons --- toonz/sources/include/toonzqt/gutil.h | 9 +- toonz/sources/toonz/pane.cpp | 41 ++-- toonz/sources/toonz/xshnoteviewer.cpp | 17 +- toonz/sources/toonzqt/gutil.cpp | 268 +++++++++++++------------- 4 files changed, 153 insertions(+), 182 deletions(-) diff --git a/toonz/sources/include/toonzqt/gutil.h b/toonz/sources/include/toonzqt/gutil.h index a4ac55e1..77084308 100644 --- a/toonz/sources/include/toonzqt/gutil.h +++ b/toonz/sources/include/toonzqt/gutil.h @@ -108,15 +108,14 @@ int DVAPI getDevPixRatio(); //----------------------------------------------------------------------------- -QPixmap DVAPI setOpacity(QPixmap pixmap, const qreal &opacity = 0.8); +QPixmap DVAPI compositePixmap(QPixmap pixmap, const qreal &opacity = 0.8, + const QSize &size = QSize(), + const int leftAdj = 0, const int topAdj = 0, + QColor bgColor = Qt::transparent); QPixmap DVAPI recolorPixmap( QPixmap pixmap, QColor color = Preferences::instance()->getIconTheme() ? Qt::black : Qt::white); -QPixmap DVAPI compositePixmap(QPixmap pixmap, qreal opacity, - int canvasWidth = 20, int canvasHeight = 20, - int iconWidth = 16, int iconHeight = 16, - int offset = 0); QIcon DVAPI createQIcon(const char *iconSVGName, bool useFullOpacity = false); QIcon DVAPI createQIconPNG(const char *iconPNGName); QIcon DVAPI createQIconOnOffPNG(const char *iconPNGName, bool withOver = true); diff --git a/toonz/sources/toonz/pane.cpp b/toonz/sources/toonz/pane.cpp index dbf42a86..a7206b3c 100644 --- a/toonz/sources/toonz/pane.cpp +++ b/toonz/sources/toonz/pane.cpp @@ -263,34 +263,23 @@ void TPanelTitleBarButton::setPressed(bool pressed) { //----------------------------------------------------------------------------- void TPanelTitleBarButton::paintEvent(QPaintEvent *event) { + // Set unique pressed colors if filename contains the following words: + QColor bgColor = getPressedColor(); + if (m_standardPixmapName.contains("freeze", Qt::CaseInsensitive)) + bgColor = getFreezeColor(); + if (m_standardPixmapName.contains("preview", Qt::CaseInsensitive)) + bgColor = getPreviewColor(); + + QPixmap panePixmap = recolorPixmap(svgToPixmap(m_standardPixmapName)); + QPixmap panePixmapOff = compositePixmap(panePixmap, 0.8); + QPixmap panePixmapOver = + compositePixmap(panePixmap, 1, QSize(), 0, 0, getOverColor()); + QPixmap panePixmapOn = compositePixmap(panePixmap, 1, QSize(), 0, 0, bgColor); + QPainter painter(this); - - // Create color states for the button - QPixmap normalPixmap(m_standardPixmap.size()); - QPixmap onPixmap(m_standardPixmap.size()); - QPixmap overPixmap(m_standardPixmap.size()); - normalPixmap.fill(Qt::transparent); - onPixmap.fill(QColor(getPressedColor())); - overPixmap.fill(QColor(getOverColor())); - - // Set unique 'pressed' colors if filename contains... - if (m_standardPixmapName.contains("freeze", Qt::CaseInsensitive)) { - onPixmap.fill(QColor(getFreezeColor())); - } - if (m_standardPixmapName.contains("preview", Qt::CaseInsensitive)) { - onPixmap.fill(QColor(getPreviewColor())); - } - - // Compose the state colors painter.drawPixmap( - 0, 0, m_pressed ? onPixmap : m_rollover ? overPixmap : normalPixmap); - - // Icon - QPixmap panePixmap = recolorPixmap(m_standardPixmap); - QPixmap paneOffPixmap = setOpacity(panePixmap, 0.8); - painter.drawPixmap( - 0, 0, m_pressed ? panePixmap : m_rollover ? panePixmap : paneOffPixmap); - + 0, 0, + m_pressed ? panePixmapOn : m_rollover ? panePixmapOver : panePixmapOff); painter.end(); } diff --git a/toonz/sources/toonz/xshnoteviewer.cpp b/toonz/sources/toonz/xshnoteviewer.cpp index aa1de1d3..c631032d 100644 --- a/toonz/sources/toonz/xshnoteviewer.cpp +++ b/toonz/sources/toonz/xshnoteviewer.cpp @@ -474,15 +474,12 @@ NoteArea::NoteArea(XsheetViewer *parent, Qt::WFlags flags) m_layerHeaderPanel = new LayerHeaderPanel(m_viewer, this); //----- - + // // m_flipOrientationButton->setObjectName("flipOrientationButton"); // m_flipOrientationButton->setFocusPolicy(Qt::FocusPolicy::NoFocus); // m_flipOrientationButton->setFixedSize(QSize(70, 23)); - // m_flipOrientationButton->setIconSize(QSize(40, 20)); - // QIcon flipOrientationIcon; - // flipOrientationIcon.addFile(QString(":Resources/xsheet2timeline.svg"), - // QSize(), QIcon::Normal); - // m_flipOrientationButton->setIcon(flipOrientationIcon); + // m_flipOrientationButton->setIconSize(QSize(20, 20)); + // m_flipOrientationButton->setIcon(createQIcon("toggle_xsheet_orientation")); // m_flipOrientationButton->setToolTip(tr("Toggle Xsheet/Timeline")); m_newLevelButton->setObjectName("ToolbarToolButton"); @@ -646,12 +643,8 @@ void NoteArea::updateButtons() { void NoteArea::onXsheetOrientationChanged(const Orientation *newOrientation) { // m_flipOrientationButton->setText(newOrientation->caption()); - // QIcon flipOrientationIcon; - // QString iconFile = newOrientation->isVerticalTimeline() - // ? QString(":Resources/xsheet2timeline.svg") - // : QString(":Resources/timeline2xsheet.svg"); - // flipOrientationIcon.addFile(iconFile, QSize(), QIcon::Normal); - // m_flipOrientationButton->setIcon(flipOrientationIcon); + // m_flipOrientationButton->setIcon(createQIcon("toggle_xsheet_orientation")); + // m_flipOrientationButton->setIconSize(QSize(20, 20)); removeLayout(); createLayout(); diff --git a/toonz/sources/toonzqt/gutil.cpp b/toonz/sources/toonzqt/gutil.cpp index 21cac699..1e49b1f5 100644 --- a/toonz/sources/toonzqt/gutil.cpp +++ b/toonz/sources/toonzqt/gutil.cpp @@ -222,26 +222,27 @@ QString getIconThemePath(const QString &fileSVGPath) { //----------------------------------------------------------------------------- -QPixmap setOpacity(QPixmap pixmap, const qreal &opacity) { +QPixmap compositePixmap(QPixmap pixmap, const qreal &opacity, const QSize &size, + const int leftAdj, const int topAdj, QColor bgColor) { static int devPixRatio = getDevPixRatio(); - const QSize pixmapSize(pixmap.width() * devPixRatio, - pixmap.height() * devPixRatio); - QPixmap opacityPixmap(pixmapSize); - opacityPixmap.setDevicePixelRatio(devPixRatio); - opacityPixmap.fill(Qt::transparent); + // Sets size of destination pixmap for source to be drawn onto, if size is + // empty use source pixmap size, else use custom size. + QPixmap destination(size.isEmpty() ? pixmap.size() : size * devPixRatio); + destination.setDevicePixelRatio(devPixRatio); + destination.fill(bgColor); if (!pixmap.isNull()) { - QPainter p(&opacityPixmap); - QPixmap normalPixmap = pixmap.scaled(pixmapSize, Qt::KeepAspectRatio); - normalPixmap.setDevicePixelRatio(devPixRatio); + QPainter p(&destination); + pixmap = pixmap.scaled(pixmap.size(), Qt::KeepAspectRatio); + pixmap.setDevicePixelRatio(devPixRatio); p.setBackgroundMode(Qt::TransparentMode); p.setBackground(QBrush(Qt::transparent)); - p.eraseRect(normalPixmap.rect()); + p.eraseRect(pixmap.rect()); p.setOpacity(opacity); - p.drawPixmap(0, 0, normalPixmap); + p.drawPixmap(leftAdj, topAdj, pixmap); } - return opacityPixmap; + return destination; } //----------------------------------------------------------------------------- @@ -266,138 +267,126 @@ QPixmap recolorPixmap(QPixmap pixmap, QColor color) { //----------------------------------------------------------------------------- -QPixmap compositePixmap(QPixmap pixmap, qreal opacity, int canvasWidth, - int canvasHeight, int iconWidth, int iconHeight, - int offset) { - /* Creates a composite pixmap from two pixmaps. The canvas controls the final - * size, whereas pixmap is the image to be composited ontop. You can control - * the position of pixmap by setting an offset (top-left), default is 0. */ - - static int devPixRatio = getDevPixRatio(); - - QPixmap canvas(canvasWidth, canvasHeight); - canvas.fill(Qt::transparent); // set this to a color to debug - QPixmap combined(canvasWidth, canvasHeight); - combined.fill(Qt::transparent); - if (!pixmap.isNull()) { - QPainter painter; - painter.begin(&combined); - QRect canvasRect(0, 0, canvasWidth, canvasHeight); - painter.drawPixmap(canvasRect, canvas); - painter.setOpacity(opacity); - QRect iconRect(offset, offset, iconWidth, iconHeight); - painter.drawPixmap(iconRect, pixmap); - painter.end(); - } - - return combined; -} - -//----------------------------------------------------------------------------- - QIcon createQIcon(const char *iconSVGName, bool useFullOpacity) { static int devPixRatio = getDevPixRatio(); - // get icon size QIcon themeIcon = QIcon::fromTheme(iconSVGName); + + // Get icon dimensions QSize iconSize(0, 0); for (QList sizes = themeIcon.availableSizes(); !sizes.isEmpty(); sizes.removeFirst()) - if (sizes.first().width() > iconSize.width()) iconSize = sizes.first(); + if (sizes.first().width() > iconSize.width()) + iconSize = sizes.first() * devPixRatio; + + // Control lightness of the icons + const qreal activeOpacity = 1; + const qreal baseOpacity = useFullOpacity ? 1 : 0.8; + const qreal disabledOpacity = 0.15; + + // Psuedo state name strings + QString overStr = QString(iconSVGName) + "_over"; + QString onStr = QString(iconSVGName) + "_on"; + + //---------- + + // Base pixmap + QPixmap themeIconPixmap(recolorPixmap(themeIcon.pixmap(iconSize))); + if (!themeIconPixmap.isNull()) { // suppress message + themeIconPixmap.setDevicePixelRatio(devPixRatio); + themeIconPixmap = themeIconPixmap.scaled(iconSize, Qt::KeepAspectRatio, + Qt::SmoothTransformation); + } + + // Over pixmap + QPixmap overPixmap(recolorPixmap(QIcon::fromTheme(overStr).pixmap(iconSize))); + if (!overPixmap.isNull()) { // suppress message + overPixmap.setDevicePixelRatio(devPixRatio); + overPixmap = overPixmap.scaled(iconSize, Qt::KeepAspectRatio, + Qt::SmoothTransformation); + } + + // On pixmap + QPixmap onPixmap(recolorPixmap(QIcon::fromTheme(onStr).pixmap(iconSize))); + if (!onPixmap.isNull()) { // suppress message + onPixmap.setDevicePixelRatio(devPixRatio); + onPixmap = onPixmap.scaled(iconSize, Qt::KeepAspectRatio, + Qt::SmoothTransformation); + } + + //---------- - QString overStr = QString(iconSVGName) + "_over"; - QString onStr = QString(iconSVGName) + "_on"; - QPixmap themeIconPixmap = recolorPixmap(themeIcon.pixmap(iconSize)); - QPixmap overPixmap = - recolorPixmap(QIcon::fromTheme(overStr).pixmap(iconSize)); - QPixmap onPixmap = recolorPixmap(QIcon::fromTheme(onStr).pixmap(iconSize)); QIcon icon; - // build icon - for (int devPixRatio = 1; devPixRatio <= 2; devPixRatio++) { - int iconW = themeIconPixmap.width(); - int iconH = themeIconPixmap.height(); - int canvasW = iconW; - int canvasH = iconH; - int offset = 0; - const qreal normalOpacity = useFullOpacity ? 1 : 0.8; - const qreal disabledOpacity = 0.15; - const qreal onOpacity = 1; + // Base icon + icon.addPixmap(compositePixmap(themeIconPixmap, baseOpacity), QIcon::Normal, + QIcon::Off); + icon.addPixmap(compositePixmap(themeIconPixmap, disabledOpacity), + QIcon::Disabled, QIcon::Off); - // off - icon.addPixmap(compositePixmap(themeIconPixmap, normalOpacity, canvasW, - canvasH, iconW, iconH), - QIcon::Normal, QIcon::Off); - icon.addPixmap(compositePixmap(themeIconPixmap, disabledOpacity, canvasW, - canvasH, iconW, iconH), - QIcon::Disabled); + // Over icon + icon.addPixmap(!overPixmap.isNull() + ? compositePixmap(overPixmap, activeOpacity) + : compositePixmap(themeIconPixmap, activeOpacity), + QIcon::Active); - // over + // On icon + if (!onPixmap.isNull()) { + icon.addPixmap(compositePixmap(onPixmap, activeOpacity), QIcon::Normal, + QIcon::On); + icon.addPixmap(compositePixmap(onPixmap, disabledOpacity), QIcon::Disabled, + QIcon::On); + } else { + icon.addPixmap(compositePixmap(themeIconPixmap, activeOpacity), + QIcon::Normal, QIcon::On); + icon.addPixmap(compositePixmap(themeIconPixmap, disabledOpacity), + QIcon::Disabled, QIcon::On); + } + + //---------- + + // For icons intended for menus that are 16x16 in dimensions, to repurpose + // them for use in toolbars that are set for 20x20 we want to draw them onto a + // 20x20 pixmap so they don't get resized in the GUI, they will be loaded into + // the icon along with the original 16x16 pixmap. + + if (themeIconPixmap.size() == QSize(16 * devPixRatio, 16 * devPixRatio)) { + const QSize drawOnSize(20, 20); + const int x = (drawOnSize.width() - 16) / 2; // left adjust + const int y = (drawOnSize.height() - 16) / 2; // top adjust + + // Base icon icon.addPixmap( - compositePixmap(!overPixmap.isNull() ? overPixmap : themeIconPixmap, - onOpacity, canvasW, canvasH, iconW, iconH), + compositePixmap(themeIconPixmap, baseOpacity, drawOnSize, x, y), + QIcon::Normal, QIcon::Off); + icon.addPixmap( + compositePixmap(themeIconPixmap, disabledOpacity, drawOnSize, x, y), + QIcon::Disabled, QIcon::Off); + + // Over icon + icon.addPixmap( + !overPixmap.isNull() + ? compositePixmap(overPixmap, activeOpacity, drawOnSize, x, y) + : compositePixmap(themeIconPixmap, activeOpacity, drawOnSize, x, y), QIcon::Active); - // on + // On icon if (!onPixmap.isNull()) { - icon.addPixmap( - compositePixmap(onPixmap, onOpacity, canvasW, canvasH, iconW, iconH), - QIcon::Normal, QIcon::On); - icon.addPixmap(compositePixmap(onPixmap, normalOpacity, canvasW, canvasH, - iconW, iconH), - QIcon::Disabled, QIcon::On); - } else { - icon.addPixmap(compositePixmap(themeIconPixmap, onOpacity, canvasW, - canvasH, iconW, iconH), + icon.addPixmap(compositePixmap(onPixmap, activeOpacity, drawOnSize, x, y), QIcon::Normal, QIcon::On); - icon.addPixmap(compositePixmap(themeIconPixmap, disabledOpacity, canvasW, - canvasH, iconW, iconH), - QIcon::Disabled, QIcon::On); - } - - /* If size is 16x16 (suitable for menu) we composite it onto a separate - * 20x20 pixmap so that it is compatible with toolbars, otherwise it will be - * scaled up and blur. You need to add icons to all QIcon modes otherwise it - * will use the original size, which is undesirable. This is equal to having - * two sets loaded into the icon (16x16 and 20x20) and is dynamically used - * depending on iconSize for toolbars. - */ - if (iconSize == (QSize(16, 16))) { - canvasW = 20 * devPixRatio; - canvasH = 20 * devPixRatio; - offset = 2 * devPixRatio; - - // off - icon.addPixmap(compositePixmap(themeIconPixmap, normalOpacity, canvasW, - canvasH, iconW, iconH, offset), - QIcon::Normal, QIcon::Off); - icon.addPixmap(compositePixmap(themeIconPixmap, disabledOpacity, canvasW, - canvasH, iconW, iconH, offset), - QIcon::Disabled); - // over icon.addPixmap( - compositePixmap(!overPixmap.isNull() ? overPixmap : themeIconPixmap, - onOpacity, canvasW, canvasH, iconW, iconH, offset), - QIcon::Active); - - // on - if (!onPixmap.isNull()) { - icon.addPixmap(compositePixmap(onPixmap, onOpacity, canvasW, canvasH, - iconW, iconH, offset), - QIcon::Normal, QIcon::On); - icon.addPixmap(compositePixmap(onPixmap, disabledOpacity, canvasW, - canvasH, iconW, iconH, offset), - QIcon::Disabled, QIcon::On); - } else { - icon.addPixmap(compositePixmap(themeIconPixmap, onOpacity, canvasW, - canvasH, iconW, iconH, offset), - QIcon::Normal, QIcon::On); - icon.addPixmap(compositePixmap(themeIconPixmap, disabledOpacity, - canvasW, canvasH, iconW, iconH, offset), - QIcon::Disabled, QIcon::On); - } + compositePixmap(onPixmap, disabledOpacity, drawOnSize, x, y), + QIcon::Disabled, QIcon::On); + } else { + icon.addPixmap( + compositePixmap(themeIconPixmap, activeOpacity, drawOnSize, x, y), + QIcon::Normal, QIcon::On); + icon.addPixmap( + compositePixmap(themeIconPixmap, disabledOpacity, drawOnSize, x, y), + QIcon::Disabled, QIcon::On); } } + return icon; } @@ -439,9 +428,9 @@ QIcon createQIconOnOffPNG(const char *iconPNGName, bool withOver) { QIcon createTemporaryIconFromName(const char *commandName) { const int visibleIconSize = 20; const int menubarIconSize = 16; - const qreal normalOpacity = 0.8; + const qreal activeOpacity = 1; + const qreal baseOpacity = 0.8; const qreal disabledOpacity = 0.15; - const qreal onOpacity = 1; QString name(commandName); QList iconChar; @@ -495,22 +484,23 @@ QIcon createTemporaryIconFromName(const char *commandName) { painter.end(); + // For menu only icon.addPixmap(transparentPm, QIcon::Normal, QIcon::Off); icon.addPixmap(transparentPm, QIcon::Active); icon.addPixmap(transparentPm, QIcon::Normal, QIcon::On); - icon.addPixmap(transparentPm, QIcon::Disabled); - icon.addPixmap(compositePixmap(pixmap, normalOpacity, pxSize, pxSize, - pixmap.width(), pixmap.height()), - QIcon::Normal, QIcon::Off); - icon.addPixmap(compositePixmap(pixmap, onOpacity, pxSize, pxSize, - pixmap.width(), pixmap.height()), - QIcon::Normal, QIcon::On); - icon.addPixmap(compositePixmap(pixmap, onOpacity, pxSize, pxSize, - pixmap.width(), pixmap.height()), - QIcon::Active); - icon.addPixmap(compositePixmap(pixmap, disabledOpacity, pxSize, pxSize, - pixmap.width(), pixmap.height()), - QIcon::Disabled); + icon.addPixmap(transparentPm, QIcon::Disabled, QIcon::Off); + icon.addPixmap(transparentPm, QIcon::Disabled, QIcon::On); + + // For toolbars + icon.addPixmap(compositePixmap(pixmap, baseOpacity), QIcon::Normal, + QIcon::Off); + icon.addPixmap(compositePixmap(pixmap, disabledOpacity), QIcon::Disabled, + QIcon::Off); + icon.addPixmap(compositePixmap(pixmap, activeOpacity), QIcon::Active); + icon.addPixmap(compositePixmap(pixmap, activeOpacity), QIcon::Normal, + QIcon::On); + icon.addPixmap(compositePixmap(pixmap, disabledOpacity), QIcon::Disabled, + QIcon::On); } return icon; }