diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 591ede24..2511b0de 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,11 +10,11 @@ I will first review the request, then I'll accept it, add comments for rework, o ### Workflow -0. `fork` Tahoma2D to your GitHub account from `turtletooth/tahoma2d`. - - (use the `fork` button at the https://github.com/turtletooth/tahoma2d) +0. `fork` Tahoma2D to your GitHub account from `tahoma2d/tahoma2d`. + - (use the `fork` button at the https://github.com/tahoma2d/tahoma2d) 0. `clone` the repository. - `git clone git@github.com:your-github-account/tahoma2d.git` - - `git remote add upstream https://github.com/turtletooth/tahoma2d.git`, additionally. + - `git remote add upstream https://github.com/tahoma2d/tahoma2d.git`, additionally. 0. modify the codes. - `git checkout -b your-branch-name` - `your-branch-name` is a name of your modifications, for example, @@ -32,7 +32,7 @@ I will first review the request, then I'll accept it, add comments for rework, o ## Bugs -If you find bugs, please report details about them using [issues](https://github.com/turtletooth/tahoma2d/issues). +If you find bugs, please report details about them using [issues](https://github.com/tahoma2d/tahoma2d/issues). Please include information needed to reproduce the bug, including the operating system and information directly relating to the issue. Links to screen captures of what is observed on screen or video of specific steps to produce the problem are very helpful. diff --git a/README.md b/README.md index 226f79ad..801d006d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # Tahoma2D -[![](https://ci.appveyor.com/api/projects/status/mnc3mepksux9kvap/branch/master?svg=true)](https://ci.appveyor.com/project/turtletooth/tahoma2d) -[![](https://travis-ci.com/turtletooth/tahoma2d.svg?branch=master)](https://travis-ci.com/turtletooth/tahoma2d) +[![](https://ci.appveyor.com/api/projects/status/mnc3mepksux9kvap/branch/master?svg=true)](https://ci.appveyor.com/project/tahoma2d/tahoma2d) ## What is Tahoma2D? @@ -16,7 +15,7 @@ Please refer to the Tahoma2D site at . ## Installation -Please download the latest release at . +Please download the latest release at . ## How to Build Locally @@ -31,7 +30,7 @@ Can't develop but still want to help? Help us test individual Pull Requests befo ## Community - To share tips or to troubleshoot, join the [Google Tahoma2D Users forum](hhttps://groups.google.com/g/tahoma2d) -- If you found a bug with the software after troubleshooting, or are a developer, search the [Github issues](https://github.com/turtletooth/tahoma2d/issues) and post there. +- If you found a bug with the software after troubleshooting, or are a developer, search the [Github issues](https://github.com/tahoma2d/tahoma2d/issues) and post there. ## Licensing diff --git a/doc/how_to_build_linux.md b/doc/how_to_build_linux.md index 6f2ddd1b..042e4f72 100644 --- a/doc/how_to_build_linux.md +++ b/doc/how_to_build_linux.md @@ -101,7 +101,7 @@ $ cd .. ### Cloning the GIT Tree ``` -$ git clone https://github.com/turtletooth/tahoma2d +$ git clone https://github.com/tahoma2d/tahoma2d ``` ### Copying the 'stuff' Directory diff --git a/doc/how_to_build_macosx.md b/doc/how_to_build_macosx.md index 217c112f..45f42696 100644 --- a/doc/how_to_build_macosx.md +++ b/doc/how_to_build_macosx.md @@ -62,7 +62,7 @@ $ rm /usr/local/lib/cmake/glew These steps will put the Tahoma2D repository under /Users/yourlogin/Documents. ``` $ cd ~/Documents #or where you want to store the repository# -$ git clone https://github.com/turtletooth/tahoma2d +$ git clone https://github.com/tahoma2d/tahoma2d $ cd tahoma2d $ git lfs pull $ cd thirdparty/boost diff --git a/stuff/doc/LICENSE/LICENSE_ffmpeg_info.txt b/stuff/doc/LICENSE/LICENSE_ffmpeg_info.txt index 944d0ae3..b698bc34 100644 --- a/stuff/doc/LICENSE/LICENSE_ffmpeg_info.txt +++ b/stuff/doc/LICENSE/LICENSE_ffmpeg_info.txt @@ -4,7 +4,7 @@ Tahoma2D does not directly use FFmpeg libraries or code. As of July 2020, Tahoma2D is shipping with FFmpeg 4.3 LGPL version from https://ffmpeg.zeranoe.com/builds/ FFmpeg source code can be found at: -https://github.com/turtletooth/FFmpeg +https://github.com/tahoma2d/FFmpeg or https://github.com/FFmpeg/FFmpeg diff --git a/stuff/doc/LICENSE/LICENSE_tahoma2d.txt b/stuff/doc/LICENSE/LICENSE_tahoma2d.txt deleted file mode 100644 index a3383bd6..00000000 --- a/stuff/doc/LICENSE/LICENSE_tahoma2d.txt +++ /dev/null @@ -1,36 +0,0 @@ -License Agreement For Tahoma2D -[https://github.com/turtletooth/tahoma2d] - -- - - - - - - - - - - - - - - - - -Tahoma2D - -All contributions by Jeremy Bullock: -Copyright (c) 2016 - 2020, Jeremy Bullock -All rights reserved. - -All contributions by DWANGO: -Copyright (c) 2016 - 2020, DWANGO Co., Ltd. -All rights reserved. - -All other contributions: -Copyright (c) 2016 - 2020, the respective contributors. -All rights reserved. - -Each contributor holds copyright over their respective contributions. -The project versioning (Git) records all such contribution source information. - - -LICENSE - -BSD 3-Clause "New" or "Revised" License - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/toonz/cmake/BundleInfo.plist.in b/toonz/cmake/BundleInfo.plist.in index 3fbacfc6..086a93e0 100644 --- a/toonz/cmake/BundleInfo.plist.in +++ b/toonz/cmake/BundleInfo.plist.in @@ -11,7 +11,7 @@ CFBundleIconFile Tahoma2D.icns CFBundleIdentifier - io.github.turtletooth.Tahoma2D + io.github.tahoma2d.Tahoma2D NSCameraUsageDescription Tahoma2D needs access to the camera in order to use Camera Capture NSMicrophoneUsageDescription diff --git a/toonz/sources/common/tparam/tdoublekeyframe.cpp b/toonz/sources/common/tparam/tdoublekeyframe.cpp index 641840ac..3df05e76 100644 --- a/toonz/sources/common/tparam/tdoublekeyframe.cpp +++ b/toonz/sources/common/tparam/tdoublekeyframe.cpp @@ -57,7 +57,7 @@ void TDoubleKeyframe::saveData(TOStream &os) const { // Dirty resolution. Because the degree sign is converted to unexpected // string... if (QString::fromStdWString(L"\u00b0").toStdString() == unitName) - unitName = "\\u00b0"; + unitName = "degrees"; switch (m_type) { case Constant: case Exponential: @@ -157,6 +157,9 @@ void TDoubleKeyframe::loadData(TIStream &is) { break; } if (!is.matchEndTag()) throw TException(tagName + " : missing endtag"); - if (m_unitName == "default") m_unitName = ""; - m_isKeyframe = true; + if (m_unitName == "default") + m_unitName = ""; + else if (m_unitName == "degrees") + m_unitName = "\u00b0"; + m_isKeyframe = true; } diff --git a/toonz/sources/include/toonz/preferences.h b/toonz/sources/include/toonz/preferences.h index e9ae2e46..5dbc89f6 100644 --- a/toonz/sources/include/toonz/preferences.h +++ b/toonz/sources/include/toonz/preferences.h @@ -342,6 +342,9 @@ public: bool useCtrlAltToResizeBrushEnabled() const { return getBoolValue(useCtrlAltToResizeBrush); } + int getTempToolSwitchtimer() const { + return getIntValue(temptoolswitchtimer); + } // Xsheet tab QString getXsheetLayoutPreference() const { diff --git a/toonz/sources/include/toonz/preferencesitemids.h b/toonz/sources/include/toonz/preferencesitemids.h index 99d8abf9..930e2e5a 100644 --- a/toonz/sources/include/toonz/preferencesitemids.h +++ b/toonz/sources/include/toonz/preferencesitemids.h @@ -107,6 +107,7 @@ enum PreferencesItemId { cursorOutlineEnabled, levelBasedToolsDisplay, useCtrlAltToResizeBrush, + temptoolswitchtimer, //---------- // Xsheet diff --git a/toonz/sources/include/toonz/tapplication.h b/toonz/sources/include/toonz/tapplication.h index 0948e3cd..3c358ad5 100644 --- a/toonz/sources/include/toonz/tapplication.h +++ b/toonz/sources/include/toonz/tapplication.h @@ -20,6 +20,7 @@ class TPaletteHandle; class TFxHandle; class PaletteController; class TColorStyle; +class StatusBar; //==================================================== @@ -51,6 +52,7 @@ public: virtual int getCurrentLevelStyleIndex() const = 0; virtual void setCurrentLevelStyleIndex(int index, bool forceUpdate = false) = 0; + virtual void refreshStatusBar() = 0; }; #endif // TAPPLICATION_H diff --git a/toonz/sources/tnztools/geometrictool.cpp b/toonz/sources/tnztools/geometrictool.cpp index 857b0f5d..fb1e413c 100644 --- a/toonz/sources/tnztools/geometrictool.cpp +++ b/toonz/sources/tnztools/geometrictool.cpp @@ -1172,6 +1172,7 @@ public: if (typeCode != m_typeCode) { m_typeCode = typeCode; changeType(typeCode); + TTool::getApplication()->refreshStatusBar(); } } else if (propertyName == m_param.m_edgeCount.getName()) GeometricEdgeCount = m_param.m_edgeCount.getValue(); diff --git a/toonz/sources/tnztools/tool.cpp b/toonz/sources/tnztools/tool.cpp index 2b7051f6..a607ffd3 100644 --- a/toonz/sources/tnztools/tool.cpp +++ b/toonz/sources/tnztools/tool.cpp @@ -301,7 +301,8 @@ TImage *TTool::touchImage() { bool animationSheetEnabled = pref->isAnimationSheetEnabled(); bool isAutoStretchEnabled = pref->isAutoStretchEnabled(); bool isAutoRenumberEnabled = pref->isAutorenumberEnabled(); - bool isCreateInHoldCellsEnabled = pref->isCreationInHoldCellsEnabled(); + bool isCreateInHoldCellsEnabled = + isAutoCreateEnabled && pref->isCreationInHoldCellsEnabled(); TFrameHandle *currentFrame = m_application->getCurrentFrame(); TXshLevelHandle *currentLevel = m_application->getCurrentLevel(); diff --git a/toonz/sources/tnztools/toolhandle.cpp b/toonz/sources/tnztools/toolhandle.cpp index 06ba72ba..72f76ae0 100644 --- a/toonz/sources/tnztools/toolhandle.cpp +++ b/toonz/sources/tnztools/toolhandle.cpp @@ -7,6 +7,7 @@ #include "timage.h" //#include "tapp.h" #include "toonzqt/menubarcommand.h" +#include "toonz/preferences.h" #include #include #include @@ -70,9 +71,10 @@ void ToolHandle::storeTool() { //----------------------------------------------------------------------------- void ToolHandle::restoreTool() { - // qDebug() << m_storedToolTime.elapsed(); + //qDebug() << m_storedToolTime.elapsed(); if (m_storedToolName != m_toolName && m_storedToolName != "" && - m_storedToolTime.elapsed() > 500) { + m_storedToolTime.elapsed() > + Preferences::instance()->getTempToolSwitchtimer()) { setTool(m_storedToolName); } } diff --git a/toonz/sources/toonz/CMakeLists.txt b/toonz/sources/toonz/CMakeLists.txt index da2d4354..128011de 100644 --- a/toonz/sources/toonz/CMakeLists.txt +++ b/toonz/sources/toonz/CMakeLists.txt @@ -446,20 +446,20 @@ endif() if(BUILD_ENV_MSVC) if(WITH_CANON) - set(EXTRA_LIBS ${EXTRA_LIBS} ${CANON_LIB}) - endif() + set(EXTRA_LIBS ${EXTRA_LIBS} ${CANON_LIB}) + endif() - if(WITH_CRASHRPT) - set(EXTRA_LIBS ${EXTRA_LIBS} ${CRASHRPT_LIB}) - endif() + if(WITH_CRASHRPT) + set(EXTRA_LIBS ${EXTRA_LIBS} ${CRASHRPT_LIB}) + endif() - target_link_libraries(Tahoma2D - Qt5::WinMain Qt5::Core Qt5::Gui Qt5::Network Qt5::OpenGL Qt5::Svg Qt5::Xml - Qt5::Script Qt5::Widgets Qt5::PrintSupport Qt5::Multimedia Qt5::SerialPort - ${GL_LIB} ${GLUT_LIB} ${TURBOJPEG_LIB} ${OpenCV_LIBS} ${EXTRA_LIBS} strmiids - tnzcore tnzbase toonzlib colorfx tnzext image sound toonzqt tnztools tnzstdfx tfarm - ) -elseif(BUILD_ENV_APPLE) + target_link_libraries(Tahoma2D + Qt5::WinMain Qt5::Core Qt5::Gui Qt5::Network Qt5::OpenGL Qt5::Svg Qt5::Xml + Qt5::Script Qt5::Widgets Qt5::PrintSupport Qt5::Multimedia Qt5::SerialPort + ${GL_LIB} ${GLUT_LIB} ${TURBOJPEG_LIB} ${OpenCV_LIBS} ${EXTRA_LIBS} strmiids + tnzcore tnzbase toonzlib colorfx tnzext image sound toonzqt tnztools tnzstdfx tfarm + ) +elseif(BUILD_ENV_APPLE AND WITH_CANON) find_library(COCOA_LIB Cocoa) _find_toonz_library(EXTRA_LIBS "tnzcore;tnzbase;toonzlib;colorfx;tnzext;image;sound;toonzqt;tnztools") @@ -467,9 +467,22 @@ elseif(BUILD_ENV_APPLE) # 変なところにライブラリ生成するカスども set(EXTRA_LIBS ${EXTRA_LIBS} "$" "$") - if(WITH_CANON) - set(EXTRA_LIBS ${EXTRA_LIBS} ${CANON_LIB}) - endif() + add_dependencies(Tahoma2D tnzcore tnzbase toonzlib colorfx tnzext image sound toonzqt tnztools tnzstdfx tfarm) + + target_link_libraries(Tahoma2D + Qt5::Core Qt5::Gui Qt5::Network Qt5::OpenGL Qt5::Svg Qt5::Xml + Qt5::Script Qt5::Widgets Qt5::PrintSupport Qt5::Multimedia Qt5::MultimediaWidgets Qt5::SerialPort + ${GL_LIB} ${GLUT_LIB} ${CANON_LIB} ${TURBOJPEG_LIB} ${OpenCV_LIBS} + ${COCOA_LIB} ${EXTRA_LIBS} mousedragfilter + ) + +elseif(BUILD_ENV_APPLE) + find_library(COCOA_LIB Cocoa) + + _find_toonz_library(EXTRA_LIBS "tnzcore;tnzbase;toonzlib;colorfx;tnzext;image;sound;toonzqt;tnztools") + + # 変なところにライブラリ生成するカスども + set(EXTRA_LIBS ${EXTRA_LIBS} "$" "$") add_dependencies(Tahoma2D tnzcore tnzbase toonzlib colorfx tnzext image sound toonzqt tnztools tnzstdfx tfarm) diff --git a/toonz/sources/toonz/Resources/info.txt b/toonz/sources/toonz/Resources/info.txt index 3c451f17..5f666752 100644 --- a/toonz/sources/toonz/Resources/info.txt +++ b/toonz/sources/toonz/Resources/info.txt @@ -1 +1 @@ -Web: https://turtletooth.com/ +Web: https://tahoma2d.org diff --git a/toonz/sources/toonz/cellselection.cpp b/toonz/sources/toonz/cellselection.cpp index 18a55be8..ad1e1c12 100644 --- a/toonz/sources/toonz/cellselection.cpp +++ b/toonz/sources/toonz/cellselection.cpp @@ -131,6 +131,8 @@ void deleteCellsWithoutUndo(int &r0, int &c0, int &r1, int &c1) { port->setFx(0); } } + xsh->getStageObjectTree()->removeStageObject( + TStageObjectId::ColumnId(c)); } } TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); @@ -156,6 +158,7 @@ void cutCellsWithoutUndo(int &r0, int &c0, int &r1, int &c1) { TFxPort *port = fx->getOutputConnection(i); port->setFx(0); } + xsh->getStageObjectTree()->removeStageObject(TStageObjectId::ColumnId(c)); } } @@ -242,6 +245,8 @@ class DeleteCellsUndo final : public TUndo { QMimeData *m_data; QMap> m_outputConnections; QMap m_columns; + QMap> m_columnObjChildren; + QMap m_columnObjParents; public: DeleteCellsUndo(TCellSelection *selection, QMimeData *data) : m_data(data) { @@ -263,6 +268,26 @@ public: 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; @@ -304,10 +329,35 @@ public: 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 { @@ -330,6 +380,8 @@ 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() { @@ -344,6 +396,26 @@ public: 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; @@ -380,8 +452,33 @@ public: 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 { @@ -2613,6 +2710,8 @@ void TCellSelection::createBlankDrawing(int row, int col, bool multiple) { ToolHandle *toolHandle = TApp::instance()->getCurrentTool(); + //----- Going to cheat a little. Use autocreate rules to help create what we + // need // If autocreate disabled, let's turn it on temporarily bool isAutoCreateEnabled = Preferences::instance()->isAutoCreateEnabled(); if (!isAutoCreateEnabled) @@ -2622,6 +2721,7 @@ void TCellSelection::createBlankDrawing(int row, int col, bool multiple) { Preferences::instance()->isCreationInHoldCellsEnabled(); if (!isCreationInHoldCellsEnabled) Preferences::instance()->setValue(EnableCreationInHoldCells, true, false); + //------------------ TImage *img = toolHandle->getTool()->touchImage(); @@ -2629,11 +2729,13 @@ void TCellSelection::createBlankDrawing(int row, int col, bool multiple) { TXshSimpleLevel *sl = cell.getSimpleLevel(); if (!img || !sl) { + //----- Restore previous states of autocreation if (!isAutoCreateEnabled) Preferences::instance()->setValue(EnableAutocreation, false, false); if (!isCreationInHoldCellsEnabled) Preferences::instance()->setValue(EnableCreationInHoldCells, false, false); + //------------------ if (!multiple) DVGui::warning(QObject::tr( "Unable to create a blank drawing on the current column")); @@ -2641,11 +2743,13 @@ void TCellSelection::createBlankDrawing(int row, int col, bool multiple) { } if (!toolHandle->getTool()->m_isFrameCreated) { + //----- Restore previous states of autocreation if (!isAutoCreateEnabled) Preferences::instance()->setValue(EnableAutocreation, false, false); if (!isCreationInHoldCellsEnabled) Preferences::instance()->setValue(EnableCreationInHoldCells, false, false); + //------------------ if (!multiple) DVGui::warning(QObject::tr( "Unable to replace the current drawing with a blank drawing")); @@ -2663,11 +2767,12 @@ void TCellSelection::createBlankDrawing(int row, int col, bool multiple) { IconGenerator::instance()->invalidate(sl, frame); - // Reset back to what these were + //----- Restore previous states of autocreation if (!isAutoCreateEnabled) Preferences::instance()->setValue(EnableAutocreation, false, false); if (!isCreationInHoldCellsEnabled) Preferences::instance()->setValue(EnableCreationInHoldCells, false, false); + //------------------ } //----------------------------------------------------------------------------- @@ -2764,6 +2869,8 @@ void TCellSelection::duplicateFrame(int row, int col, bool multiple) { ToolHandle *toolHandle = TApp::instance()->getCurrentTool(); + //----- Going to cheat a little. Use autocreate rules to help create what we + // need // If autocreate disabled, let's turn it on temporarily bool isAutoCreateEnabled = Preferences::instance()->isAutoCreateEnabled(); if (!isAutoCreateEnabled) @@ -2773,14 +2880,17 @@ void TCellSelection::duplicateFrame(int row, int col, bool multiple) { Preferences::instance()->isCreationInHoldCellsEnabled(); if (!isCreationInHoldCellsEnabled) Preferences::instance()->setValue(EnableCreationInHoldCells, true, false); + //------------------ TImage *img = toolHandle->getTool()->touchImage(); if (!img) { + //----- Restore previous states of autocreation if (!isAutoCreateEnabled) Preferences::instance()->setValue(EnableAutocreation, false, false); if (!isCreationInHoldCellsEnabled) Preferences::instance()->setValue(EnableCreationInHoldCells, false, false); + //------------------ if (!multiple) DVGui::warning( QObject::tr("Unable to duplicate a drawing on the current column")); @@ -2789,11 +2899,13 @@ void TCellSelection::duplicateFrame(int row, int col, bool multiple) { bool frameCreated = toolHandle->getTool()->m_isFrameCreated; if (!frameCreated) { + //----- Restore previous states of autocreation if (!isAutoCreateEnabled) Preferences::instance()->setValue(EnableAutocreation, false, false); if (!isCreationInHoldCellsEnabled) Preferences::instance()->setValue(EnableCreationInHoldCells, false, false); + //------------------ if (!multiple) DVGui::warning( QObject::tr("Unable to replace the current or next drawing with a " @@ -2815,10 +2927,12 @@ void TCellSelection::duplicateFrame(int row, int col, bool multiple) { new DuplicateDrawingUndo(sl, srcFrame, targetFrame); TUndoManager::manager()->add(undo); + //----- Restore previous states of autocreation if (!isAutoCreateEnabled) Preferences::instance()->setValue(EnableAutocreation, false, false); if (!isCreationInHoldCellsEnabled) Preferences::instance()->setValue(EnableCreationInHoldCells, false, false); + //------------------ } //----------------------------------------------------------------------------- diff --git a/toonz/sources/toonz/filmstrip.cpp b/toonz/sources/toonz/filmstrip.cpp index 57e16c86..37f06dde 100644 --- a/toonz/sources/toonz/filmstrip.cpp +++ b/toonz/sources/toonz/filmstrip.cpp @@ -488,9 +488,8 @@ void FilmstripFrames::hideEvent(QHideEvent *) { // if the level strip is floating during shutting down Tahoma2D // it can cause a crash disconnecting from the viewer which was already - // destroyed. Checking the fps is a janky way to ensure the viewer is - // stil relevant. - if (m_viewer && m_viewer->getFPS() > -100) { + // destroyed. + if (m_viewer && m_viewer->isValid()) { disconnect(m_viewer, SIGNAL(onZoomChanged()), this, SLOT(update())); disconnect(m_viewer, SIGNAL(refreshNavi()), this, SLOT(update())); m_viewer = nullptr; diff --git a/toonz/sources/toonz/main.cpp b/toonz/sources/toonz/main.cpp index 029d6673..cf9e0691 100644 --- a/toonz/sources/toonz/main.cpp +++ b/toonz/sources/toonz/main.cpp @@ -328,28 +328,8 @@ int main(int argc, char *argv[]) { argc = 1; } - // Toonz environment - initToonzEnv(argumentPathValues); - -#ifdef WITH_CRASHRPT - CR_INSTALL_INFO pInfo; - memset(&pInfo, 0, sizeof(CR_INSTALL_INFO)); - pInfo.cb = sizeof(CR_INSTALL_INFO); - pInfo.pszAppName = convertToLPCWSTR(TEnv::getApplicationName()); - pInfo.pszAppVersion = convertToLPCWSTR(TEnv::getApplicationVersion()); - TFilePath crashrptCache = - ToonzFolder::getCacheRootFolder() + TFilePath("crashrpt"); - pInfo.pszErrorReportSaveDir = - convertToLPCWSTR(crashrptCache.getQString().toStdString()); - // Install all available exception handlers. - // Don't send reports automaticall, store locally - pInfo.dwFlags |= CR_INST_ALL_POSSIBLE_HANDLERS | CR_INST_DONT_SEND_REPORT; - - crInstall(&pInfo); -#endif - -// Enables high-DPI scaling. This attribute must be set before QApplication is -// constructed. Available from Qt 5.6. + // Enables high-DPI scaling. This attribute must be set before QApplication is + // constructed. Available from Qt 5.6. #if QT_VERSION >= 0x050600 QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif @@ -511,6 +491,26 @@ int main(int argc, char *argv[]) { TBigMemoryManager::instance()->setRunOutOfContiguousMemoryHandler( &toonzRunOutOfContMemHandler); + // Toonz environment + initToonzEnv(argumentPathValues); + +#ifdef WITH_CRASHRPT + CR_INSTALL_INFO pInfo; + memset(&pInfo, 0, sizeof(CR_INSTALL_INFO)); + pInfo.cb = sizeof(CR_INSTALL_INFO); + pInfo.pszAppName = convertToLPCWSTR(TEnv::getApplicationName()); + pInfo.pszAppVersion = convertToLPCWSTR(TEnv::getApplicationVersion()); + TFilePath crashrptCache = + ToonzFolder::getCacheRootFolder() + TFilePath("crashrpt"); + pInfo.pszErrorReportSaveDir = + convertToLPCWSTR(crashrptCache.getQString().toStdString()); + // Install all available exception handlers. + // Don't send reports automaticall, store locally + pInfo.dwFlags |= CR_INST_ALL_POSSIBLE_HANDLERS | CR_INST_DONT_SEND_REPORT; + + crInstall(&pInfo); +#endif + // Initialize thread components TThread::init(); diff --git a/toonz/sources/toonz/mainwindow.cpp b/toonz/sources/toonz/mainwindow.cpp index a229a99d..b78ff54b 100644 --- a/toonz/sources/toonz/mainwindow.cpp +++ b/toonz/sources/toonz/mainwindow.cpp @@ -1195,7 +1195,7 @@ void MainWindow::onOpenReportABug() { int ret = DVGui::MsgBox(DVGui::INFORMATION, str, buttons, 1); if (ret == 1) QDesktopServices::openUrl( - QUrl("https://github.com/turtletooth/tahoma2d/issues")); + QUrl("https://github.com/tahoma2d/tahoma2d/issues")); } //----------------------------------------------------------------------------- @@ -1481,7 +1481,7 @@ void MainWindow::onUpdateCheckerDone(bool error) { if (ret == 1) { // Write the new last date to file QDesktopServices::openUrl(QObject::tr( - "https://github.com/turtletooth/tahoma2d/releases/latest")); + "https://github.com/tahoma2d/tahoma2d/releases/latest")); } } diff --git a/toonz/sources/toonz/outputsettingspopup.cpp b/toonz/sources/toonz/outputsettingspopup.cpp index 069a561e..58b14692 100644 --- a/toonz/sources/toonz/outputsettingspopup.cpp +++ b/toonz/sources/toonz/outputsettingspopup.cpp @@ -1002,7 +1002,9 @@ void OutputSettingsPopup::updateField() { if (!m_isPreviewSettings) { TFilePath path = prop->getPath(); - QString name = QString::fromStdWString(path.getWideName()); + QString name = path.withoutParentDir().getQString(); + name = QString::fromStdString(name.toStdString().substr( + 0, name.length() - path.getDottedType().length())); if (name.isEmpty()) name = QString::fromStdString(scene->getScenePath().getName()); m_saveInFileFld->setPath(toQString(path.getParentDir())); @@ -1204,7 +1206,7 @@ void OutputSettingsPopup::onNameChanged() { if (fp.getWideName() == wname) return; // Already had the right name - fp = fp.withName(wname); + fp = fp.getParentDir() + TFilePath(wname).withType(fp.getType()); prop->setPath(fp); TApp::instance()->getCurrentScene()->setDirtyFlag(true); diff --git a/toonz/sources/toonz/preferencespopup.cpp b/toonz/sources/toonz/preferencespopup.cpp index 72640ebc..5481b696 100644 --- a/toonz/sources/toonz/preferencespopup.cpp +++ b/toonz/sources/toonz/preferencespopup.cpp @@ -1082,6 +1082,8 @@ QString PreferencesPopup::getUIString(PreferencesItemId id) { {cursorOutlineEnabled, tr("Show Cursor Size Outlines")}, {levelBasedToolsDisplay, tr("Toolbar Display Behaviour:")}, {useCtrlAltToResizeBrush, tr("Use Ctrl+Alt to Resize Brush")}, + {temptoolswitchtimer, + tr("Temporary Tool Switch Shortcut Hold Time (ms):")}, // Xsheet {xsheetLayoutPreference, tr("Column Header Layout*:")}, @@ -1656,13 +1658,16 @@ QWidget* PreferencesPopup::createDrawingPage() { insertUI(newLevelSizeToCameraSizeEnabled, lay); insertDualUIs(DefLevelWidth, DefLevelHeight, lay); // insertUI(DefLevelDpi, lay); + QGridLayout* creationLay = insertGroupBox( + tr("Frame Creation Options"), lay); + { + insertUI(NumberingSystem, creationLay, getComboItemList(NumberingSystem)); + insertUI(EnableAutoStretch, creationLay); + insertUI(EnableAutoRenumber, creationLay); + } QGridLayout* autoCreationLay = insertGroupBoxUI(EnableAutocreation, lay); { - insertUI(NumberingSystem, autoCreationLay, - getComboItemList(NumberingSystem)); - insertUI(EnableAutoStretch, autoCreationLay); insertUI(EnableCreationInHoldCells, autoCreationLay); - insertUI(EnableAutoRenumber, autoCreationLay); } insertUI(vectorSnappingTarget, lay, getComboItemList(vectorSnappingTarget)); insertUI(saveUnpaintedInCleanup, lay); @@ -1716,6 +1721,7 @@ QWidget* PreferencesPopup::createToolsPage() { insertUI(levelBasedToolsDisplay, lay, getComboItemList(levelBasedToolsDisplay)); // insertUI(useCtrlAltToResizeBrush, lay); + insertUI(temptoolswitchtimer, lay); lay->setRowStretch(lay->rowCount(), 1); widget->setLayout(lay); diff --git a/toonz/sources/toonz/statusbar.cpp b/toonz/sources/toonz/statusbar.cpp index 51754f52..9480c393 100644 --- a/toonz/sources/toonz/statusbar.cpp +++ b/toonz/sources/toonz/statusbar.cpp @@ -15,12 +15,14 @@ #include "toonz/tobjecthandle.h" #include "toonzqt/tselectionhandle.h" #include "toonzqt/selection.h" -#include "toonz/tstageobjecttree.h" +#include "toonzqt/gutil.h" #include "tools/tool.h" #include "tools/toolhandle.h" +#include "tproperty.h" + #include #include @@ -32,7 +34,7 @@ StatusBar::StatusBar(QWidget* parent) : QStatusBar(parent) { m_infoLabel = new StatusLabel(tr("Info goes here."), this); m_infoLabel->setObjectName("MainWindowPlainLabel"); m_infoLabel->setMinimumWidth(1); - addWidget(m_infoLabel, 0); + addWidget(m_infoLabel, 1); addPermanentWidget(m_currentFrameLabel, 0); TApp* app = TApp::instance(); @@ -53,7 +55,8 @@ StatusBar::StatusBar(QWidget* parent) : QStatusBar(parent) { assert(ret); - makeMap(); + m_infoMap = makeMap(tr(" "), tr(" - "), tr(" - ")); + m_hintMap = makeMap(tr("\n "), tr("\t- "), tr("\t\t- ")); updateInfoText(); } @@ -96,137 +99,273 @@ void StatusBar::updateInfoText() { if (level) { type = level->getType(); } - bool isRaster = false; - bool isVector = false; - bool isSmartRaster = false; - bool isEmpty = false; - std::string namePlus = ""; + bool isRaster = false; + bool isVector = false; + bool isSmartRaster = false; + std::string nameLevel = ""; + std::string nameMode = ""; if (type >= 0) { if (type == TXshLevelType::PLI_XSHLEVEL) { - isVector = true; - namePlus = "Vector"; + isVector = true; + nameLevel = "Vector"; } else if (type == TXshLevelType::TZP_XSHLEVEL) { isSmartRaster = true; - namePlus = "SmartRaster"; + nameLevel = "SmartRaster"; } else if (type == TXshLevelType::OVL_XSHLEVEL) { - isRaster = true; - namePlus = "Raster"; - } else if (type == NO_XSHLEVEL) - isEmpty = true; - } - QString text = ""; - if (m_infoMap.find(name + namePlus) != m_infoMap.end()) { - text += m_infoMap[name + namePlus]; - int i = 0; - i++; - } else if (m_infoMap.find(name) != m_infoMap.end()) { - text += m_infoMap[name]; - int i = 0; - i++; + isRaster = true; + nameLevel = "Raster"; + } } + if (name == "T_Geometric") { + TPropertyGroup* props = tool->getProperties(0); + nameMode = props->getProperty("Shape:")->getValueAsString(); + } + + QString text = ""; + if (m_infoMap.find(name + nameLevel + nameMode) != m_infoMap.end()) + text += m_infoMap[name + nameLevel + nameMode]; + else if (m_infoMap.find(name + nameLevel) != m_infoMap.end()) + text += m_infoMap[name + nameLevel]; + else if (m_infoMap.find(name + nameMode) != m_infoMap.end()) + text += m_infoMap[name + nameMode]; + else if (m_infoMap.find(name) != m_infoMap.end()) + text += m_infoMap[name]; + + QString hintText = ""; + if (m_hintMap.find(name + nameLevel + nameMode) != m_hintMap.end()) + hintText += m_hintMap[name + nameLevel + nameMode]; + else if (m_hintMap.find(name + nameLevel) != m_hintMap.end()) + hintText += m_hintMap[name + nameLevel]; + else if (m_hintMap.find(name + nameMode) != m_hintMap.end()) + hintText += m_hintMap[name + nameMode]; + else if (m_hintMap.find(name) != m_hintMap.end()) + hintText += m_hintMap[name]; + + m_infoLabel->setToolTip(hintText); m_infoLabel->setText(text); } //----------------------------------------------------------------------------- +QString trModKey(QString key) { +#ifdef MACOSX + // Convert Windows key modifier to macOS modifier + if (key == "Ctrl") // Command + return QString::fromStdWString(L"\u2318"); + else if (key == "Shift") + return QString::fromStdWString(L"\u21e7"); + else if (key == "Alt") + return QString::fromStdWString(L"\u2325"); +// else if (key == "???") // Control +// return QString::fromStdWString(L"\u2303"); +#endif -void StatusBar::makeMap() { - QString spacer = " "; - // tools - m_infoMap.insert({"T_Hand", "Hand Tool: Pans the workspace"}); - m_infoMap.insert( - {"T_Selection", - "Selection Tool: Select parts of your image to transform it."}); - m_infoMap.insert({"T_Edit", - "Animate Tool: Modifies the position, rotation and size of " - "the current column"}); - m_infoMap.insert({"T_Brush", "Brush Tool: Draws in the work area freehand"}); - m_infoMap.insert( - {"T_BrushVector", "Brush Tool: Draws in the work area freehand" + spacer + - "Shift - Straight Lines" + spacer + -#ifdef MACOSX - "Cmd - Straight Lines Snapped to Angles" + spacer + - "Cmd + Opt - Add / Remove Vanishing Point" + - spacer + "Opt - Draw to Vanishing Point" + spacer + - "Hold Cmd + Shift - Toggle Snapping"}); -#else - "Control - Straight Lines Snapped to Angles" + - spacer + - "Ctrl + Alt - Add / Remove Vanishing Point" + - spacer + "Alt - Draw to Vanishing Point" + spacer + - "Hold Ctrl + Shift - Toggle Snapping"}); -#endif - m_infoMap.insert({"T_BrushSmartRaster", - "Brush Tool: Draws in the work area freehand" + spacer + - "Shift - Straight Lines" + spacer + -#ifdef MACOSX - "Cmd - Straight Lines Snapped to Angles" + spacer + - "Cmd + Opt - Add / Remove Vanishing Point" + spacer + - "Opt - Draw to Vanishing Point"}); -#else - "Control - Straight Lines Snapped to Angles" + spacer + - "Ctrl + Alt - Add / Remove Vanishing Point" + spacer + - "Alt - Draw to Vanishing Point"}); -#endif - m_infoMap.insert( - {"T_BrushRaster", "Brush Tool: Draws in the work area freehand" + spacer + - "Shift - Straight Lines" + spacer + -#ifdef MACOSX - "Cmd - Straight Lines Snapped to Angles" + spacer + - "Cmd + Opt - Add / Remove Vanishing Point" + - spacer + "Opt - Draw to Vanishing Point"}); -#else - "Control - Straight Lines Snapped to Angles" + - spacer + - "Ctrl + Alt - Add / Remove Vanishing Point" + - spacer + "Alt - Draw to Vanishing Point"}); -#endif - m_infoMap.insert({"T_Geometric", "Geometry Tool: Draws geometric shapes"}); - m_infoMap.insert( - {"T_GeometricVector", "Geometry Tool: Draws geometric shapes" + spacer + -#ifdef MACOSX - "Hold Cmd + Shift - Toggle Snapping"}); -#else - "Hold Ctrl + Shift - Toggle Snapping"}); -#endif - m_infoMap.insert({"T_Type", "Type Tool: Adds text"}); - m_infoMap.insert( - {"T_PaintBrush", - "Smart Raster Painter: Paints areas in Smart Raster leves"}); - m_infoMap.insert( - {"T_Fill", "Fill Tool: Fills drawing areas with the current style"}); - m_infoMap.insert({"T_Eraser", "Eraser: Erases lines and areas"}); - m_infoMap.insert( - {"T_Tape", "Tape Tool: Closes gaps in raster, joins edges in vector"}); - m_infoMap.insert( - {"T_StylePicker", "Style Picker: Selects style on current drawing"}); - m_infoMap.insert( - {"T_RGBPicker", - "RGB Picker: Picks color on screen and applies to current style"}); - m_infoMap.insert({"T_ControlPointEditor", - "Control Point Editor: Modifies vector lines by editing " - "its control points"}); - m_infoMap.insert({"T_Pinch", "Pinch Tool: Pulls vector drawings"}); - m_infoMap.insert({"T_Pump", "Pump Tool: Changes vector thickness"}); - m_infoMap.insert({"T_Magnet", "Magnet Tool: Deforms vector lines"}); - m_infoMap.insert( - {"T_Bender", "Bend Tool: Bends vector shapes around the first click"}); - m_infoMap.insert({"T_Iron", "Iron Tool: Smooths vector lines"}); - m_infoMap.insert({"T_Cutter", "Cutter Tool: Splits vector lines"}); - m_infoMap.insert({"T_Hook", ""}); - m_infoMap.insert({"T_Skeleton", - "Skeleton Tool: Allows to build a skeleton and animate in " - "a cut-out workflow"}); - m_infoMap.insert( - {"T_Tracker", - "Tracker: Tracks specific regions in a sequence of images"}); - m_infoMap.insert({"T_Plastic", - "Plastic Tool: Builds a mesh that allows to deform and " - "animate a level"}); - m_infoMap.insert({"T_Zoom", "Zoom Tool: Zooms viewer"}); - m_infoMap.insert({"T_Rotate", "Rotate Tool: Rotate the workspace"}); - m_infoMap.insert({"T_Ruler", ""}); - m_infoMap.insert( - {"T_Finger", "Finger Tool: Smudges small areas to cover with line"}); - m_infoMap.insert({"T_Dummy", "This tool doesn't work on this layer type."}); + return key; +} + +std::unordered_map StatusBar::makeMap( + QString spacer, QString cmdTextSeparator, QString cmd2TextSeparator) { + std::unordered_map lMap; + +#ifdef MACOSX + // on macOS, we display symbols. No need to space differently + cmd2TextSeparator = cmdTextSeparator; +#endif + + // tools + lMap.insert({"T_Hand", tr("Hand Tool: Pans the workspace")}); + lMap.insert( + {"T_Selection", + tr("Selection Tool: Select parts of your image to transform it") + + spacer + + tr("%1%2Scale / Directional scale") + .arg(trModKey("Shift")) + .arg(cmd2TextSeparator) + + spacer + + tr("%1%2Distort / Shear") + .arg(trModKey("Ctrl")) + .arg(cmd2TextSeparator) + + spacer + + tr("%1%2Scale Symmetrically from Center") + .arg(trModKey("Alt")) + .arg(cmd2TextSeparator) + + spacer + + tr("%1%2Scale Symmetrically from Center w/ Proportion Lock") + .arg(trModKey("Shift") + "+" + trModKey("Alt")) + .arg(cmdTextSeparator)}); + lMap.insert({"T_Edit", tr("Animate Tool: Modifies the position, " + "rotation and size of the current column")}); + lMap.insert({"T_Brush", tr("Brush Tool: Draws in the work area freehand")}); + lMap.insert({"T_BrushVector", + tr("Brush Tool : Draws in the work area freehand") + spacer + + tr("%1%2Straight Lines") + .arg(trModKey("Shift")) + .arg(cmd2TextSeparator) + + spacer + + tr("%1%2Straight Lines Snapped to Angles") + .arg(trModKey("Ctrl")) + .arg(cmd2TextSeparator) + + spacer + + tr("%1%2Add / Remove Vanishing Point") + .arg(trModKey("Ctrl") + "+" + trModKey("Alt")) + .arg(cmdTextSeparator) + + spacer + + tr("%1%2Draw to Vanishing Point") + .arg(trModKey("Alt")) + .arg(cmd2TextSeparator) + + spacer + + tr("%1%2Allow or Disallow Snapping") + .arg(trModKey("Ctrl") + "+" + trModKey("Shift")) + .arg(cmdTextSeparator)}); + lMap.insert({"T_BrushSmartRaster", + tr("Brush Tool : Draws in the work area freehand") + spacer + + tr("%1%2Straight Lines") + .arg(trModKey("Shift")) + .arg(cmd2TextSeparator) + + spacer + + tr("%1%2Straight Lines Snapped to Angles") + .arg(trModKey("Ctrl")) + .arg(cmd2TextSeparator) + + spacer + + tr("%1%2Add / Remove Vanishing Point") + .arg(trModKey("Ctrl") + "+" + trModKey("Alt")) + .arg(cmdTextSeparator) + + spacer + + tr("%1%2Draw to Vanishing Point") + .arg(trModKey("Alt")) + .arg(cmd2TextSeparator)}); + lMap.insert({"T_BrushRaster", + tr("Brush Tool : Draws in the work area freehand") + spacer + + tr("%1%2Straight Lines") + .arg(trModKey("Shift")) + .arg(cmd2TextSeparator) + + spacer + + tr("%1%2Straight Lines Snapped to Angles") + .arg(trModKey("Ctrl")) + .arg(cmd2TextSeparator) + + spacer + + tr("%1%2Add / Remove Vanishing Point") + .arg(trModKey("Ctrl") + "+" + trModKey("Alt")) + .arg(cmdTextSeparator) + + spacer + + tr("%1%2Draw to Vanishing Point") + .arg(trModKey("Alt")) + .arg(cmd2TextSeparator)}); + lMap.insert({"T_Geometric", tr("Geometry Tool: Draws geometric shapes")}); + lMap.insert({"T_GeometricRectangle", + tr("Geometry Tool: Draws geometric shapes") + spacer + + tr("%1%2Proportion Lock") + .arg(trModKey("Shift")) + .arg(cmdTextSeparator) + + spacer + + tr("%1%2Create From Center") + .arg(trModKey("Alt")) + .arg(cmdTextSeparator)}); + lMap.insert({"T_GeometricEllipse", + tr("Geometry Tool: Draws geometric shapes") + spacer + + tr("%1%2Proportion Lock") + .arg(trModKey("Shift")) + .arg(cmdTextSeparator) + + spacer + + tr("%1%2Create From Center") + .arg(trModKey("Alt")) + .arg(cmdTextSeparator)}); + lMap.insert( + {"T_GeometricPolyline", + tr("Geometry Tool: Draws geometric shapes") + spacer + + tr("%1%2Create Curve").arg(tr("Click+Drag")).arg(cmdTextSeparator) + + spacer + + tr("%1%2Return to Straight Line") + .arg(trModKey("Ctrl")) + .arg(cmd2TextSeparator) + + spacer + + tr("%1%2Snap to Angle") + .arg(trModKey("Shift")) + .arg(cmd2TextSeparator)}); + lMap.insert({"T_GeometricVector", + tr("Geometry Tool: Draws geometric shapes") + spacer + + tr("%1%2Allow or Disallow Snapping") + .arg(trModKey("Ctrl") + "+" + trModKey("Shift")) + .arg(cmdTextSeparator)}); + lMap.insert({"T_GeometricVectorRectangle", + tr("Geometry Tool: Draws geometric shapes") + spacer + + tr("%1%2Proportion Lock") + .arg(trModKey("Shift")) + .arg(cmd2TextSeparator) + + spacer + + tr("%1%2Create From Center") + .arg(trModKey("Alt")) + .arg(cmd2TextSeparator) + + spacer + + tr("%1%2Allow or Disallow Snapping") + .arg(trModKey("Ctrl") + "+" + trModKey("Shift")) + .arg(cmdTextSeparator)}); + lMap.insert({"T_GeometricVectorEllipse", + tr("Geometry Tool: Draws geometric shapes") + spacer + + tr("%1%2Proportion Lock") + .arg(trModKey("Shift")) + .arg(cmd2TextSeparator) + + spacer + + tr("%1%2Create From Center") + .arg(trModKey("Alt")) + .arg(cmd2TextSeparator) + + spacer + + tr("%1%2Allow or Disallow Snapping") + .arg(trModKey("Ctrl") + "+" + trModKey("Shift")) + .arg(cmdTextSeparator)}); + lMap.insert( + {"T_GeometricVectorPolyline", + tr("Geometry Tool: Draws geometric shapes") + spacer + + tr("%1%2Create Curve").arg(tr("Click+Drag")).arg(cmdTextSeparator) + + spacer + + tr("%1%2Return to Straight Line") + .arg(trModKey("Ctrl")) + .arg(cmd2TextSeparator) + + spacer + + tr("%1%2Snap to Angle") + .arg(trModKey("Shift")) + .arg(cmd2TextSeparator) + + spacer + + tr("%1%2Allow or Disallow Snapping") + .arg(trModKey("Ctrl") + "+" + trModKey("Shift")) + .arg(cmdTextSeparator)}); + lMap.insert({"T_Type", tr("Type Tool: Adds text")}); + lMap.insert({"T_PaintBrush", + tr("Smart Raster Painter: Paints areas in Smart Raster leves")}); + lMap.insert( + {"T_Fill", tr("Fill Tool: Fills drawing areas with the current style")}); + lMap.insert({"T_Eraser", tr("Eraser: Erases lines and areas")}); + lMap.insert({"T_Tape", + tr("Tape Tool: Closes gaps in raster, joins edges in vector")}); + lMap.insert( + {"T_StylePicker", tr("Style Picker: Selects style on current drawing")}); + lMap.insert( + {"T_RGBPicker", + tr("RGB Picker: Picks color on screen and applies to current style")}); + lMap.insert( + {"T_ControlPointEditor", tr("Control Point Editor: Modifies vector lines " + "by editing its control points")}); + lMap.insert({"T_Pinch", tr("Pinch Tool: Pulls vector drawings")}); + lMap.insert({"T_Pump", tr("Pump Tool: Changes vector thickness")}); + lMap.insert({"T_Magnet", tr("Magnet Tool: Deforms vector lines")}); + lMap.insert({"T_Bender", + tr("Bend Tool: Bends vector shapes around the first click")}); + lMap.insert({"T_Iron", tr("Iron Tool: Smooths vector lines")}); + lMap.insert({"T_Cutter", tr("Cutter Tool: Splits vector lines")}); + lMap.insert({"T_Hook", ""}); + lMap.insert( + {"T_Skeleton", tr("Skeleton Tool: Allows to build a skeleton and animate " + "in a cut-out workflow")}); + lMap.insert({"T_Tracker", + tr("Tracker: Tracks specific regions in a sequence of images")}); + lMap.insert({"T_Plastic", tr("Plastic Tool: Builds a mesh that allows " + "to deform and animate a level")}); + lMap.insert({"T_Zoom", tr("Zoom Tool: Zooms viewer")}); + lMap.insert({"T_Rotate", tr("Rotate Tool: Rotate the workspace")}); + lMap.insert({"T_Ruler", tr("Ruler Tool: Measures distances on the canvas")}); + lMap.insert( + {"T_Finger", tr("Finger Tool: Smudges small areas to cover with line")}); + lMap.insert({"T_Dummy", tr("This tool doesn't work on this layer type.")}); + + return lMap; } diff --git a/toonz/sources/toonz/statusbar.h b/toonz/sources/toonz/statusbar.h index e4194c56..27e972b2 100644 --- a/toonz/sources/toonz/statusbar.h +++ b/toonz/sources/toonz/statusbar.h @@ -3,7 +3,7 @@ #ifndef STATUSBAR_H #define STATUSBAR_H -#include ; +#include #include #include @@ -32,11 +32,16 @@ public: void updateFrameText(QString text); + void refreshStatusBar() { updateInfoText(); } + protected: StatusLabel *m_currentFrameLabel, *m_infoLabel; std::unordered_map m_infoMap; + std::unordered_map m_hintMap; void showEvent(QShowEvent*) override; - void makeMap(); + std::unordered_map makeMap(QString spacer, + QString cmdTextSeparator, + QString cmd2TextSeparator); protected slots: void updateInfoText(); diff --git a/toonz/sources/toonz/tapp.cpp b/toonz/sources/toonz/tapp.cpp index 11c3098f..f9ab4179 100644 --- a/toonz/sources/toonz/tapp.cpp +++ b/toonz/sources/toonz/tapp.cpp @@ -869,6 +869,12 @@ void TApp::showMessage(QString message) { //----------------------------------------------------------------------------- +void TApp::refreshStatusBar() { + if (m_statusBar) m_statusBar->refreshStatusBar(); +} + +//----------------------------------------------------------------------------- + QString TApp::getCurrentRoomName() const { Room *currentRoom = dynamic_cast(getCurrentRoom()); if (!currentRoom) return QString(); diff --git a/toonz/sources/toonz/tapp.h b/toonz/sources/toonz/tapp.h index 302750c3..ee49e16e 100644 --- a/toonz/sources/toonz/tapp.h +++ b/toonz/sources/toonz/tapp.h @@ -216,6 +216,8 @@ public: void setStatusBar(StatusBar *statusBar); void setStatusBarFrameInfo(QString text); + void refreshStatusBar() override; + protected: bool eventFilter(QObject *obj, QEvent *event) override; bool m_showTitleBars = true; diff --git a/toonz/sources/toonz/vcrcommand.cpp b/toonz/sources/toonz/vcrcommand.cpp index 2cabc2fd..47a2258f 100644 --- a/toonz/sources/toonz/vcrcommand.cpp +++ b/toonz/sources/toonz/vcrcommand.cpp @@ -4,6 +4,7 @@ #include "menubarcommandids.h" #include "tapp.h" #include "sceneviewer.h" +#include "stopmotion.h" // TnzQt includes #include "toonzqt/menubarcommand.h" @@ -144,6 +145,10 @@ public: int stopFrame = std::min(currentFrame, maxFrame); + StopMotion *stopMotion = StopMotion::instance(); + if (stopMotion->getPlaceOnXSheet() && stopMotion->m_liveViewStatus > 0) + stopFrame = StopMotion::instance()->getXSheetFrameNumber() - 1; + int startFrame = std::max(0, stopFrame - shortPlayFrameCount); TApp::instance()->getCurrentFrame()->setFrame(startFrame); diff --git a/toonz/sources/toonz/xshcellviewer.cpp b/toonz/sources/toonz/xshcellviewer.cpp index 7ade96c5..950a046c 100644 --- a/toonz/sources/toonz/xshcellviewer.cpp +++ b/toonz/sources/toonz/xshcellviewer.cpp @@ -76,6 +76,7 @@ #include #include #include +#include namespace { @@ -558,7 +559,11 @@ namespace XsheetGUI { //----------------------------------------------------------------------------- RenameCellField::RenameCellField(QWidget *parent, XsheetViewer *viewer) - : QLineEdit(parent), m_viewer(viewer), m_row(-1), m_col(-1) { + : QLineEdit(parent) + , m_viewer(viewer) + , m_row(-1) + , m_col(-1) + , m_isRenamingCell(false) { connect(this, SIGNAL(returnPressed()), SLOT(onReturnPressed())); setContextMenuPolicy(Qt::PreventContextMenu); setObjectName("RenameCellField"); @@ -884,24 +889,39 @@ void RenameCellField::renameCell() { //----------------------------------------------------------------------------- -void RenameCellField::onReturnPressed() { - renameCell(); - +void RenameCellField::moveCellSelection(int direction) { // move the cell selection TCellSelection *cellSelection = dynamic_cast( TApp::instance()->getCurrentSelection()->getSelection()); if (!cellSelection) return; TCellSelection::Range range = cellSelection->getSelectedCells(); - int offset = range.m_r1 - range.m_r0 + 1; + int offset = range.m_r1 - range.m_r0 + direction; + if ((m_row + offset) < 0) return; cellSelection->selectCells(range.m_r0 + offset, range.m_c0, range.m_r1 + offset, range.m_c1); showInRowCol(m_row + offset, m_col, range.getColCount() > 1); m_viewer->updateCells(); + m_viewer->setCurrentRow(m_row); TApp::instance()->getCurrentSelection()->notifySelectionChanged(); } //----------------------------------------------------------------------------- +void RenameCellField::onReturnPressed() { + renameCell(); + moveCellSelection(1); +} + +//----------------------------------------------------------------------------- + +void RenameCellField::onTabPressed() { moveCellSelection(1); } + +//----------------------------------------------------------------------------- + +void RenameCellField::onBacktabPressed() { moveCellSelection(-1); } + +//----------------------------------------------------------------------------- + void RenameCellField::focusOutEvent(QFocusEvent *e) { hide(); @@ -912,9 +932,34 @@ void RenameCellField::focusOutEvent(QFocusEvent *e) { // Override shortcut keys for cell selection commands bool RenameCellField::eventFilter(QObject *obj, QEvent *e) { + if (e->type() == QEvent::KeyPress) { + QKeyEvent *keyEvent = static_cast(e); + int key = keyEvent->key(); + switch (key) { + case Qt::Key_Tab: + onTabPressed(); + return true; + break; + case Qt::Key_Backtab: + onBacktabPressed(); + return true; + break; + } + } + if (e->type() != QEvent::ShortcutOverride) return QLineEdit::eventFilter(obj, e); // return false; + // If we aren't allowing any shortcuts while renaming, use default editing + // commands. + if (!Preferences::instance()->isShortcutCommandsWhileRenamingCellEnabled()) + return QLineEdit::eventFilter(obj, e); + + // No shortcuts in Note Levels + TXshColumn *col = m_viewer->getXsheet()->getColumn(m_col); + bool noShortcuts = (col && col->getSoundTextColumn()) ? true : false; + if (noShortcuts) return QLineEdit::eventFilter(obj, e); + TCellSelection *cellSelection = dynamic_cast( TApp::instance()->getCurrentSelection()->getSelection()); if (!cellSelection) return QLineEdit::eventFilter(obj, e); @@ -925,19 +970,13 @@ bool RenameCellField::eventFilter(QObject *obj, QEvent *e) { QAction *action = CommandManager::instance()->getActionFromShortcut(keyStr); if (!action) return QLineEdit::eventFilter(obj, e); - std::string actionId = CommandManager::instance()->getIdFromAction(action); - // These are usally standard ctrl/command strokes for text editing. // Default to standard behavior and don't execute OT's action while renaming // cell if users prefer to do so. - // Or, always invoke OT's commands when renaming cell even the standard - // command strokes for text editing. - // The latter option is demanded by Japanese animation industry in order to - // gain efficiency for inputting xsheet. - if (!Preferences::instance()->isShortcutCommandsWhileRenamingCellEnabled() && - (actionId == "MI_Undo" || actionId == "MI_Redo" || - actionId == "MI_Clear" || actionId == "MI_Copy" || - actionId == "MI_Paste" || actionId == "MI_Cut")) + std::string actionId = CommandManager::instance()->getIdFromAction(action); + if (actionId == "MI_Undo" || actionId == "MI_Redo" || + actionId == "MI_Clear" || actionId == "MI_Copy" || + actionId == "MI_Paste" || actionId == "MI_Cut") return QLineEdit::eventFilter(obj, e); return TCellSelection::isEnabledCommand(actionId); @@ -948,6 +987,7 @@ bool RenameCellField::eventFilter(QObject *obj, QEvent *e) { void RenameCellField::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Escape) { clearFocus(); + m_viewer->setFocus(); return; } @@ -965,7 +1005,8 @@ void RenameCellField::keyPressEvent(QKeyEvent *event) { stride.setFrame(cellSelection->getSelectedCells().getRowCount()); CellPosition offset; - switch (int key = event->key()) { + int key = event->key(); + switch (key) { case Qt::Key_Up: case Qt::Key_Down: offset = m_viewer->orientation()->arrowShift(key); @@ -973,10 +1014,16 @@ void RenameCellField::keyPressEvent(QKeyEvent *event) { case Qt::Key_Left: case Qt::Key_Right: // ctrl+left/right arrow for moving cursor to the end in the field - if (isCtrlPressed && + if (!isCtrlPressed || !Preferences::instance()->isUseArrowKeyToShiftCellSelectionEnabled()) { - QLineEdit::keyPressEvent(event); - return; + // Allow left/right movement inside field. If you go too far, you will + // shift cells + int curPos = cursorPosition(); + if ((key == Qt::Key_Left && curPos > 0) || + (key == Qt::Key_Right && curPos < text().size())) { + QLineEdit::keyPressEvent(event); + return; + } } offset = m_viewer->orientation()->arrowShift(key); break; @@ -1019,6 +1066,8 @@ void RenameCellField::showEvent(QShowEvent *) { bool ret = connect(TApp::instance()->getCurrentXsheet(), SIGNAL(xsheetChanged()), this, SLOT(onXsheetChanged())); assert(ret); + + m_isRenamingCell = true; } //----------------------------------------------------------------------------- @@ -1026,6 +1075,7 @@ void RenameCellField::showEvent(QShowEvent *) { void RenameCellField::hideEvent(QHideEvent *) { disconnect(TApp::instance()->getCurrentXsheet(), SIGNAL(xsheetChanged()), this, SLOT(onXsheetChanged())); + m_isRenamingCell = false; } //----------------------------------------------------------------------------- diff --git a/toonz/sources/toonz/xshcellviewer.h b/toonz/sources/toonz/xshcellviewer.h index 43a219a7..0090e7a8 100644 --- a/toonz/sources/toonz/xshcellviewer.h +++ b/toonz/sources/toonz/xshcellviewer.h @@ -26,6 +26,7 @@ class RenameCellField final : public QLineEdit { int m_row; int m_col; XsheetViewer *m_viewer; + bool m_isRenamingCell; public: RenameCellField(QWidget *parent, XsheetViewer *viewer); @@ -35,6 +36,8 @@ public: bool isLocatedAt(int row, int col) { return row == m_row && col == m_col; } + bool isRenamingCell() { return m_isRenamingCell; } + protected: void focusOutEvent(QFocusEvent *) override; void keyPressEvent(QKeyEvent *event) override; @@ -46,6 +49,10 @@ protected: void renameCell(); void renameSoundTextColumn(TXshSoundTextColumn *sndTextCol, const QString &s); + void moveCellSelection(int direction); + void onTabPressed(); + void onBacktabPressed(); + protected slots: void onReturnPressed(); void onXsheetChanged(); @@ -134,6 +141,9 @@ public: m_renameCell->showInRowCol(row, col, multiColumnSelected); } void hideRenameField() { m_renameCell->hide(); } + bool isRenamingCell() { + return m_renameCell && m_renameCell->isRenamingCell(); + } protected: void paintEvent(QPaintEvent *) override; diff --git a/toonz/sources/toonz/xsheetviewer.cpp b/toonz/sources/toonz/xsheetviewer.cpp index 1c3fc92e..90538494 100644 --- a/toonz/sources/toonz/xsheetviewer.cpp +++ b/toonz/sources/toonz/xsheetviewer.cpp @@ -1667,8 +1667,8 @@ void XsheetViewer::changeWindowTitle() { QString sceneName = QString::fromStdWString(scene->getSceneName()); if (sceneName.isEmpty()) sceneName = tr("Untitled"); if (app->getCurrentScene()->getDirtyFlag()) sceneName += QString("*"); - QString name = tr("Scene: ") + sceneName; QString separator = " | "; + QString name = tr("Scene: ") + sceneName; int frameCount = scene->getFrameCount(); name = name + separator + tr(std::to_string(frameCount).c_str()) + (frameCount == 1 ? tr(" Frame") : tr(" Frames")); @@ -1682,7 +1682,7 @@ void XsheetViewer::changeWindowTitle() { TXshLevel *level = app->getCurrentLevel()->getLevel(); if (level) { QString levelName = QString::fromStdWString(level->getName()); - name += separator + tr(" Level: ") + levelName; + name += separator + tr("Level: ") + levelName; } // cell selection range if ((TSelection *)getCellSelection() == @@ -1690,12 +1690,12 @@ void XsheetViewer::changeWindowTitle() { !getCellSelection()->isEmpty()) { int r0, r1, c0, c1; getCellSelection()->getSelectedCells(r0, c0, r1, c1); - name += separator + tr(" Selected: ") + QString::number(r1 - r0 + 1) + + name += separator + tr("Selected: ") + QString::number(r1 - r0 + 1) + ((r1 - r0 + 1 == 1) ? tr(" frame : ") : tr(" frames * ")) + QString::number(c1 - c0 + 1) + ((c1 - c0 + 1 == 1) ? tr(" column") : tr(" columns")); } - TApp::instance()->setStatusBarFrameInfo(name); + TApp::instance()->setStatusBarFrameInfo("| " + name); parentWidget()->setWindowTitle(name); } diff --git a/toonz/sources/toonzlib/preferences.cpp b/toonz/sources/toonzlib/preferences.cpp index 0e37cdba..23717563 100644 --- a/toonz/sources/toonzlib/preferences.cpp +++ b/toonz/sources/toonzlib/preferences.cpp @@ -498,6 +498,8 @@ void Preferences::definePreferenceItems() { 0); // Default define(useCtrlAltToResizeBrush, "useCtrlAltToResizeBrush", QMetaType::Bool, true); + define(temptoolswitchtimer, "temptoolswitchtimer", QMetaType::Int, 500, 1, + std::numeric_limits::max()); // Xsheet define(xsheetLayoutPreference, "xsheetLayoutPreference", QMetaType::QString, diff --git a/toonz/sources/xdg-data/org.tahoma2d.Tahoma2D.metainfo.xml b/toonz/sources/xdg-data/org.tahoma2d.Tahoma2D.metainfo.xml index 9c9b6cd1..04f597a6 100644 --- a/toonz/sources/xdg-data/org.tahoma2d.Tahoma2D.metainfo.xml +++ b/toonz/sources/xdg-data/org.tahoma2d.Tahoma2D.metainfo.xml @@ -18,7 +18,7 @@

https://tahoma2d.org - https://github.com/turtletooth/tahoma2d/issues + https://github.com/tahoma2d/tahoma2d/issues https://tahoma2d.readthedocs.io/en/latest/_images/interface.png