From 1f9dda0620b89b408a21e22297725e24acd31469 Mon Sep 17 00:00:00 2001 From: Matt Date: Mon, 16 Apr 2018 13:18:49 +1000 Subject: [PATCH 001/184] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 824fa1e3e..33d6e3e85 100644 --- a/README.md +++ b/README.md @@ -16,10 +16,10 @@ | :--------------: | :---------------: | :-------------: | :---------------: | | [Download][0] | [Download][1] | [Download][2] | [Download][3] | -[0]: https://github.com/pencil2d/pencil/releases/download/v0.6.1/pencil2d-win64-0.6.1.zip -[1]: https://github.com/pencil2d/pencil/releases/download/v0.6.1/pencil2d-win32-0.6.1.zip -[2]: https://github.com/pencil2d/pencil/releases/download/v0.6.1/pencil2d-mac-0.6.1.zip -[3]: https://github.com/pencil2d/pencil/releases/download/v0.6.1/pencil2d-linux-amd64-0.6.1.AppImage +[0]: https://github.com/pencil2d/pencil/releases/download/v0.6.1.1/pencil2d-win64-0.6.1.1.zip +[1]: https://github.com/pencil2d/pencil/releases/download/v0.6.1.1/pencil2d-win32-0.6.1.1.zip +[2]: https://github.com/pencil2d/pencil/releases/download/v0.6.1.1/pencil2d-mac-0.6.1.1.zip +[3]: https://github.com/pencil2d/pencil/releases/download/v0.6.1.1/pencil2d-linux-amd64-0.6.1.1.AppImage ### Debian & Ubuntu From 5155af9df42a515d95189a353d28b640384e23aa Mon Sep 17 00:00:00 2001 From: CandyFace Date: Sun, 15 Apr 2018 21:39:50 +0200 Subject: [PATCH 002/184] Add warning to import on failed attemps and remove .tiff --- app/src/mainwindow2.cpp | 30 ++++++++++++++++++++++++------ core_lib/src/util/pencildef.h | 2 +- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index 763a4c770..ee3051aa5 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -721,21 +721,18 @@ void MainWindow2::importImageSequence() progress.setMaximum(totalImagesToImport); int imagesImportedSoFar = 0; + QString failedFiles; + bool failedImport = false; for (QString strImgFile : files) { QString strImgFileLower = strImgFile.toLower(); + if (strImgFileLower.endsWith(".png") || strImgFileLower.endsWith(".jpg") || strImgFileLower.endsWith(".jpeg") || - strImgFileLower.endsWith(".tif") || - strImgFileLower.endsWith(".tiff") || strImgFileLower.endsWith(".bmp")) { mEditor->importImage(strImgFile); - for (int i = 1; i < number; i++) - { - mEditor->scrubForward(); - } imagesImportedSoFar++; progress.setValue(imagesImportedSoFar); @@ -745,8 +742,29 @@ void MainWindow2::importImageSequence() { break; } + } else { + failedFiles += strImgFile + "\n"; + if (!failedImport) + { + failedImport = true; + } } } + + if (failedImport) + { + QMessageBox::warning(this, + tr("Warning"), + tr("was unable to import") + failedFiles, + QMessageBox::Ok, + QMessageBox::Ok); + } + + for (int i = 1; i < number; i++) + { + mEditor->scrubForward(); + } + mEditor->layers()->notifyAnimationLengthChanged(); progress.close(); diff --git a/core_lib/src/util/pencildef.h b/core_lib/src/util/pencildef.h index 042ca76d6..9a55a7beb 100644 --- a/core_lib/src/util/pencildef.h +++ b/core_lib/src/util/pencildef.h @@ -22,7 +22,7 @@ GNU General Public License for more details. QObject::tr( "AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv)" ) #define PENCIL_IMAGE_FILTER \ - QObject::tr( "Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif)" ) + QObject::tr( "Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif)" ) enum ToolType : int From 4587a75d9d6240790428983d50b0e16d52748a80 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 17 Apr 2018 14:05:10 +1000 Subject: [PATCH 003/184] Unit test for #947 1x1 pixel dot appearing in the center of canvas --- tests/src/test_bitmapimage.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/src/test_bitmapimage.cpp b/tests/src/test_bitmapimage.cpp index ca7ee68b8..0a298f52c 100644 --- a/tests/src/test_bitmapimage.cpp +++ b/tests/src/test_bitmapimage.cpp @@ -17,7 +17,7 @@ GNU General Public License for more details. #include "bitmapimage.h" -TEST_CASE("BitmapImage") +TEST_CASE("BitmapImage constructors") { SECTION("Init an Bitmap Image") { @@ -61,4 +61,21 @@ TEST_CASE("BitmapImage") REQUIRE(img1 != img2); REQUIRE((*img1) == (*img2)); } + + SECTION("#947 Initial Color") + { + // A new bitmap image must be fully transparent + // otherwise a pixel dot will appear in center of canvas + // ref: https://github.com/pencil2d/pencil/pull/947 + + auto b = std::make_shared(); + for (int x = 0; x < b->width(); ++x) + { + for (int y = 0; y < b->height(); ++y) + { + QRgb color = b->pixel(x, y); + REQUIRE(qAlpha(color) == 0); + } + } + } } From 84aab3dc40a8de1b97e74b56fdce3fa15194cc55 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 17 Apr 2018 15:57:46 +1000 Subject: [PATCH 004/184] Delete unused functions --- core_lib/src/interface/timelinecells.cpp | 4 ---- core_lib/src/structure/layer.cpp | 18 ------------------ core_lib/src/structure/layer.h | 4 ---- 3 files changed, 26 deletions(-) diff --git a/core_lib/src/interface/timelinecells.cpp b/core_lib/src/interface/timelinecells.cpp index 129c1cbac..140e48124 100644 --- a/core_lib/src/interface/timelinecells.cpp +++ b/core_lib/src/interface/timelinecells.cpp @@ -529,7 +529,6 @@ void TimeLineCells::mousePressEvent(QMouseEvent* event) mCanMoveFrame = true; } - currentLayer->mousePress(event, frameNumber); mTimeLine->updateContent(); } else @@ -606,7 +605,6 @@ void TimeLineCells::mouseMoveEvent(QMouseEvent* event) } mLastFrameNumber = frameNumber; } - currentLayer->mouseMove(event, frameNumber); } } } @@ -638,8 +636,6 @@ void TimeLineCells::mouseReleaseEvent(QMouseEvent* event) // Add/remove from already selected currentLayer->toggleFrameSelected(frameNumber, multipleSelection); } - - currentLayer->mouseRelease(event, frameNumber); } if (mType == TIMELINE_CELL_TYPE::Layers && layerNumber != mStartLayerNumber && mStartLayerNumber != -1 && layerNumber != -1) { diff --git a/core_lib/src/structure/layer.cpp b/core_lib/src/structure/layer.cpp index 094721343..2103a2348 100644 --- a/core_lib/src/structure/layer.cpp +++ b/core_lib/src/structure/layer.cpp @@ -424,30 +424,12 @@ void Layer::paintSelection(QPainter& painter, int x, int y, int width, int heigh painter.drawRect(x, y, width, height - 1); } -void Layer::mousePress(QMouseEvent* event, int frameNumber) -{ - Q_UNUSED(event); - Q_UNUSED(frameNumber); -} - void Layer::mouseDoubleClick(QMouseEvent* event, int frameNumber) { Q_UNUSED(event); Q_UNUSED(frameNumber); } -void Layer::mouseMove(QMouseEvent* event, int frameNumber) -{ - Q_UNUSED(event); - Q_UNUSED(frameNumber); -} - -void Layer::mouseRelease(QMouseEvent* event, int frameNumber) -{ - Q_UNUSED(event); - Q_UNUSED(frameNumber); -} - void Layer::editProperties() { } diff --git a/core_lib/src/structure/layer.h b/core_lib/src/structure/layer.h index b0f2a6919..4d0cba022 100644 --- a/core_lib/src/structure/layer.h +++ b/core_lib/src/structure/layer.h @@ -113,10 +113,6 @@ class Layer : public QObject void paintFrames(QPainter& painter, TimeLineCells* cells, int y, int height, bool selected, int frameSize); void paintLabel(QPainter& painter, TimeLineCells* cells, int x, int y, int height, int width, bool selected, int allLayers); virtual void paintSelection(QPainter& painter, int x, int y, int height, int width); - - void mousePress(QMouseEvent*, int frameNumber); - void mouseMove(QMouseEvent*, int frameNumber); - void mouseRelease(QMouseEvent*, int frameNumber); void mouseDoubleClick(QMouseEvent*, int frameNumber); virtual void editProperties(); From 0728875010468f220580d3b01ef3ab7b4b65f907 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 17 Apr 2018 16:08:55 +1000 Subject: [PATCH 005/184] Delete unused functions --- core_lib/src/structure/layersound.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/core_lib/src/structure/layersound.h b/core_lib/src/structure/layersound.h index d6f95086b..cfead1ca3 100644 --- a/core_lib/src/structure/layersound.h +++ b/core_lib/src/structure/layersound.h @@ -33,17 +33,8 @@ class LayerSound : public Layer void loadDomElement(QDomElement element, QString dataDirPath, ProgressCallback progressStep) override; Status loadSoundClipAtFrame( const QString& sSoundClipName, const QString& filePathString, int frame ); - void updateFrameLengths(int fps); - // These functions will be removed later. - // Don't use them!! - int getSoundSize() { return 0; } - bool soundIsNotNull( int ) { return true; } - QString getSoundFilepathAt( int ) { return ""; } - bool isEmpty() { return true; } - // These functions will be removed. - SoundClip* getSoundClipWhichCovers(int frameNumber); protected: From b06ed53ae6df49abe23b15538a66a7d25e45235e Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 17 Apr 2018 23:04:26 +1000 Subject: [PATCH 006/184] Clean up --- core_lib/src/external/win32/win32.cpp | 33 --------------------------- 1 file changed, 33 deletions(-) diff --git a/core_lib/src/external/win32/win32.cpp b/core_lib/src/external/win32/win32.cpp index 14aa12974..c5eef7d11 100644 --- a/core_lib/src/external/win32/win32.cpp +++ b/core_lib/src/external/win32/win32.cpp @@ -29,39 +29,6 @@ GNU General Public License for more details. #include "editor.h" #include "layersound.h" -#define MIN(a, b) ((a)>(b) ? (b) : (a)) - - - - -int16_t safeSum( int16_t a, int16_t b ) -{ - if ( ( ( int )a + ( int )b ) > 32767 ) - return 32767; - if ( ( ( int )a + ( int )b ) < -32768 ) - return -32768; - return a + b; -} - -void initialise() -{ - //qDebug() << "Initialize win32: "; - - // QImageReader capabilities - QList formats = QImageReader::supportedImageFormats(); - foreach( QString format, formats ) - { - //qDebug() << "QImageReader capability: " << format; - } - - // QImageWriter capabilities - formats = QImageWriter::supportedImageFormats(); - foreach( QString format, formats ) - { - //qDebug() << "QImageWriter capability: " << format; - } -} - void Editor::importMovie( QString filePath, int fps ) { From a36d9510c4dc9bfb8027fdc933e81b3b39f6f64f Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 17 Apr 2018 23:11:56 +1000 Subject: [PATCH 007/184] Keep the color palette preferences - so it won't go back to default state when pencil2d restarts --- app/src/colorpalettewidget.cpp | 44 ++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/app/src/colorpalettewidget.cpp b/app/src/colorpalettewidget.cpp index 0a081b6c2..4aa022948 100644 --- a/app/src/colorpalettewidget.cpp +++ b/app/src/colorpalettewidget.cpp @@ -49,9 +49,19 @@ void ColorPaletteWidget::initUI() // "Remove color" feature is disabled because // vector strokes that are linked to palette // colors don't handle color removal from palette - mIconSize = QSize(34, 34); ui->removeColorButton->hide(); - updateUI(); + + QSettings settings(PENCIL2D, PENCIL2D); + int colorGridSize = settings.value("PreferredColorGridSize", 34).toInt(); + + mIconSize = QSize(colorGridSize, colorGridSize); + + QString sViewMode = settings.value("ColorPaletteViewMode", "ListMode").toString(); + if (sViewMode == "ListMode") + setListMode(); + else + setGridMode(); + palettePreferences(); connect(ui->colorListWidget, &QListWidget::currentItemChanged, this, &ColorPaletteWidget::colorListCurrentItemChanged); @@ -192,7 +202,7 @@ void ColorPaletteWidget::palettePreferences() ui->colorListWidget->setMinimumWidth(ui->colorListWidget->sizeHintForColumn(0)); // Let's pretend this button is a separator - mSeparator = new QAction(tr(""), this); + mSeparator = new QAction("", this); mSeparator->setSeparator(true); // Add to UI @@ -203,6 +213,15 @@ void ColorPaletteWidget::palettePreferences() ui->palettePref->addAction(ui->mediumSwatchAction); ui->palettePref->addAction(ui->largeSwatchAction); + if (mIconSize.width() > 30) ui->largeSwatchAction->setChecked(true); + else if (mIconSize.width() > 20) ui->mediumSwatchAction->setChecked(true); + else ui->smallSwatchAction->setChecked(true); + + if (ui->colorListWidget->viewMode() == QListView::ListMode) + ui->listModeAction->setChecked(true); + else + ui->gridModeAction->setChecked(true); + connect(ui->listModeAction, &QAction::triggered, this, &ColorPaletteWidget::setListMode); connect(ui->gridModeAction, &QAction::triggered, this, &ColorPaletteWidget::setGridMode); connect(ui->smallSwatchAction, &QAction::triggered, this, &ColorPaletteWidget::setSwatchSizeSmall); @@ -216,6 +235,9 @@ void ColorPaletteWidget::setListMode() ui->colorListWidget->setMovement(QListView::Static); ui->colorListWidget->setGridSize(QSize(-1, -1)); updateUI(); + + QSettings settings(PENCIL2D, PENCIL2D); + settings.setValue("ColorPaletteViewMode", "ListMode"); } void ColorPaletteWidget::setGridMode() @@ -225,6 +247,9 @@ void ColorPaletteWidget::setGridMode() ui->colorListWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); ui->colorListWidget->setGridSize(mIconSize); updateUI(); + + QSettings settings(PENCIL2D, PENCIL2D); + settings.setValue("ColorPaletteViewMode", "GridMode"); } void ColorPaletteWidget::resizeEvent(QResizeEvent* event) @@ -259,8 +284,11 @@ void ColorPaletteWidget::setSwatchSizeSmall() if (mIconSize.width() > 18) { mIconSize = QSize(14, 14); + updateUI(); + + QSettings settings(PENCIL2D, PENCIL2D); + settings.setValue("PreferredColorGridSize", 14); } - updateUI(); } void ColorPaletteWidget::setSwatchSizeMedium() @@ -269,6 +297,9 @@ void ColorPaletteWidget::setSwatchSizeMedium() { mIconSize = QSize(26, 26); updateUI(); + + QSettings settings(PENCIL2D, PENCIL2D); + settings.setValue("PreferredColorGridSize", 26); } } @@ -278,13 +309,16 @@ void ColorPaletteWidget::setSwatchSizeLarge() { mIconSize = QSize(34, 34); updateUI(); + + QSettings settings(PENCIL2D, PENCIL2D); + settings.setValue("PreferredColorGridSize", 34); } } void ColorPaletteWidget::updateGridUI() { if (ui->colorListWidget->viewMode() == QListView::IconMode) - ui->colorListWidget->setGridSize(QSize(mIconSize.width(), mIconSize.height())); + ui->colorListWidget->setGridSize(mIconSize); else ui->colorListWidget->setGridSize(QSize(-1, -1)); From 240a6a1124ffa720b75abe38c02b92fc33704534 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 17 Apr 2018 23:34:30 +1000 Subject: [PATCH 008/184] Format documents --- core_lib/src/managers/preferencemanager.cpp | 212 ++++++++++---------- core_lib/src/managers/preferencemanager.h | 25 ++- 2 files changed, 114 insertions(+), 123 deletions(-) diff --git a/core_lib/src/managers/preferencemanager.cpp b/core_lib/src/managers/preferencemanager.cpp index 43fed126a..31fd6be46 100644 --- a/core_lib/src/managers/preferencemanager.cpp +++ b/core_lib/src/managers/preferencemanager.cpp @@ -49,96 +49,88 @@ void PreferenceManager::loadPrefs() QSettings settings( PENCIL2D, PENCIL2D ); // Display - set( SETTING::GRID, settings.value( SETTING_SHOW_GRID, false ).toBool() ); - set( SETTING::INVISIBLE_LINES, settings.value( SETTING_INVISIBLE_LINES, false ).toBool() ); - set( SETTING::OUTLINES, settings.value( SETTING_OUTLINES, false ).toBool() ); + set(SETTING::GRID, settings.value(SETTING_SHOW_GRID, false).toBool()); + set(SETTING::INVISIBLE_LINES, settings.value(SETTING_INVISIBLE_LINES, false).toBool()); + set(SETTING::OUTLINES, settings.value(SETTING_OUTLINES, false).toBool()); // Grid - set( SETTING::GRID_SIZE, settings.value( SETTING_GRID_SIZE, 50 ).toInt() ); + set(SETTING::GRID_SIZE, settings.value(SETTING_GRID_SIZE, 50).toInt()); // General // - set( SETTING::ANTIALIAS, settings.value( SETTING_ANTIALIAS, true ).toBool() ); - set( SETTING::TOOL_CURSOR, settings.value( SETTING_TOOL_CURSOR, true ).toBool() ); - set( SETTING::DOTTED_CURSOR, settings.value( SETTING_DOTTED_CURSOR, true ).toBool() ); - set( SETTING::HIGH_RESOLUTION, settings.value( SETTING_HIGH_RESOLUTION, true ).toBool() ); - set( SETTING::SHADOW, settings.value( SETTING_SHADOW, false ).toBool() ); - set( SETTING::QUICK_SIZING, settings.value( SETTING_QUICK_SIZING, true ).toBool() ); + set(SETTING::ANTIALIAS, settings.value(SETTING_ANTIALIAS, true).toBool()); + set(SETTING::TOOL_CURSOR, settings.value(SETTING_TOOL_CURSOR, true).toBool()); + set(SETTING::DOTTED_CURSOR, settings.value(SETTING_DOTTED_CURSOR, true).toBool()); + set(SETTING::HIGH_RESOLUTION, settings.value(SETTING_HIGH_RESOLUTION, true).toBool()); + set(SETTING::SHADOW, settings.value(SETTING_SHADOW, false).toBool()); + set(SETTING::QUICK_SIZING, settings.value(SETTING_QUICK_SIZING, true).toBool()); - set( SETTING::WINDOW_OPACITY, settings.value( SETTING_WINDOW_OPACITY, 0 ).toInt() ); - set( SETTING::CURVE_SMOOTHING, settings.value( SETTING_CURVE_SMOOTHING, 20 ).toInt() ); + set(SETTING::WINDOW_OPACITY, settings.value(SETTING_WINDOW_OPACITY, 0).toInt()); + set(SETTING::CURVE_SMOOTHING, settings.value(SETTING_CURVE_SMOOTHING, 20).toInt()); - set( SETTING::BACKGROUND_STYLE, settings.value( SETTING_BACKGROUND_STYLE, "white" ).toString() ); + set(SETTING::BACKGROUND_STYLE, settings.value(SETTING_BACKGROUND_STYLE, "white").toString()); - set( SETTING::LAYOUT_LOCK, settings.value( SETTING_LAYOUT_LOCK, false ).toBool() ); + set(SETTING::LAYOUT_LOCK, settings.value(SETTING_LAYOUT_LOCK, false).toBool()); // Files - set( SETTING::AUTO_SAVE, settings.value( SETTING_AUTO_SAVE, true ).toBool() ); - set( SETTING::AUTO_SAVE_NUMBER, settings.value( SETTING_AUTO_SAVE_NUMBER, 25 ).toInt() ); + set(SETTING::AUTO_SAVE, settings.value(SETTING_AUTO_SAVE, true ).toBool()); + set(SETTING::AUTO_SAVE_NUMBER, settings.value(SETTING_AUTO_SAVE_NUMBER, 25).toInt()); // Timeline - // - set( SETTING::SHORT_SCRUB, settings.value( SETTING_SHORT_SCRUB, false ).toBool() ); - set( SETTING::FRAME_SIZE, settings.value( SETTING_FRAME_SIZE, 12 ).toInt() ); - set( SETTING::TIMELINE_SIZE, settings.value( SETTING_TIMELINE_SIZE, 240 ).toInt() ); - set( SETTING::DRAW_LABEL, settings.value( SETTING_DRAW_LABEL, false ).toBool() ); - set( SETTING::LABEL_FONT_SIZE, settings.value( SETTING_LABEL_FONT_SIZE, 12 ).toInt() ); + set(SETTING::SHORT_SCRUB, settings.value(SETTING_SHORT_SCRUB, false ).toBool()); + set(SETTING::FRAME_SIZE, settings.value(SETTING_FRAME_SIZE, 12).toInt()); + set(SETTING::TIMELINE_SIZE, settings.value(SETTING_TIMELINE_SIZE, 240).toInt()); + set(SETTING::DRAW_LABEL, settings.value(SETTING_DRAW_LABEL, false ).toBool()); + set(SETTING::LABEL_FONT_SIZE, settings.value(SETTING_LABEL_FONT_SIZE, 12).toInt()); // Onion Skin - // - set( SETTING::PREV_ONION, settings.value( SETTING_PREV_ONION, false ).toBool() ); - set( SETTING::NEXT_ONION, settings.value( SETTING_NEXT_ONION, false ).toBool() ); - set( SETTING::MULTILAYER_ONION, settings.value( SETTING_MULTILAYER_ONION, false ).toBool() ); - set( SETTING::ONION_BLUE, settings.value( SETTING_ONION_BLUE, false ).toBool() ); - set( SETTING::ONION_RED, settings.value( SETTING_ONION_RED, false ).toBool() ); - - set( SETTING::ONION_MAX_OPACITY, settings.value( SETTING_ONION_MAX_OPACITY, 50 ).toInt() ); - set( SETTING::ONION_MIN_OPACITY, settings.value( SETTING_ONION_MIN_OPACITY, 20 ).toInt() ); - set( SETTING::ONION_PREV_FRAMES_NUM, settings.value( SETTING_ONION_PREV_FRAMES_NUM, 5 ).toInt() ); - set( SETTING::ONION_NEXT_FRAMES_NUM, settings.value( SETTING_ONION_NEXT_FRAMES_NUM, 5 ).toInt() ); - set( SETTING::ONION_TYPE, settings.value( SETTING_ONION_TYPE, "relative" ).toString() ); - - set( SETTING::LANGUAGE, settings.value( SETTING_LANGUAGE ).toString() ); - - set( SETTING::AXIS, false ); -//#define DRAW_AXIS -#ifdef DRAW_AXIS - set( SETTING::AXIS, true ); -#endif + set(SETTING::PREV_ONION, settings.value(SETTING_PREV_ONION, false).toBool()); + set(SETTING::NEXT_ONION, settings.value(SETTING_NEXT_ONION, false).toBool()); + set(SETTING::MULTILAYER_ONION, settings.value(SETTING_MULTILAYER_ONION, false).toBool()); + set(SETTING::ONION_BLUE, settings.value(SETTING_ONION_BLUE, false).toBool()); + set(SETTING::ONION_RED, settings.value(SETTING_ONION_RED, false).toBool()); + + set(SETTING::ONION_MAX_OPACITY, settings.value(SETTING_ONION_MAX_OPACITY, 50).toInt()); + set(SETTING::ONION_MIN_OPACITY, settings.value(SETTING_ONION_MIN_OPACITY, 20).toInt()); + set(SETTING::ONION_PREV_FRAMES_NUM, settings.value(SETTING_ONION_PREV_FRAMES_NUM, 5).toInt()); + set(SETTING::ONION_NEXT_FRAMES_NUM, settings.value(SETTING_ONION_NEXT_FRAMES_NUM, 5).toInt()); + set(SETTING::ONION_TYPE, settings.value(SETTING_ONION_TYPE, "relative").toString()); + + set(SETTING::LANGUAGE, settings.value(SETTING_LANGUAGE).toString()); } -void PreferenceManager::turnOn( SETTING option ) +void PreferenceManager::turnOn(SETTING option) { - set( option, true ); + set(option, true); } -void PreferenceManager::turnOff( SETTING option ) +void PreferenceManager::turnOff(SETTING option) { - set( option, false ); + set(option, false); } -bool PreferenceManager::isOn( SETTING option ) +bool PreferenceManager::isOn(SETTING option) { - int optionId = static_cast< int >( option ); + int optionId = static_cast(option); return mBooleanSet.value(optionId, false); } -int PreferenceManager::getInt( SETTING option ) +int PreferenceManager::getInt(SETTING option) { int optionId = static_cast(option); return mIntegerSet.value(optionId, -1); } -QString PreferenceManager::getString( SETTING option ) +QString PreferenceManager::getString(SETTING option) { - int optionId = static_cast< int >( option ); - if ( mIntegerSet.contains( optionId ) ) + int optionId = static_cast(option); + if (mIntegerSet.contains(optionId)) { - return QString::number( mIntegerSet.value( optionId, -1 ) ); + return QString::number(mIntegerSet.value(optionId, -1)); } - else if ( mBooleanSet.contains( optionId ) ) + else if (mBooleanSet.contains(optionId)) { - if ( mBooleanSet.value( optionId, false ) ) + if (mBooleanSet.value(optionId, false)) { return "true"; } @@ -155,160 +147,160 @@ QString PreferenceManager::getString( SETTING option ) // void PreferenceManager::set(SETTING option, QString value) { - QSettings settings( PENCIL2D, PENCIL2D ); - switch ( option ) + QSettings settings(PENCIL2D, PENCIL2D); + switch (option) { case SETTING::BACKGROUND_STYLE: - settings.setValue( SETTING_BACKGROUND_STYLE, value ); + settings.setValue(SETTING_BACKGROUND_STYLE, value); break; case SETTING::ONION_TYPE: - settings.setValue( SETTING_ONION_TYPE, value ); + settings.setValue(SETTING_ONION_TYPE, value); break; case SETTING::LANGUAGE: - settings.setValue( SETTING_LANGUAGE, value ); + settings.setValue(SETTING_LANGUAGE, value); break; default: break; } - int optionId = static_cast< int >( option ); - if ( mStringSet[ optionId ] != value ) + int optionId = static_cast(option); + if (mStringSet[optionId] != value) { - mStringSet[ optionId ] = value; - emit optionChanged( option ); + mStringSet[optionId] = value; + emit optionChanged(option); } } // Set int value // -void PreferenceManager::set( SETTING option, int value ) +void PreferenceManager::set(SETTING option, int value) { - QSettings settings( PENCIL2D, PENCIL2D ); - switch ( option ) + QSettings settings(PENCIL2D, PENCIL2D); + switch (option) { case SETTING::WINDOW_OPACITY: - settings.setValue( SETTING_WINDOW_OPACITY, value ); + settings.setValue(SETTING_WINDOW_OPACITY, value); break; case SETTING::CURVE_SMOOTHING: - settings.setValue( SETTING_CURVE_SMOOTHING, value ); + settings.setValue(SETTING_CURVE_SMOOTHING, value); break; case SETTING::AUTO_SAVE_NUMBER: - settings.setValue ( SETTING_AUTO_SAVE_NUMBER, value ); + settings.setValue(SETTING_AUTO_SAVE_NUMBER, value); break; case SETTING::FRAME_SIZE: if (value < 4) { value = 4; } else if (value > 20) { value = 20; } - settings.setValue ( SETTING_FRAME_SIZE, value ); + settings.setValue(SETTING_FRAME_SIZE, value); break; case SETTING::TIMELINE_SIZE: if (value < 2) { value = 2; } - settings.setValue ( SETTING_TIMELINE_SIZE, value ); + settings.setValue(SETTING_TIMELINE_SIZE, value); break; case SETTING::LABEL_FONT_SIZE: if (value < 12) { value = 12; } - settings.setValue ( SETTING_LABEL_FONT_SIZE, value ); + settings.setValue(SETTING_LABEL_FONT_SIZE, value); break; case SETTING::ONION_MAX_OPACITY: - settings.setValue ( SETTING_ONION_MAX_OPACITY, value ); + settings.setValue(SETTING_ONION_MAX_OPACITY, value); break; case SETTING::ONION_MIN_OPACITY: - settings.setValue ( SETTING_ONION_MIN_OPACITY, value ); + settings.setValue(SETTING_ONION_MIN_OPACITY, value); break; case SETTING::ONION_PREV_FRAMES_NUM: - settings.setValue ( SETTING_ONION_PREV_FRAMES_NUM, value ); + settings.setValue(SETTING_ONION_PREV_FRAMES_NUM, value); break; case SETTING::ONION_NEXT_FRAMES_NUM: - settings.setValue ( SETTING_ONION_NEXT_FRAMES_NUM, value ); + settings.setValue(SETTING_ONION_NEXT_FRAMES_NUM, value); break; case SETTING::GRID_SIZE: - settings.setValue ( SETTING_GRID_SIZE, value ); + settings.setValue(SETTING_GRID_SIZE, value); break; default: - Q_ASSERT( false ); + Q_ASSERT(false); break; } - int optionId = static_cast< int >( option ); - if ( mIntegerSet[ optionId ] != value ) + int optionId = static_cast(option); + if (mIntegerSet[optionId] != value) { - mIntegerSet[ optionId ] = value; - emit optionChanged( option ); + mIntegerSet[optionId] = value; + emit optionChanged(option); } } // Set bool value // -void PreferenceManager::set( SETTING option, bool value ) +void PreferenceManager::set(SETTING option, bool value) { - QSettings settings( PENCIL2D, PENCIL2D ); - switch ( option ) + QSettings settings(PENCIL2D, PENCIL2D); + switch (option) { case SETTING::ANTIALIAS: - settings.setValue( SETTING_ANTIALIAS, value ); + settings.setValue(SETTING_ANTIALIAS, value); break; case SETTING::GRID: - settings.setValue( SETTING_SHOW_GRID, value ); + settings.setValue(SETTING_SHOW_GRID, value); break; case SETTING::SHADOW: - settings.setValue ( SETTING_SHADOW, value ); + settings.setValue(SETTING_SHADOW, value); break; case SETTING::PREV_ONION: - settings.setValue ( SETTING_PREV_ONION, value ); + settings.setValue(SETTING_PREV_ONION, value); break; case SETTING::NEXT_ONION: - settings.setValue ( SETTING_NEXT_ONION, value ); + settings.setValue(SETTING_NEXT_ONION, value); break; case SETTING::MULTILAYER_ONION: - settings.setValue( SETTING_MULTILAYER_ONION, value); + settings.setValue(SETTING_MULTILAYER_ONION, value); break; case SETTING::AXIS: - settings.setValue ( SETTING_AXIS, value ); + settings.setValue(SETTING_AXIS, value); break; case SETTING::INVISIBLE_LINES: - settings.setValue ( SETTING_INVISIBLE_LINES, value ); + settings.setValue(SETTING_INVISIBLE_LINES, value); break; case SETTING::OUTLINES: - settings.setValue ( SETTING_OUTLINES, value ); + settings.setValue(SETTING_OUTLINES, value); break; case SETTING::ONION_BLUE: - settings.setValue ( SETTING_ONION_BLUE, value ); + settings.setValue(SETTING_ONION_BLUE, value); break; case SETTING::ONION_RED: - settings.setValue ( SETTING_ONION_RED, value ); + settings.setValue(SETTING_ONION_RED, value); break; case SETTING::TOOL_CURSOR: - settings.setValue ( SETTING_TOOL_CURSOR, value ); + settings.setValue(SETTING_TOOL_CURSOR, value); break; case SETTING::DOTTED_CURSOR: - settings.setValue ( SETTING_DOTTED_CURSOR, value ); + settings.setValue(SETTING_DOTTED_CURSOR, value); break; case SETTING::HIGH_RESOLUTION: - settings.setValue ( SETTING_HIGH_RESOLUTION, value ); + settings.setValue(SETTING_HIGH_RESOLUTION, value); break; case SETTING::AUTO_SAVE: - settings.setValue ( SETTING_AUTO_SAVE, value ); + settings.setValue(SETTING_AUTO_SAVE, value); break; case SETTING::SHORT_SCRUB: - settings.setValue ( SETTING_SHORT_SCRUB, value ); + settings.setValue(SETTING_SHORT_SCRUB, value); break; case SETTING::DRAW_LABEL: - settings.setValue ( SETTING_DRAW_LABEL, value ); + settings.setValue(SETTING_DRAW_LABEL, value); break; case SETTING::QUICK_SIZING: - settings.setValue ( SETTING_QUICK_SIZING, value ); + settings.setValue(SETTING_QUICK_SIZING, value); break; case SETTING::LAYOUT_LOCK: - settings.setValue( SETTING_LAYOUT_LOCK, value ); + settings.setValue(SETTING_LAYOUT_LOCK, value); break; default: - Q_ASSERT( false ); + Q_ASSERT(false); break; } - int optionId = static_cast< int >( option ); - if ( mBooleanSet[ optionId ] != value ) + int optionId = static_cast(option); + if (mBooleanSet[optionId] != value) { - mBooleanSet[ optionId ] = value; - emit optionChanged( option ); + mBooleanSet[optionId] = value; + emit optionChanged(option); } } diff --git a/core_lib/src/managers/preferencemanager.h b/core_lib/src/managers/preferencemanager.h index cf3ea4a0d..c23bd3cdb 100644 --- a/core_lib/src/managers/preferencemanager.h +++ b/core_lib/src/managers/preferencemanager.h @@ -71,29 +71,28 @@ class PreferenceManager : public BaseManager ~PreferenceManager(); virtual bool init() override; - Status load( Object* ) override; - Status save( Object* ) override; + Status load(Object*) override; + Status save(Object*) override; void loadPrefs(); - void set(SETTING option, QString value ); - void set(SETTING option, int value ); - void set(SETTING option, bool value ); + void set(SETTING option, QString value); + void set(SETTING option, int value); + void set(SETTING option, bool value); - void turnOn(SETTING option ); - void turnOff(SETTING option ); - bool isOn(SETTING option ); + void turnOn(SETTING option); + void turnOff(SETTING option); + bool isOn(SETTING option); QString getString(SETTING option); int getInt(SETTING option); Q_SIGNALS: - void optionChanged( SETTING e ); - + void optionChanged(SETTING e); private: - QHash< int, QString > mStringSet; - QHash< int, int > mIntegerSet; - QHash< int, bool > mBooleanSet; + QHash mStringSet; + QHash mIntegerSet; + QHash mBooleanSet; }; #endif // PREFERENCEMANAGER_H From 1a66ae150b5e6c51da6e9e0e2fbc1978e8f6ae0e Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 17 Apr 2018 23:43:19 +1000 Subject: [PATCH 009/184] Delete unused enum --- core_lib/src/interface/scribblearea.cpp | 2 +- core_lib/src/managers/preferencemanager.cpp | 15 +++------------ core_lib/src/managers/preferencemanager.h | 1 - 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index 5ec9e8a1f..7b9cec064 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -1041,7 +1041,7 @@ void ScribbleArea::drawCanvas(int frame, QRect rect) o.bAntiAlias = mPrefs->isOn(SETTING::ANTIALIAS); o.bGrid = mPrefs->isOn(SETTING::GRID); o.nGridSize = mPrefs->getInt(SETTING::GRID_SIZE); - o.bAxis = mPrefs->isOn(SETTING::AXIS); + o.bAxis = false; o.bThinLines = mPrefs->isOn(SETTING::INVISIBLE_LINES); o.bOutlines = mPrefs->isOn(SETTING::OUTLINES); o.nShowAllLayers = mShowAllLayers; diff --git a/core_lib/src/managers/preferencemanager.cpp b/core_lib/src/managers/preferencemanager.cpp index 31fd6be46..7280c9313 100644 --- a/core_lib/src/managers/preferencemanager.cpp +++ b/core_lib/src/managers/preferencemanager.cpp @@ -34,14 +34,14 @@ bool PreferenceManager::init() return true; } -Status PreferenceManager::load( Object* ) +Status PreferenceManager::load(Object*) { return Status::OK; } -Status PreferenceManager::save( Object * ) +Status PreferenceManager::save(Object*) { - return Status::OK; + return Status::OK; } void PreferenceManager::loadPrefs() @@ -57,7 +57,6 @@ void PreferenceManager::loadPrefs() set(SETTING::GRID_SIZE, settings.value(SETTING_GRID_SIZE, 50).toInt()); // General - // set(SETTING::ANTIALIAS, settings.value(SETTING_ANTIALIAS, true).toBool()); set(SETTING::TOOL_CURSOR, settings.value(SETTING_TOOL_CURSOR, true).toBool()); set(SETTING::DOTTED_CURSOR, settings.value(SETTING_DOTTED_CURSOR, true).toBool()); @@ -142,9 +141,6 @@ QString PreferenceManager::getString(SETTING option) return mStringSet.value(optionId); } - -// Set string value -// void PreferenceManager::set(SETTING option, QString value) { QSettings settings(PENCIL2D, PENCIL2D); @@ -171,8 +167,6 @@ void PreferenceManager::set(SETTING option, QString value) } } -// Set int value -// void PreferenceManager::set(SETTING option, int value) { QSettings settings(PENCIL2D, PENCIL2D); @@ -253,9 +247,6 @@ void PreferenceManager::set(SETTING option, bool value) case SETTING::MULTILAYER_ONION: settings.setValue(SETTING_MULTILAYER_ONION, value); break; - case SETTING::AXIS: - settings.setValue(SETTING_AXIS, value); - break; case SETTING::INVISIBLE_LINES: settings.setValue(SETTING_INVISIBLE_LINES, value); break; diff --git a/core_lib/src/managers/preferencemanager.h b/core_lib/src/managers/preferencemanager.h index c23bd3cdb..d8b8d0fdd 100644 --- a/core_lib/src/managers/preferencemanager.h +++ b/core_lib/src/managers/preferencemanager.h @@ -31,7 +31,6 @@ enum class SETTING SHADOW, PREV_ONION, NEXT_ONION, - AXIS, INVISIBLE_LINES, OUTLINES, ONION_BLUE, From 3d847e346133200e8b03d39490876509b4ea21bb Mon Sep 17 00:00:00 2001 From: Martin van Zijl Date: Tue, 6 Mar 2018 11:44:54 +1300 Subject: [PATCH 010/184] Fix "vanishing line" bug in bitmap layers. --- core_lib/src/interface/scribblearea.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index 7b9cec064..580888f13 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -675,7 +675,9 @@ void ScribbleArea::paintBitmapBuffer() int frameNumber = mEditor->currentFrame(); - if (layer->getKeyFrameAt(frameNumber) == nullptr) + // If there is no keyframe at or before the current position, + // just return (since we have nothing to paint on). + if (layer->getLastKeyFrameAtPosition(frameNumber) == nullptr) { updateCurrentFrame(); return; @@ -711,8 +713,10 @@ void ScribbleArea::paintBitmapBuffer() drawCanvas(frameNumber, rect.adjusted(-1, -1, 1, 1)); update(rect); - QPixmapCache::remove(mPixmapCacheKeys[frameNumber]); - mPixmapCacheKeys[frameNumber] = QPixmapCache::Key(); + // Update the cache for the last key-frame. + auto lastKeyFramePosition = mEditor->layers()->LastFrameAtFrame(frameNumber); + QPixmapCache::remove(mPixmapCacheKeys[lastKeyFramePosition]); + mPixmapCacheKeys[lastKeyFramePosition] = QPixmapCache::Key(); layer->setModified(frameNumber, true); mBufferImg->clear(); From 84c591cd5048d79acee8f1b5e49d3aa99705eebf Mon Sep 17 00:00:00 2001 From: Martin van Zijl Date: Tue, 13 Mar 2018 09:08:52 +1300 Subject: [PATCH 011/184] Added options for when drawing on an empty (non-key) frame. Smudge and move tool are still WIP; preference does not apply for them yet. --- app/src/preferencesdialog.cpp | 37 ++++++++++++ app/src/preferencesdialog.h | 1 + app/ui/timelinepage.ui | 65 +++++++++++++++++++- core_lib/src/interface/scribblearea.cpp | 67 +++++++++++++++++++++ core_lib/src/interface/scribblearea.h | 4 ++ core_lib/src/managers/preferencemanager.cpp | 6 ++ core_lib/src/managers/preferencemanager.h | 9 +++ core_lib/src/tool/movetool.cpp | 31 ++++++++++ core_lib/src/tool/polylinetool.cpp | 2 + core_lib/src/tool/smudgetool.cpp | 13 ++++ core_lib/src/tool/smudgetool.h | 3 + core_lib/src/tool/stroketool.cpp | 10 +++ core_lib/src/tool/stroketool.h | 7 +++ core_lib/src/util/pencildef.h | 2 + 14 files changed, 255 insertions(+), 2 deletions(-) diff --git a/app/src/preferencesdialog.cpp b/app/src/preferencesdialog.cpp index 03f0ca949..e0e013d93 100644 --- a/app/src/preferencesdialog.cpp +++ b/app/src/preferencesdialog.cpp @@ -274,6 +274,9 @@ TimelinePage::TimelinePage(QWidget* parent) : connect(ui->frameSize, &QSlider::valueChanged, this, &TimelinePage::frameSizeChange); connect(ui->timelineLength, spinBoxValueChange, this, &TimelinePage::timelineLengthChanged); connect(ui->scrubBox, &QCheckBox::stateChanged, this, &TimelinePage::scrubChange); + connect(ui->radioButtonAddNewKey, &QRadioButton::toggled, this, &TimelinePage::radioButtonToggled); + connect(ui->radioButtonDuplicate, &QRadioButton::toggled, this, &TimelinePage::radioButtonToggled); + connect(ui->radioButtonDrawOnPrev, &QRadioButton::toggled, this, &TimelinePage::radioButtonToggled); } TimelinePage::~TimelinePage() @@ -297,6 +300,24 @@ void TimelinePage::updateValues() ui->timelineLength->setValue(mManager->getInt(SETTING::TIMELINE_SIZE)); if (mManager->getString(SETTING::TIMELINE_SIZE).toInt() <= 0) ui->timelineLength->setValue(240); + + SignalBlocker b4(ui->radioButtonAddNewKey); + SignalBlocker b5(ui->radioButtonDuplicate); + SignalBlocker b6(ui->radioButtonDrawOnPrev); + int action = mManager->getInt(SETTING::DRAW_ON_EMPTY_FRAME_ACTION); + switch (action) { + case CREATE_NEW_KEY: + ui->radioButtonAddNewKey->setChecked(true); + break; + case DUPLICATE_PREVIOUS_KEY: + ui->radioButtonDuplicate->setChecked(true); + break; + case KEEP_DRAWING_ON_PREVIOUS_KEY: + ui->radioButtonDrawOnPrev->setChecked(true); + break; + default: + break; + } } void TimelinePage::timelineLengthChanged(int value) @@ -324,6 +345,22 @@ void TimelinePage::scrubChange(int value) mManager->set(SETTING::SHORT_SCRUB, value != Qt::Unchecked); } +void TimelinePage::radioButtonToggled(bool) +{ + if(ui->radioButtonAddNewKey->isChecked()) + { + mManager->set(SETTING::DRAW_ON_EMPTY_FRAME_ACTION, CREATE_NEW_KEY); + } + else if(ui->radioButtonDuplicate->isChecked()) + { + mManager->set(SETTING::DRAW_ON_EMPTY_FRAME_ACTION, DUPLICATE_PREVIOUS_KEY); + } + else if(ui->radioButtonDrawOnPrev->isChecked()) + { + mManager->set(SETTING::DRAW_ON_EMPTY_FRAME_ACTION, KEEP_DRAWING_ON_PREVIOUS_KEY); + } +} + FilesPage::FilesPage(QWidget* parent) : QWidget(parent), ui(new Ui::FilesPage) diff --git a/app/src/preferencesdialog.h b/app/src/preferencesdialog.h index cfaeed661..718394ab6 100644 --- a/app/src/preferencesdialog.h +++ b/app/src/preferencesdialog.h @@ -135,6 +135,7 @@ public slots: void frameSizeChange(int); void labelChange(bool); void scrubChange(int); + void radioButtonToggled(bool); private: Ui::TimelinePage* ui = nullptr; diff --git a/app/ui/timelinepage.ui b/app/ui/timelinepage.ui index c65c39906..6d2ffb67f 100644 --- a/app/ui/timelinepage.ui +++ b/app/ui/timelinepage.ui @@ -6,8 +6,8 @@ 0 0 - 315 - 262 + 342 + 374 @@ -83,6 +83,67 @@ + + + + Drawing + + + + + + When drawing on an empty frame: + + + + + + + Create a new (blank) key-frame and start drawing on it. + + + Create a new (blank) key-frame + + + true + + + + + + + Duplicate the previous key-frame and start drawing on the duplicate. + + + Duplicate the previous key-frame + + + + + + + Keep drawing on the previous key-frame + + + + + + + + 10 + + + + <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + + true + + + + + + diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index 580888f13..8f3a42680 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -854,6 +854,73 @@ void ScribbleArea::updateCanvasCursor() } +void ScribbleArea::handleDrawingOnEmptyFrame() +{ + auto layer = mEditor->layers()->currentLayer(); + + if(!layer || !layer->isPaintable()) + { + return; + } + + int frameNumber = mEditor->currentFrame(); + auto previousKeyFrame = layer->getLastKeyFrameAtPosition(frameNumber); + + if(layer->getKeyFrameAt(frameNumber) == nullptr) + { + // Drawing on an empty frame; take action based on preference. + int action = mPrefs->getInt(SETTING::DRAW_ON_EMPTY_FRAME_ACTION); + + switch(action) + { + case CREATE_NEW_KEY: + mEditor->addNewKey(); + mEditor->scrubTo(frameNumber); // Refresh timeline. + + // Hack to clear previous frame's content. + if(layer->type() == Layer::BITMAP && previousKeyFrame) + { + auto asBitmapImage = dynamic_cast (previousKeyFrame); + + if(asBitmapImage) + { + drawCanvas(frameNumber, asBitmapImage->bounds()); + } + } + + if(layer->type() == Layer::VECTOR) + { + auto asVectorImage = dynamic_cast (previousKeyFrame); + + if(asVectorImage) + { + auto copy(*asVectorImage); + copy.selectAll(); + + drawCanvas(frameNumber, copy.getSelectionRect().toRect()); + } + } + + break; + case DUPLICATE_PREVIOUS_KEY: + { + if(previousKeyFrame) + { + KeyFrame* dupKey = previousKeyFrame->clone(); + layer->addKeyFrame(frameNumber, dupKey); + mEditor->scrubTo(frameNumber); // Refresh timeline. + } + break; + } + case KEEP_DRAWING_ON_PREVIOUS_KEY: + // No action needed. + break; + default: + break; + } + } +} + void ScribbleArea::paintEvent(QPaintEvent* event) { if (!mMouseInUse || currentTool()->type() == MOVE || currentTool()->type() == HAND || mMouseRightButtonInUse) diff --git a/core_lib/src/interface/scribblearea.h b/core_lib/src/interface/scribblearea.h index 05cecd679..b5af2e4d7 100644 --- a/core_lib/src/interface/scribblearea.h +++ b/core_lib/src/interface/scribblearea.h @@ -179,6 +179,10 @@ public slots: void updateCanvasCursor(); + /// Call this when starting to use a paint tool. Checks whether we are drawing + /// on an empty frame, and if so, takes action according to use preference. + void handleDrawingOnEmptyFrame(); + BitmapImage* mBufferImg = nullptr; // used to pre-draw vector modifications BitmapImage* mStrokeImg = nullptr; // used for brush strokes before they are finalized diff --git a/core_lib/src/managers/preferencemanager.cpp b/core_lib/src/managers/preferencemanager.cpp index 7280c9313..e04252a2c 100644 --- a/core_lib/src/managers/preferencemanager.cpp +++ b/core_lib/src/managers/preferencemanager.cpp @@ -82,6 +82,9 @@ void PreferenceManager::loadPrefs() set(SETTING::DRAW_LABEL, settings.value(SETTING_DRAW_LABEL, false ).toBool()); set(SETTING::LABEL_FONT_SIZE, settings.value(SETTING_LABEL_FONT_SIZE, 12).toInt()); + set( SETTING::DRAW_ON_EMPTY_FRAME_ACTION, settings.value( SETTING_DRAW_ON_EMPTY_FRAME_ACTION, + KEEP_DRAWING_ON_PREVIOUS_KEY).toInt() ); + // Onion Skin set(SETTING::PREV_ONION, settings.value(SETTING_PREV_ONION, false).toBool()); set(SETTING::NEXT_ONION, settings.value(SETTING_NEXT_ONION, false).toBool()); @@ -209,6 +212,9 @@ void PreferenceManager::set(SETTING option, int value) case SETTING::GRID_SIZE: settings.setValue(SETTING_GRID_SIZE, value); break; + case SETTING::DRAW_ON_EMPTY_FRAME_ACTION: + settings.setValue( SETTING_DRAW_ON_EMPTY_FRAME_ACTION, value); + break; default: Q_ASSERT(false); break; diff --git a/core_lib/src/managers/preferencemanager.h b/core_lib/src/managers/preferencemanager.h index d8b8d0fdd..79cabea83 100644 --- a/core_lib/src/managers/preferencemanager.h +++ b/core_lib/src/managers/preferencemanager.h @@ -58,9 +58,18 @@ enum class SETTING MULTILAYER_ONION, LANGUAGE, LAYOUT_LOCK, + DRAW_ON_EMPTY_FRAME_ACTION, COUNT, // COUNT must always be the last one. }; +// Actions for drawing on an empty frame. +enum DrawOnEmptyFrameAction +{ + CREATE_NEW_KEY, + DUPLICATE_PREVIOUS_KEY, + KEEP_DRAWING_ON_PREVIOUS_KEY +}; + class PreferenceManager : public BaseManager { Q_OBJECT diff --git a/core_lib/src/tool/movetool.cpp b/core_lib/src/tool/movetool.cpp index 318c5b889..437c3ba4e 100644 --- a/core_lib/src/tool/movetool.cpp +++ b/core_lib/src/tool/movetool.cpp @@ -130,7 +130,38 @@ void MoveTool::pressOperation(QMouseEvent* event, Layer* layer) QRectF selectionRect = mScribbleArea->myTransformedSelection; if (!selectionRect.isEmpty()) { + // Hack to "carry over" the selected part of the drawing. + // Commented out for now, since it doesn't work right for + // vector layers. + +// bool onEmptyFrame = layer->getKeyFrameAt(mEditor->currentFrame()) == nullptr; +// bool preferCreateNewKey = mEditor->preference()->getInt(SETTING::DRAW_ON_EMPTY_FRAME_ACTION) == CREATE_NEW_KEY; +// bool preferDuplicate = mEditor->preference()->getInt(SETTING::DRAW_ON_EMPTY_FRAME_ACTION) == DUPLICATE_PREVIOUS_KEY; + +// if(onEmptyFrame) +// { +// if(preferCreateNewKey) +// { +// mEditor->copy(); +// mScribbleArea->deleteSelection(); +// } +// else if(preferDuplicate) +// { +// mEditor->copy(); +// } +// } + +// mScribbleArea->handleDrawingOnEmptyFrame(); mEditor->backup(typeName()); + + // Hack to "carry over" the selected part of the drawing. +// if(onEmptyFrame) +// { +// if(preferCreateNewKey || preferDuplicate) +// { +// mEditor->paste(); +// } +// } } if (mScribbleArea->somethingSelected) // there is an area selection diff --git a/core_lib/src/tool/polylinetool.cpp b/core_lib/src/tool/polylinetool.cpp index ae1681939..b2392b617 100644 --- a/core_lib/src/tool/polylinetool.cpp +++ b/core_lib/src/tool/polylinetool.cpp @@ -107,6 +107,8 @@ void PolylineTool::mousePressEvent( QMouseEvent *event ) { if ( layer->type() == Layer::BITMAP || layer->type() == Layer::VECTOR ) { + mScribbleArea->handleDrawingOnEmptyFrame(); + if ( layer->type() == Layer::VECTOR ) { ((LayerVector *)layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0)->deselectAll(); diff --git a/core_lib/src/tool/smudgetool.cpp b/core_lib/src/tool/smudgetool.cpp index ac337e2b0..cad084e6c 100644 --- a/core_lib/src/tool/smudgetool.cpp +++ b/core_lib/src/tool/smudgetool.cpp @@ -92,6 +92,12 @@ void SmudgeTool::setPressure( const bool pressure ) settings.sync(); } +bool SmudgeTool::emptyFrameActionEnabled() +{ + // Disabled till we get it working for vector layers... + return false; +} + QCursor SmudgeTool::cursor() { qDebug() << "smudge tool"; @@ -161,6 +167,13 @@ void SmudgeTool::mousePressEvent(QMouseEvent *event) if (mScribbleArea->mClosestVertices.size() > 0 || mScribbleArea->mClosestCurves.size() > 0) // the user clicks near a vertex or a curve { + // Since startStroke() isn't called, handle empty frame behaviour here. + // Commented out for now - leads to segfault on mouse-release event. +// if(emptyFrameActionEnabled()) +// { +// mScribbleArea->handleDrawingOnEmptyFrame(); +// } + //qDebug() << "closestCurves:" << closestCurves << " | closestVertices" << closestVertices; VectorImage *vectorImage = ((LayerVector *)layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0); diff --git a/core_lib/src/tool/smudgetool.h b/core_lib/src/tool/smudgetool.h index e6f6587de..4aec34fae 100644 --- a/core_lib/src/tool/smudgetool.h +++ b/core_lib/src/tool/smudgetool.h @@ -43,6 +43,9 @@ class SmudgeTool : public StrokeTool void setFeather( const qreal feather ); void setPressure( const bool pressure ); +protected: + bool emptyFrameActionEnabled() override; + private: QPointF mLastBrushPoint; }; diff --git a/core_lib/src/tool/stroketool.cpp b/core_lib/src/tool/stroketool.cpp index 79a047911..ccdefe8c6 100644 --- a/core_lib/src/tool/stroketool.cpp +++ b/core_lib/src/tool/stroketool.cpp @@ -43,6 +43,11 @@ BaseTool( parent ) void StrokeTool::startStroke() { + if(emptyFrameActionEnabled()) + { + mScribbleArea->handleDrawingOnEmptyFrame(); + } + mFirstDraw = true; mLastPixel = getCurrentPixel(); @@ -77,6 +82,11 @@ bool StrokeTool::keyReleaseEvent(QKeyEvent *event) return true; } +bool StrokeTool::emptyFrameActionEnabled() +{ + return true; +} + void StrokeTool::endStroke() { m_pStrokeManager->interpolateEnd(); diff --git a/core_lib/src/tool/stroketool.h b/core_lib/src/tool/stroketool.h index be85103f8..2d0493ced 100644 --- a/core_lib/src/tool/stroketool.h +++ b/core_lib/src/tool/stroketool.h @@ -47,6 +47,13 @@ class StrokeTool : public BaseTool qreal mCurrentWidth = 0.0; qreal mCurrentPressure = 0.5; + /// Whether to enable the "drawing on empty frame" preference. + /// If true, then the user preference is honored. + /// If false, then the stroke is drawn on the previous key-frame (i.e. the + /// "old" Pencil behaviour). + /// Returns true by default. + virtual bool emptyFrameActionEnabled(); + private: QPointF mLastPixel = { 0, 0 }; }; diff --git a/core_lib/src/util/pencildef.h b/core_lib/src/util/pencildef.h index 9a55a7beb..4f10b2f4c 100644 --- a/core_lib/src/util/pencildef.h +++ b/core_lib/src/util/pencildef.h @@ -184,6 +184,8 @@ enum BackgroundStyle #define SETTING_ONION_NEXT_FRAMES_NUM "OnionNextFramesNum" #define SETTING_ONION_TYPE "OnionType" +#define SETTING_DRAW_ON_EMPTY_FRAME_ACTION "DrawOnEmptyFrameAction" + #define SETTING_LANGUAGE "Language" #endif // PENCILDEF_H From d35631351b9c19f506180bc866dc6cc680228478 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Thu, 19 Apr 2018 15:21:32 +1000 Subject: [PATCH 012/184] clang-tidy suggestions --- app/src/exportimagedialog.cpp | 56 +++---- app/src/exportimagedialog.h | 10 +- core_lib/src/interface/basedockwidget.cpp | 2 +- core_lib/src/interface/basedockwidget.h | 4 +- core_lib/src/structure/layer.cpp | 39 ++--- core_lib/src/structure/object.cpp | 27 ++-- core_lib/src/structure/object.h | 8 +- core_lib/src/structure/soundclip.cpp | 29 ++-- core_lib/src/structure/soundclip.h | 16 +- core_lib/src/tool/penciltool.cpp | 180 +++++++++++----------- core_lib/src/tool/penciltool.h | 2 +- core_lib/src/tool/stroketool.h | 2 +- 12 files changed, 190 insertions(+), 185 deletions(-) diff --git a/app/src/exportimagedialog.cpp b/app/src/exportimagedialog.cpp index d88524f3e..8fbb72c1d 100644 --- a/app/src/exportimagedialog.cpp +++ b/app/src/exportimagedialog.cpp @@ -18,22 +18,22 @@ GNU General Public License for more details. #include "exportimagedialog.h" #include "ui_exportimageoptions.h" -ExportImageDialog::ExportImageDialog(QWidget *parent, FileType eFileType) : +ExportImageDialog::ExportImageDialog(QWidget* parent, FileType eFileType) : ImportExportDialog(parent, ImportExportDialog::Export, eFileType), ui(new Ui::ExportImageOptions) { - ui->setupUi( getOptionsGroupBox() ); + ui->setupUi(getOptionsGroupBox()); if (eFileType == FileType::IMAGE_SEQUENCE) { - setWindowTitle( tr( "Export image sequence" ) ); + setWindowTitle(tr("Export image sequence")); } else { - setWindowTitle( tr( "Export image" ) ); + setWindowTitle(tr("Export image")); } - connect( ui->formatComboBox, &QComboBox::currentTextChanged, this, &ExportImageDialog::formatChanged ); - formatChanged( getExportFormat() ); // Make sure file extension matches format combobox + connect(ui->formatComboBox, &QComboBox::currentTextChanged, this, &ExportImageDialog::formatChanged); + formatChanged(getExportFormat()); // Make sure file extension matches format combobox } ExportImageDialog::~ExportImageDialog() @@ -43,55 +43,55 @@ ExportImageDialog::~ExportImageDialog() void ExportImageDialog::setCamerasInfo(const std::vector>& cameraInfo) { - Q_ASSERT(ui->cameraCombo); + Q_ASSERT(ui->cameraCombo); - ui->cameraCombo->clear(); - for (const std::pair& it : cameraInfo) - { - ui->cameraCombo->addItem(it.first, it.second); - } + ui->cameraCombo->clear(); + for (const std::pair& it : cameraInfo) + { + ui->cameraCombo->addItem(it.first, it.second); + } - auto indexChanged = static_cast(&QComboBox::currentIndexChanged); - connect(ui->cameraCombo, indexChanged, this, &ExportImageDialog::cameraComboChanged); + const auto indexChanged = static_cast(&QComboBox::currentIndexChanged); + connect(ui->cameraCombo, indexChanged, this, &ExportImageDialog::cameraComboChanged); - cameraComboChanged(0); + cameraComboChanged(0); } void ExportImageDialog::setExportSize(QSize size) { - ui->imgWidthSpinBox->setValue( size.width() ); - ui->imgHeightSpinBox->setValue( size.height() ); + ui->imgWidthSpinBox->setValue(size.width()); + ui->imgHeightSpinBox->setValue(size.height()); } -QSize ExportImageDialog::getExportSize() +QSize ExportImageDialog::getExportSize() const { - return QSize( ui->imgWidthSpinBox->value(), ui->imgHeightSpinBox->value() ); + return QSize(ui->imgWidthSpinBox->value(), ui->imgHeightSpinBox->value()); } -bool ExportImageDialog::getTransparency() +bool ExportImageDialog::getTransparency() const { return ui->cbTransparency->checkState() == Qt::Checked; } -QString ExportImageDialog::getExportFormat() +QString ExportImageDialog::getExportFormat() const { return ui->formatComboBox->currentText(); } -QString ExportImageDialog::getCameraLayerName() +QString ExportImageDialog::getCameraLayerName() const { - return ui->cameraCombo->currentText(); + return ui->cameraCombo->currentText(); } -void ExportImageDialog::formatChanged(QString format) +void ExportImageDialog::formatChanged(const QString& format) { - setFileExtension( format.toLower() ); + setFileExtension(format.toLower()); } void ExportImageDialog::cameraComboChanged(int index) { - QSize cameraSize = ui->cameraCombo->itemData(index).toSize(); + const QSize cameraSize = ui->cameraCombo->itemData(index).toSize(); - ui->imgWidthSpinBox->setValue(cameraSize.width()); - ui->imgHeightSpinBox->setValue(cameraSize.height()); + ui->imgWidthSpinBox->setValue(cameraSize.width()); + ui->imgHeightSpinBox->setValue(cameraSize.height()); } diff --git a/app/src/exportimagedialog.h b/app/src/exportimagedialog.h index 69de942e3..4a626bdb8 100644 --- a/app/src/exportimagedialog.h +++ b/app/src/exportimagedialog.h @@ -35,13 +35,13 @@ class ExportImageDialog : public ImportExportDialog void setCamerasInfo(const std::vector>& camInfo); void setExportSize( QSize size ); - QSize getExportSize(); - bool getTransparency(); - QString getExportFormat(); - QString getCameraLayerName(); + QSize getExportSize() const; + bool getTransparency() const; + QString getExportFormat() const; + QString getCameraLayerName() const; private slots: - void formatChanged(QString format); + void formatChanged(const QString& format); void cameraComboChanged(int index); private: diff --git a/core_lib/src/interface/basedockwidget.cpp b/core_lib/src/interface/basedockwidget.cpp index 8fe6aeafe..e129d5dfc 100644 --- a/core_lib/src/interface/basedockwidget.cpp +++ b/core_lib/src/interface/basedockwidget.cpp @@ -19,7 +19,7 @@ GNU General Public License for more details. #include "basedockwidget.h" BaseDockWidget::BaseDockWidget(QWidget* pParent) -: QDockWidget(pParent, Qt::Tool ) +: QDockWidget(pParent, Qt::Tool) { } diff --git a/core_lib/src/interface/basedockwidget.h b/core_lib/src/interface/basedockwidget.h index 6aa95de0c..fffbac7c1 100644 --- a/core_lib/src/interface/basedockwidget.h +++ b/core_lib/src/interface/basedockwidget.h @@ -27,14 +27,14 @@ class BaseDockWidget : public QDockWidget { Q_OBJECT protected: - explicit BaseDockWidget( QWidget* pParent ); + explicit BaseDockWidget(QWidget* pParent); virtual ~BaseDockWidget(); public: virtual void initUI() = 0; virtual void updateUI() = 0; - Editor* editor() { return mEditor; } + Editor* editor() const { return mEditor; } void setEditor( Editor* e ) { mEditor = e; } private: diff --git a/core_lib/src/structure/layer.cpp b/core_lib/src/structure/layer.cpp index 2103a2348..ab8465ae6 100644 --- a/core_lib/src/structure/layer.cpp +++ b/core_lib/src/structure/layer.cpp @@ -125,10 +125,7 @@ int Layer::getPreviousFrameNumber(int position, bool isAbsolute) const { return -1; // There is no previous keyframe } - else - { - return prevNumber; - } + return prevNumber; } int Layer::getNextFrameNumber(int position, bool isAbsolute) const @@ -167,7 +164,7 @@ int Layer::getMaxKeyFramePosition() const bool Layer::addNewKeyFrameAt(int position) { if (position <= 0) return false; - + KeyFrame* key = createKeyFrame(position, mObject); return addKeyFrame(position, key); } @@ -311,7 +308,9 @@ Status Layer::save(QString strDataFolder, ProgressCallback progressStep) return Status::OK; } -void Layer::paintTrack(QPainter& painter, TimeLineCells* cells, int x, int y, int width, int height, bool selected, int frameSize) +void Layer::paintTrack(QPainter& painter, TimeLineCells* cells, + int x, int y, int width, int height, + bool selected, int frameSize) { if (mVisible) { @@ -375,7 +374,9 @@ void Layer::paintFrames(QPainter& painter, TimeLineCells* cells, int y, int heig } } -void Layer::paintLabel(QPainter& painter, TimeLineCells* cells, int x, int y, int width, int height, bool selected, int allLayers) +void Layer::paintLabel(QPainter& painter, TimeLineCells* cells, + int x, int y, int width, int height, + bool selected, int allLayers) { Q_UNUSED(cells); painter.setBrush(Qt::lightGray); @@ -384,9 +385,9 @@ void Layer::paintLabel(QPainter& painter, TimeLineCells* cells, int x, int y, in if (mVisible) { - if (allLayers == 0) painter.setBrush(Qt::NoBrush); - if (allLayers == 1) painter.setBrush(Qt::darkGray); - if ((allLayers == 2) || selected) painter.setBrush(Qt::black); + if (allLayers == 0) painter.setBrush(Qt::NoBrush); + if (allLayers == 1) painter.setBrush(Qt::darkGray); + if ((allLayers == 2) || selected) painter.setBrush(Qt::black); } else { @@ -445,7 +446,7 @@ void Layer::setModified(int position, bool modified) bool Layer::isFrameSelected(int position) { - KeyFrame *keyFrame = getKeyFrameWhichCovers(position); + KeyFrame* keyFrame = getKeyFrameWhichCovers(position); if (keyFrame) { return mSelectedFrames_byLast.contains(keyFrame->pos()); @@ -455,7 +456,7 @@ bool Layer::isFrameSelected(int position) void Layer::setFrameSelected(int position, bool isSelected) { - KeyFrame *keyFrame = getKeyFrameWhichCovers(position); + KeyFrame* keyFrame = getKeyFrameWhichCovers(position); if (keyFrame != nullptr) { int startPosition = keyFrame->pos(); @@ -470,7 +471,6 @@ void Layer::setFrameSelected(int position, bool isSelected) // We need to keep the list of selected frames sorted // in order to easily handle their movement std::sort(mSelectedFrames_byPosition.begin(), mSelectedFrames_byPosition.end(), sortAsc); - } else if (!isSelected) { @@ -489,7 +489,8 @@ void Layer::toggleFrameSelected(int position, bool allowMultiple) { bool wasSelected = isFrameSelected(position); - if (!allowMultiple) { + if (!allowMultiple) + { deselectAll(); } @@ -642,11 +643,11 @@ bool Layer::isPaintable() { switch (type()) { - case Layer::BITMAP: - case Layer::VECTOR: + case BITMAP: + case VECTOR: return true; - case Layer::CAMERA: - case Layer::SOUND: + case CAMERA: + case SOUND: return false; default: break; @@ -659,7 +660,7 @@ bool Layer::keyExistsWhichCovers(int frameNumber) return getKeyFrameWhichCovers(frameNumber) != nullptr; } -KeyFrame *Layer::getKeyFrameWhichCovers(int frameNumber) +KeyFrame* Layer::getKeyFrameWhichCovers(int frameNumber) { auto keyFrame = getLastKeyFrameAtPosition(frameNumber); if (keyFrame != nullptr) diff --git a/core_lib/src/structure/object.cpp b/core_lib/src/structure/object.cpp index 69f881c97..3db3e79fb 100644 --- a/core_lib/src/structure/object.cpp +++ b/core_lib/src/structure/object.cpp @@ -91,7 +91,7 @@ bool Object::loadXML(QDomElement docElem, ProgressCallback progressForward) QDomElement element = node.toElement(); // try to convert the node to an element. if (element.tagName() == "layer") { - switch (element.attribute("type").toInt() ) + switch (element.attribute("type").toInt()) { case Layer::BITMAP: addNewBitmapLayer(); break; case Layer::VECTOR: addNewVectorLayer(); break; @@ -158,7 +158,7 @@ void Object::createWorkingDir() QFileInfo fileInfo(mFilePath); strFolderName = fileInfo.completeBaseName(); } - QString strWorkingDir = QDir::tempPath() + const QString strWorkingDir = QDir::tempPath() + "/Pencil2D/" + strFolderName + PFF_TMP_DECOMPRESS_EXT @@ -273,7 +273,7 @@ void Object::deleteLayer(Layer* layer) } } -ColourRef Object::getColour(int i) +ColourRef Object::getColour(int i) const { ColourRef result(Qt::white, "error"); if (i > -1 && i < mPalette.size()) @@ -283,6 +283,12 @@ ColourRef Object::getColour(int i) return result; } +void Object::setColour(int index, QColor newColour) +{ + Q_ASSERT(index >= 0); + mPalette[index].colour = newColour; +} + void Object::addColour(QColor colour) { addColour(ColourRef(colour, "Colour " + QString::number(mPalette.size()))); @@ -295,7 +301,7 @@ bool Object::removeColour(int index) Layer* layer = getLayer(i); if (layer->type() == Layer::VECTOR) { - LayerVector* layerVector = ((LayerVector*)layer); + LayerVector* layerVector = (LayerVector*)layer; if (layerVector->usesColour(index)) return false; } } @@ -304,7 +310,7 @@ bool Object::removeColour(int index) Layer* layer = getLayer(i); if (layer->type() == Layer::VECTOR) { - LayerVector* layerVector = ((LayerVector*)layer); + LayerVector* layerVector = (LayerVector*)layer; layerVector->removeColour(index); } } @@ -498,7 +504,7 @@ bool Object::exportFrames(int frameStart, int frameEnd, QString format, bool transparency, bool antialiasing, - QProgressDialog* progress = NULL, + QProgressDialog* progress = nullptr, int progressMax = 50) { Q_ASSERT(cameraLayer); @@ -530,13 +536,13 @@ bool Object::exportFrames(int frameStart, int frameEnd, for (int currentFrame = frameStart; currentFrame <= frameEnd; currentFrame++) { - if (progress != NULL) + if (progress != nullptr) { int totalFramesToExport = (frameEnd - frameStart) + 1; if (totalFramesToExport != 0) // Avoid dividing by zero. { - progress->setValue((currentFrame - frameStart + 1)*progressMax / totalFramesToExport); - QApplication::processEvents(); // Required to make progress bar update on-screen. + progress->setValue((currentFrame - frameStart + 1) * progressMax / totalFramesToExport); + QApplication::processEvents(); // Required to make progress bar update on-screen. } if (progress->wasCanceled()) @@ -593,7 +599,8 @@ bool Object::exportX(int frameStart, int frameEnd, QTransform view, QSize export { filePath.chop(4); } - if (!xImg.save(filePath + QString::number(page) + ".jpg", "JPG", 60)) { + if (!xImg.save(filePath + QString::number(page) + ".jpg", "JPG", 60)) + { return false; } page++; diff --git a/core_lib/src/structure/object.h b/core_lib/src/structure/object.h index 2a33de96c..dfc115080 100644 --- a/core_lib/src/structure/object.h +++ b/core_lib/src/structure/object.h @@ -82,12 +82,8 @@ class Object : public QObject QString copyFileToDataFolder( QString strFilePath ); // Color palette - ColourRef getColour( int i ); - void setColour( int index, QColor newColour ) - { - Q_ASSERT( index >= 0 ); - mPalette[ index ].colour = newColour; - } + ColourRef getColour( int i ) const; + void setColour(int index, QColor newColour); void addColour( QColor ); void addColour( ColourRef newColour ) { mPalette.append( newColour ); } bool removeColour( int index ); diff --git a/core_lib/src/structure/soundclip.cpp b/core_lib/src/structure/soundclip.cpp index 2c76439b4..9bddcb189 100644 --- a/core_lib/src/structure/soundclip.cpp +++ b/core_lib/src/structure/soundclip.cpp @@ -42,33 +42,33 @@ SoundClip* SoundClip::clone() Status SoundClip::init(const QString& strSoundFile) { - if ( strSoundFile.isEmpty() ) + if (strSoundFile.isEmpty()) { return Status::FAIL; } - setFileName( strSoundFile ); + setFileName(strSoundFile); return Status::OK; } -bool SoundClip::isValid() +bool SoundClip::isValid() const { - if ( fileName().isEmpty() ) + if (fileName().isEmpty()) { return false; } - if ( mPlayer == nullptr ) + if (mPlayer == nullptr) { return false; } - + return true; } -void SoundClip::attachPlayer( SoundPlayer* player ) +void SoundClip::attachPlayer(SoundPlayer* player) { Q_ASSERT( player != nullptr ); - mPlayer.reset( player ); + mPlayer.reset(player); } void SoundClip::detachPlayer() @@ -78,7 +78,7 @@ void SoundClip::detachPlayer() void SoundClip::play() { - if ( mPlayer ) + if (mPlayer) { mPlayer->play(); } @@ -87,13 +87,14 @@ void SoundClip::play() void SoundClip::playFromPosition(int frameNumber, int fps) { int framesIntoSound = frameNumber; - if ( pos() > 1 ) { + if (pos() > 1) + { framesIntoSound = frameNumber - pos(); } - float msPerFrame = ( 1000 / fps ); + float msPerFrame = (1000 / fps); float msIntoSound = framesIntoSound * msPerFrame; - if ( mPlayer ) + if (mPlayer) { mPlayer->setMediaPlayerPosition(msIntoSound); mPlayer->play(); @@ -102,7 +103,7 @@ void SoundClip::playFromPosition(int frameNumber, int fps) void SoundClip::stop() { - if ( mPlayer ) + if (mPlayer) { mPlayer->stop(); } @@ -113,7 +114,7 @@ int64_t SoundClip::duration() const return mDuration; } -void SoundClip::setDuration(const int64_t &duration) +void SoundClip::setDuration(const int64_t& duration) { mDuration = duration; } diff --git a/core_lib/src/structure/soundclip.h b/core_lib/src/structure/soundclip.h index 323f1dbd5..176727988 100644 --- a/core_lib/src/structure/soundclip.h +++ b/core_lib/src/structure/soundclip.h @@ -33,27 +33,27 @@ class SoundClip : public KeyFrame SoundClip* clone() override; - Status init( const QString& strSoundFile ); - bool isValid(); + Status init(const QString& strSoundFile); + bool isValid() const; - void setSoundClipName( const QString& sName ) { mOriginalSoundClipName = sName; } - QString soundClipName() { return mOriginalSoundClipName; } + void setSoundClipName(const QString& sName) { mOriginalSoundClipName = sName; } + QString soundClipName() const { return mOriginalSoundClipName; } - void attachPlayer( SoundPlayer* player ); + void attachPlayer(SoundPlayer* player); void detachPlayer(); - SoundPlayer* player() { return mPlayer.get(); } + SoundPlayer* player() const { return mPlayer.get(); } void play(); void playFromPosition(int frameNumber, int fps); void stop(); int64_t duration() const; - void setDuration(const int64_t &duration); + void setDuration(const int64_t& duration); void updateLength(int fps); private: - std::shared_ptr< SoundPlayer > mPlayer; + std::shared_ptr mPlayer; QString mOriginalSoundClipName; diff --git a/core_lib/src/tool/penciltool.cpp b/core_lib/src/tool/penciltool.cpp index a15ab6970..3cb867bdc 100644 --- a/core_lib/src/tool/penciltool.cpp +++ b/core_lib/src/tool/penciltool.cpp @@ -22,17 +22,15 @@ GNU General Public License for more details. #include "layermanager.h" #include "layervector.h" -#include "layerbitmap.h" #include "colormanager.h" #include "strokemanager.h" -#include "layermanager.h" #include "editor.h" #include "scribblearea.h" #include "blitrect.h" #include "vectorimage.h" -PencilTool::PencilTool( QObject* parent ) : StrokeTool( parent ) +PencilTool::PencilTool(QObject* parent) : StrokeTool(parent) { } @@ -45,10 +43,10 @@ void PencilTool::loadSettings() m_enabledProperties[INTERPOLATION] = true; m_enabledProperties[FILLCONTOUR] = true; - QSettings settings( PENCIL2D, PENCIL2D ); - properties.width = settings.value( "pencilWidth" ).toDouble(); + QSettings settings(PENCIL2D, PENCIL2D); + properties.width = settings.value("pencilWidth").toDouble(); properties.feather = 50; - properties.pressure = settings.value( "pencilPressure" ).toBool(); + properties.pressure = settings.value("pencilPressure").toBool(); properties.inpolLevel = 0; properties.useAA = -1; properties.useFeather = true; @@ -57,14 +55,13 @@ void PencilTool::loadSettings() // properties.invisibility = 1; // properties.preserveAlpha = 0; - if ( properties.width <= 0 ) + if (properties.width <= 0) { // setting the default value to 4 // seems to give great results with pressure on - setWidth( 4 ); - setPressure( 1 ); + setWidth(4); + setPressure(true); } - } void PencilTool::setWidth(const qreal width) @@ -73,46 +70,46 @@ void PencilTool::setWidth(const qreal width) properties.width = width; // Update settings - QSettings settings( PENCIL2D, PENCIL2D ); + QSettings settings(PENCIL2D, PENCIL2D); settings.setValue("pencilWidth", width); settings.sync(); } -void PencilTool::setFeather( const qreal feather ) +void PencilTool::setFeather(const qreal feather) { properties.feather = feather; } -void PencilTool::setUseFeather( const bool usingFeather ) +void PencilTool::setUseFeather(const bool usingFeather) { // Set current property properties.useFeather = usingFeather; // Update settings - QSettings settings( PENCIL2D, PENCIL2D ); + QSettings settings(PENCIL2D, PENCIL2D); settings.setValue("brushUseFeather", usingFeather); settings.sync(); } -void PencilTool::setInvisibility( const bool ) +void PencilTool::setInvisibility(const bool) { // force value properties.invisibility = 1; } -void PencilTool::setPressure( const bool pressure ) +void PencilTool::setPressure(const bool pressure) { // Set current property properties.pressure = pressure; // Update settings - QSettings settings( PENCIL2D, PENCIL2D ); + QSettings settings(PENCIL2D, PENCIL2D); settings.setValue("pencilPressure", pressure); settings.sync(); } -void PencilTool::setPreserveAlpha( const bool preserveAlpha ) +void PencilTool::setPreserveAlpha(const bool preserveAlpha) { // force value Q_UNUSED( preserveAlpha ); @@ -123,7 +120,7 @@ void PencilTool::setInpolLevel(const int level) { properties.inpolLevel = level; - QSettings settings( PENCIL2D, PENCIL2D); + QSettings settings(PENCIL2D, PENCIL2D); settings.setValue("lineInpol", level); settings.sync(); } @@ -132,36 +129,37 @@ void PencilTool::setUseFillContour(const bool useFillContour) { properties.useFillContour = useFillContour; - QSettings settings( PENCIL2D, PENCIL2D); + QSettings settings(PENCIL2D, PENCIL2D); settings.setValue("FillContour", useFillContour); settings.sync(); } QCursor PencilTool::cursor() { - if ( mEditor->preference()->isOn( SETTING::TOOL_CURSOR ) ) + if (mEditor->preference()->isOn(SETTING::TOOL_CURSOR)) { - return QCursor( QPixmap( ":icons/pencil2.png" ), 0, 16 ); + return QCursor(QPixmap(":icons/pencil2.png"), 0, 16); } return Qt::CrossCursor; } -void PencilTool::mousePressEvent( QMouseEvent *event ) +void PencilTool::mousePressEvent(QMouseEvent* event) { mLastBrushPoint = getCurrentPoint(); - if ( event->button() == Qt::LeftButton ) + if (event->button() == Qt::LeftButton) { mScribbleArea->setAllDirty(); startStroke(); //start and appends first stroke - if ( mEditor->layers()->currentLayer()->type() == Layer::BITMAP ) // in case of bitmap, first pixel(mouseDown) is drawn + if (mEditor->layers()->currentLayer()->type() == Layer::BITMAP) + // in case of bitmap, first pixel(mouseDown) is drawn { drawStroke(); } - else if ( mEditor->layers()->currentLayer()->type() == Layer::VECTOR ) + else if (mEditor->layers()->currentLayer()->type() == Layer::VECTOR) { - if ( !mEditor->preference()->isOn(SETTING::INVISIBLE_LINES) ) + if (!mEditor->preference()->isOn(SETTING::INVISIBLE_LINES)) { mScribbleArea->toggleThinLines(); } @@ -172,31 +170,32 @@ void PencilTool::mousePressEvent( QMouseEvent *event ) mLastBrushPoint = getCurrentPoint(); } -void PencilTool::mouseMoveEvent( QMouseEvent *event ) +void PencilTool::mouseMoveEvent(QMouseEvent* event) { Layer* layer = mEditor->layers()->currentLayer(); - if ( layer->type() == Layer::BITMAP || layer->type() == Layer::VECTOR ) + if (layer->type() == Layer::BITMAP || layer->type() == Layer::VECTOR) { - if ( event->buttons() & Qt::LeftButton ) + if (event->buttons() & Qt::LeftButton) { drawStroke(); - if (properties.inpolLevel != m_pStrokeManager->getInpolLevel()) { + if (properties.inpolLevel != m_pStrokeManager->getInpolLevel()) + { m_pStrokeManager->setInpolLevel(properties.inpolLevel); } } } } -void PencilTool::mouseReleaseEvent( QMouseEvent *event ) +void PencilTool::mouseReleaseEvent(QMouseEvent* event) { - if ( event->button() == Qt::LeftButton ) + if (event->button() == Qt::LeftButton) { mEditor->backup(typeName()); Layer* layer = mEditor->layers()->currentLayer(); - if ( mScribbleArea->isLayerPaintable() ) + if (mScribbleArea->isLayerPaintable()) { - qreal distance = QLineF( getCurrentPoint(), mMouseDownPoint ).length(); + qreal distance = QLineF(getCurrentPoint(), mMouseDownPoint).length(); if (distance < 1) { paintAt(mMouseDownPoint); @@ -207,19 +206,19 @@ void PencilTool::mouseReleaseEvent( QMouseEvent *event ) } } - if ( layer->type() == Layer::BITMAP ) + if (layer->type() == Layer::BITMAP) paintBitmapStroke(); - else if (layer->type() == Layer::VECTOR ) - paintVectorStroke( layer ); + else if (layer->type() == Layer::VECTOR) + paintVectorStroke(layer); } endStroke(); } -void PencilTool::adjustPressureSensitiveProperties( qreal pressure, bool mouseDevice ) +void PencilTool::adjustPressureSensitiveProperties(qreal pressure, bool mouseDevice) { mCurrentWidth = properties.width; - if ( properties.pressure && !mouseDevice ) + if (properties.pressure && !mouseDevice) { mCurrentPressure = pressure; } @@ -230,11 +229,11 @@ void PencilTool::adjustPressureSensitiveProperties( qreal pressure, bool mouseDe } // draw a single paint dab at the given location -void PencilTool::paintAt( QPointF point ) +void PencilTool::paintAt(QPointF point) { qDebug() << "Made a single dab at " << point; Layer* layer = mEditor->layers()->currentLayer(); - if ( layer->type() == Layer::BITMAP ) + if (layer->type() == Layer::BITMAP) { qreal opacity = 1.0; mCurrentWidth = properties.width; @@ -248,15 +247,15 @@ void PencilTool::paintAt( QPointF point ) BlitRect rect; - rect.extend( point.toPoint() ); + rect.extend(point.toPoint()); mScribbleArea->drawPencil(point, brushWidth, fixedBrushFeather, mEditor->color()->frontColor(), opacity); - int rad = qRound( brushWidth ) / 2 + 2; - mScribbleArea->refreshBitmap( rect, rad ); + int rad = qRound(brushWidth) / 2 + 2; + mScribbleArea->refreshBitmap(rect, rad); } } @@ -268,11 +267,12 @@ void PencilTool::drawStroke() Layer* layer = mEditor->layers()->currentLayer(); - if ( layer->type() == Layer::BITMAP ) + if (layer->type() == Layer::BITMAP) { qreal opacity = 1.0; mCurrentWidth = properties.width; - if (properties.pressure == true) { + if (properties.pressure == true) + { opacity = mCurrentPressure / 2; mCurrentWidth = properties.width * mCurrentPressure; } @@ -280,58 +280,58 @@ void PencilTool::drawStroke() qreal fixedBrushFeather = properties.feather; qreal brushStep = (0.5 * brushWidth); - brushStep = qMax( 1.0, brushStep ); + brushStep = qMax(1.0, brushStep); BlitRect rect; QPointF a = mLastBrushPoint; QPointF b = getCurrentPoint(); - qreal distance = 4 * QLineF( b, a ).length(); - int steps = qRound( distance / brushStep ); + qreal distance = 4 * QLineF(b, a).length(); + int steps = qRound(distance / brushStep); - for ( int i = 0; i < steps; i++ ) + for (int i = 0; i < steps; i++) { - QPointF point = mLastBrushPoint + ( i + 1 ) * brushStep * ( getCurrentPoint() - mLastBrushPoint ) / distance; - rect.extend( point.toPoint() ); + QPointF point = mLastBrushPoint + (i + 1) * brushStep * (getCurrentPoint() - mLastBrushPoint) / distance; + rect.extend(point.toPoint()); mScribbleArea->drawPencil(point, brushWidth, fixedBrushFeather, mEditor->color()->frontColor(), - opacity ); + opacity); - if ( i == ( steps - 1 ) ) + if (i == (steps - 1)) { mLastBrushPoint = getCurrentPoint(); } } - int rad = qRound( brushWidth ) / 2 + 2; - - mScribbleArea->paintBitmapBufferRect( rect ); - mScribbleArea->refreshBitmap( rect, rad ); + int rad = qRound(brushWidth) / 2 + 2; + mScribbleArea->paintBitmapBufferRect(rect); + mScribbleArea->refreshBitmap(rect, rad); } - else if ( layer->type() == Layer::VECTOR ) + else if (layer->type() == Layer::VECTOR) { properties.useFeather = false; properties.width = 0; - QPen pen( mEditor->color()->frontColor(), - 1, - Qt::DotLine, - Qt::RoundCap, - Qt::RoundJoin ); - - int rad = qRound( ( properties.width / 2 + 2 ) * mEditor->view()->scaling() ); - - if ( p.size() == 4 ) { - QSizeF size( 2, 2 ); - QPainterPath path( p[ 0 ] ); - path.cubicTo( p[ 1 ], - p[ 2 ], - p[ 3 ] ); - mScribbleArea->drawPath( path, pen, Qt::NoBrush, QPainter::CompositionMode_Source ); - mScribbleArea->refreshVector( path.boundingRect().toRect(), rad ); + QPen pen(mEditor->color()->frontColor(), + 1, + Qt::DotLine, + Qt::RoundCap, + Qt::RoundJoin); + + int rad = qRound((properties.width / 2 + 2) * mEditor->view()->scaling()); + + if (p.size() == 4) + { + QSizeF size(2, 2); + QPainterPath path(p[0]); + path.cubicTo(p[1], + p[2], + p[3]); + mScribbleArea->drawPath(path, pen, Qt::NoBrush, QPainter::CompositionMode_Source); + mScribbleArea->refreshVector(path.boundingRect().toRect(), rad); } } } @@ -350,24 +350,25 @@ void PencilTool::paintVectorStroke(Layer* layer) mScribbleArea->clearBitmapBuffer(); qreal tol = mScribbleArea->getCurveSmoothing() / mEditor->view()->scaling(); - BezierCurve curve( mStrokePoints, mStrokePressures, tol ); - curve.setWidth( 0 ); - curve.setFeather( 0 ); - curve.setFilled( false ); - curve.setInvisibility( true ); - curve.setVariableWidth( false ); - curve.setColourNumber( mEditor->color()->frontColorNumber() ); - VectorImage* vectorImage = ( ( LayerVector * )layer )->getLastVectorImageAtFrame( mEditor->currentFrame(), 0 ); + BezierCurve curve(mStrokePoints, mStrokePressures, tol); + curve.setWidth(0); + curve.setFeather(0); + curve.setFilled(false); + curve.setInvisibility(true); + curve.setVariableWidth(false); + curve.setColourNumber(mEditor->color()->frontColorNumber()); + VectorImage* vectorImage = ((LayerVector *)layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0); - vectorImage->addCurve( curve, qAbs( mEditor->view()->scaling() ), properties.vectorMergeEnabled ); + vectorImage->addCurve(curve, qAbs(mEditor->view()->scaling()), properties.vectorMergeEnabled); if (properties.useFillContour == true) { - vectorImage->fillContour( mStrokePoints, - mEditor->color()->frontColorNumber() ); + vectorImage->fillContour(mStrokePoints, + mEditor->color()->frontColorNumber()); } - if (vectorImage->isAnyCurveSelected() || mScribbleArea->somethingSelected) { + if (vectorImage->isAnyCurveSelected() || mScribbleArea->somethingSelected) + { mScribbleArea->deselectAll(); } @@ -377,7 +378,6 @@ void PencilTool::paintVectorStroke(Layer* layer) // TODO: selection doesn't apply on enter or escape mScribbleArea->somethingSelected = true; - mScribbleArea->setModified( mEditor->layers()->currentLayerIndex(), mEditor->currentFrame() ); + mScribbleArea->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame()); mScribbleArea->setAllDirty(); - } diff --git a/core_lib/src/tool/penciltool.h b/core_lib/src/tool/penciltool.h index 640aa1df6..c232c2056 100644 --- a/core_lib/src/tool/penciltool.h +++ b/core_lib/src/tool/penciltool.h @@ -27,7 +27,7 @@ class PencilTool : public StrokeTool { Q_OBJECT public: - explicit PencilTool( QObject *parent = 0 ); + explicit PencilTool(QObject* parent); ToolType type() override { return PENCIL; } void loadSettings() override; QCursor cursor() override; diff --git a/core_lib/src/tool/stroketool.h b/core_lib/src/tool/stroketool.h index 2d0493ced..f225dc2a9 100644 --- a/core_lib/src/tool/stroketool.h +++ b/core_lib/src/tool/stroketool.h @@ -29,7 +29,7 @@ class StrokeTool : public BaseTool Q_OBJECT public: - explicit StrokeTool(QObject* parent = 0); + explicit StrokeTool(QObject* parent); void startStroke(); void drawStroke(); From 8d5435f94287a22bd374b36e1877e1a44afc6b43 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Thu, 19 Apr 2018 15:54:29 +1000 Subject: [PATCH 013/184] Forward declare ColorManager & ViewManager in scribblearea.h --- app/src/displayoptionwidget.cpp | 3 +- app/src/mainwindow2.cpp | 8 +++-- core_lib/src/interface/scribblearea.cpp | 47 +++++++++++++------------ core_lib/src/interface/scribblearea.h | 16 ++++----- core_lib/src/tool/basetool.cpp | 1 + core_lib/src/tool/brushtool.cpp | 1 + core_lib/src/tool/buckettool.cpp | 1 + core_lib/src/tool/erasertool.cpp | 1 + core_lib/src/tool/movetool.cpp | 1 + core_lib/src/tool/penciltool.cpp | 9 +++-- core_lib/src/tool/pentool.cpp | 1 + core_lib/src/tool/polylinetool.cpp | 2 ++ core_lib/src/tool/smudgetool.cpp | 6 ++-- core_lib/src/tool/stroketool.cpp | 1 + 14 files changed, 57 insertions(+), 41 deletions(-) diff --git a/app/src/displayoptionwidget.cpp b/app/src/displayoptionwidget.cpp index 16e902046..4bdbe240d 100644 --- a/app/src/displayoptionwidget.cpp +++ b/app/src/displayoptionwidget.cpp @@ -17,10 +17,11 @@ GNU General Public License for more details. #include "displayoptionwidget.h" #include "ui_displayoption.h" -#include #include #include + #include "preferencemanager.h" +#include "viewmanager.h" #include "scribblearea.h" #include "editor.h" #include "util.h" diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index ee3051aa5..1a78365b5 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -35,14 +35,17 @@ GNU General Public License for more details. #include "pencildef.h" #include "pencilsettings.h" #include "object.h" -#include "filemanager.h" #include "editor.h" + +#include "filemanager.h" #include "colormanager.h" #include "layermanager.h" -#include "layercamera.h" #include "toolmanager.h" #include "playbackmanager.h" #include "soundmanager.h" +#include "viewmanager.h" + +#include "layercamera.h" #include "actioncommands.h" #include "fileformat.h" //contains constants used by Pencil File Format #include "util.h" @@ -57,6 +60,7 @@ GNU General Public License for more details. #include "preferencesdialog.h" #include "timeline.h" #include "toolbox.h" + //#include "preview.h" #include "timeline2.h" #include "errordialog.h" diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index 8f3a42680..2a397d9de 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -30,10 +30,12 @@ GNU General Public License for more details. #include "bitmapimage.h" #include "vectorimage.h" +#include "colormanager.h" #include "toolmanager.h" #include "strokemanager.h" #include "layermanager.h" #include "playbackmanager.h" +#include "viewmanager.h" ScribbleArea::ScribbleArea(QWidget* parent) : QWidget(parent), @@ -59,7 +61,7 @@ bool ScribbleArea::init() connect(mPrefs, &PreferenceManager::optionChanged, this, &ScribbleArea::settingUpdated); - int curveSmoothingLevel = mPrefs->getInt(SETTING::CURVE_SMOOTHING); + const int curveSmoothingLevel = mPrefs->getInt(SETTING::CURVE_SMOOTHING); mCurveSmoothingLevel = curveSmoothingLevel / 20.0; // default value is 1.0 mQuickSizing = mPrefs->isOn(SETTING::QUICK_SIZING); @@ -722,7 +724,7 @@ void ScribbleArea::paintBitmapBuffer() mBufferImg->clear(); } -void ScribbleArea::paintBitmapBufferRect(QRect rect) +void ScribbleArea::paintBitmapBufferRect(const QRect& rect) { if (allowSmudging() || mEditor->playback()->isPlaying()) { @@ -1130,10 +1132,10 @@ void ScribbleArea::drawCanvas(int frame, QRect rect) return; } -void ScribbleArea::setGaussianGradient(QGradient &gradient, QColor colour, qreal opacity, qreal mOffset) +void ScribbleArea::setGaussianGradient(QGradient &gradient, QColor colour, qreal opacity, qreal offset) { - if (mOffset < 0) { mOffset = 0; } - if (mOffset > 100) { mOffset = 100; } + if (offset < 0) { offset = 0; } + if (offset > 100) { offset = 100; } int r = colour.red(); int g = colour.green(); @@ -1143,11 +1145,11 @@ void ScribbleArea::setGaussianGradient(QGradient &gradient, QColor colour, qreal int mainColorAlpha = qRound(a * 255 * opacity); // the more feather (offset), the more softness (opacity) - int alphaAdded = qRound((mainColorAlpha * mOffset) / 100); + int alphaAdded = qRound((mainColorAlpha * offset) / 100); gradient.setColorAt(0.0, QColor(r, g, b, mainColorAlpha - alphaAdded)); gradient.setColorAt(1.0, QColor(r, g, b, 0)); - gradient.setColorAt(1.0 - (mOffset / 100.0), QColor(r, g, b, mainColorAlpha - alphaAdded)); + gradient.setColorAt(1.0 - (offset / 100.0), QColor(r, g, b, mainColorAlpha - alphaAdded)); } void ScribbleArea::drawPen(QPointF thePoint, qreal brushWidth, QColor fillColour, bool useAA) @@ -1168,7 +1170,7 @@ void ScribbleArea::drawBrush(QPointF thePoint, qreal brushWidth, qreal mOffset, QRectF rectangle(thePoint.x() - 0.5 * brushWidth, thePoint.y() - 0.5 * brushWidth, brushWidth, brushWidth); BitmapImage gradientImg; - if (usingFeather == true) + if (usingFeather) { QRadialGradient radialGrad(thePoint, 0.5 * brushWidth); setGaussianGradient(radialGrad, fillColour, opacity, mOffset); @@ -1198,7 +1200,7 @@ void ScribbleArea::flipSelection(bool flipVertical) QTransform _translate = QTransform::fromTranslate(-centerPoints[1].x(), -centerPoints[1].y()); QTransform scale = QTransform::fromScale(-scaleX, scaleY); - if (flipVertical == true) + if (flipVertical) { scale = QTransform::fromScale(scaleX, -scaleY); } @@ -1220,7 +1222,7 @@ void ScribbleArea::blurBrush(BitmapImage *bmiSource_, QPointF srcPoint_, QPointF QRectF trgRect(thePoint_.x() - 0.5 * brushWidth_, thePoint_.y() - 0.5 * brushWidth_, brushWidth_, brushWidth_); BitmapImage bmiSrcClip = bmiSource_->copy(srcRect.toRect()); - BitmapImage bmiTmpClip = bmiSrcClip; // todo: find a shorter way + BitmapImage bmiTmpClip = bmiSrcClip; // TODO: find a shorter way bmiTmpClip.drawRect(srcRect, Qt::NoPen, radialGrad, QPainter::CompositionMode_Source, mPrefs->isOn(SETTING::ANTIALIAS)); bmiSrcClip.bounds().moveTo(trgRect.topLeft().toPoint()); @@ -1237,23 +1239,22 @@ void ScribbleArea::liquifyBrush(BitmapImage *bmiSource_, QPointF srcPoint_, QPoi setGaussianGradient(radialGrad, QColor(255, 255, 255, 255), opacity_, mOffset_); // Create gradient brush - BitmapImage* bmiTmpClip = new BitmapImage; - bmiTmpClip->drawRect(trgRect, Qt::NoPen, radialGrad, QPainter::CompositionMode_Source, mPrefs->isOn(SETTING::ANTIALIAS)); + BitmapImage bmiTmpClip; + bmiTmpClip.drawRect(trgRect, Qt::NoPen, radialGrad, QPainter::CompositionMode_Source, mPrefs->isOn(SETTING::ANTIALIAS)); // Slide texture/pixels of the source image qreal factor, factorGrad; - int xb, yb, xa, ya; - for (yb = bmiTmpClip->bounds().top(); yb < bmiTmpClip->bounds().bottom(); yb++) + for (int yb = bmiTmpClip.top(); yb < bmiTmpClip.bottom(); yb++) { - for (xb = bmiTmpClip->bounds().left(); xb < bmiTmpClip->bounds().right(); xb++) + for (int xb = bmiTmpClip.left(); xb < bmiTmpClip.right(); xb++) { QColor color; - color.setRgba(bmiTmpClip->pixel(xb, yb)); + color.setRgba(bmiTmpClip.pixel(xb, yb)); factorGrad = color.alphaF(); // any from r g b a is ok - xa = xb - factorGrad*delta.x(); - ya = yb - factorGrad*delta.y(); + int xa = xb - factorGrad*delta.x(); + int ya = yb - factorGrad*delta.y(); color.setRgba(bmiSource_->pixel(xa, ya)); factor = color.alphaF(); @@ -1270,15 +1271,15 @@ void ScribbleArea::liquifyBrush(BitmapImage *bmiSource_, QPointF srcPoint_, QPoi color.setBlue(color.blue()*factorGrad); color.setAlpha(255 * factorGrad); // Premultiplied color - bmiTmpClip->setPixel(xb, yb, color.rgba()); + bmiTmpClip.setPixel(xb, yb, color.rgba()); } - else { - bmiTmpClip->setPixel(xb, yb, qRgba(255, 255, 255, 255)); + else + { + bmiTmpClip.setPixel(xb, yb, qRgba(255, 255, 255, 255)); } } } - mBufferImg->paste(bmiTmpClip); - delete bmiTmpClip; + mBufferImg->paste(&bmiTmpClip); } void ScribbleArea::drawPolyline(QPainterPath path, QPen pen, bool useAA) diff --git a/core_lib/src/interface/scribblearea.h b/core_lib/src/interface/scribblearea.h index b5af2e4d7..f960e9797 100644 --- a/core_lib/src/interface/scribblearea.h +++ b/core_lib/src/interface/scribblearea.h @@ -35,17 +35,13 @@ GNU General Public License for more details. #include "bitmapimage.h" #include "colourref.h" #include "vectorselection.h" -#include "colormanager.h" -#include "viewmanager.h" #include "canvaspainter.h" #include "preferencemanager.h" - class Layer; class Editor; class BaseTool; class StrokeManager; -class ColorManager; class ScribbleArea : public QWidget @@ -102,7 +98,7 @@ class ScribbleArea : public QWidget void updateFrame( int frame ); void updateAllFrames(); void updateAllVectorLayersAtCurrentFrame(); - void updateAllVectorLayersAt( int frame ); + void updateAllVectorLayersAt(int frameNumber); bool shouldUpdateAll() const { return mNeedUpdateAll; } void setAllDirty() { mNeedUpdateAll = true; } @@ -115,11 +111,11 @@ class ScribbleArea : public QWidget StrokeManager* getStrokeManager() const { return mStrokeManager.get(); } - Editor* editor() { return mEditor; } + Editor* editor() const { return mEditor; } void floodFillError( int errorType ); - bool isMouseInUse() { return mMouseInUse; } + bool isMouseInUse() const { return mMouseInUse; } signals: void modification( int ); @@ -129,7 +125,7 @@ class ScribbleArea : public QWidget public slots: void clearImage(); void calculateSelectionRect(); - QTransform getSelectionTransformation() { return selectionTransformation; } + QTransform getSelectionTransformation() const { return selectionTransformation; } void calculateSelectionTransformation(); void paintTransformedSelection(); void applyTransformedSelection(); @@ -170,7 +166,7 @@ public slots: void liquifyBrush( BitmapImage *bmiSource_, QPointF srcPoint_, QPointF thePoint_, qreal brushWidth_, qreal offset_, qreal opacity_ ); void paintBitmapBuffer(); - void paintBitmapBufferRect( QRect rect ); + void paintBitmapBufferRect(const QRect& rect); void paintCanvasCursor(QPainter& painter); void clearBitmapBuffer(); void refreshBitmap( const QRectF& rect, int rad ); @@ -240,7 +236,7 @@ public slots: VectorSelection vectorSelection; QTransform selectionTransformation; - PreferenceManager *mPrefs = nullptr; + PreferenceManager* mPrefs = nullptr; QPixmap mCanvas; CanvasPainter mCanvasPainter; diff --git a/core_lib/src/tool/basetool.cpp b/core_lib/src/tool/basetool.cpp index 8713edfa2..ad432f6c7 100644 --- a/core_lib/src/tool/basetool.cpp +++ b/core_lib/src/tool/basetool.cpp @@ -19,6 +19,7 @@ GNU General Public License for more details. #include #include "editor.h" +#include "viewmanager.h" #include "toolmanager.h" #include "scribblearea.h" #include "strokemanager.h" diff --git a/core_lib/src/tool/brushtool.cpp b/core_lib/src/tool/brushtool.cpp index 5cf61a67a..c6ec857fa 100644 --- a/core_lib/src/tool/brushtool.cpp +++ b/core_lib/src/tool/brushtool.cpp @@ -29,6 +29,7 @@ GNU General Public License for more details. #include "colormanager.h" #include "strokemanager.h" #include "layermanager.h" +#include "viewmanager.h" #include "scribblearea.h" #include "blitrect.h" diff --git a/core_lib/src/tool/buckettool.cpp b/core_lib/src/tool/buckettool.cpp index 1db51c1f8..a2008b4e8 100644 --- a/core_lib/src/tool/buckettool.cpp +++ b/core_lib/src/tool/buckettool.cpp @@ -26,6 +26,7 @@ GNU General Public License for more details. #include "layermanager.h" #include "colormanager.h" #include "strokemanager.h" +#include "viewmanager.h" #include "vectorimage.h" #include "editor.h" #include "scribblearea.h" diff --git a/core_lib/src/tool/erasertool.cpp b/core_lib/src/tool/erasertool.cpp index 84463ebdf..80dc38ba8 100644 --- a/core_lib/src/tool/erasertool.cpp +++ b/core_lib/src/tool/erasertool.cpp @@ -25,6 +25,7 @@ GNU General Public License for more details. #include "scribblearea.h" #include "strokemanager.h" #include "layermanager.h" +#include "viewmanager.h" #include "layervector.h" #include "vectorimage.h" diff --git a/core_lib/src/tool/movetool.cpp b/core_lib/src/tool/movetool.cpp index 437c3ba4e..f22cd2eec 100644 --- a/core_lib/src/tool/movetool.cpp +++ b/core_lib/src/tool/movetool.cpp @@ -21,6 +21,7 @@ GNU General Public License for more details. #include "editor.h" #include "toolmanager.h" +#include "viewmanager.h" #include "scribblearea.h" #include "layervector.h" #include "layermanager.h" diff --git a/core_lib/src/tool/penciltool.cpp b/core_lib/src/tool/penciltool.cpp index 3cb867bdc..3fcf395af 100644 --- a/core_lib/src/tool/penciltool.cpp +++ b/core_lib/src/tool/penciltool.cpp @@ -21,12 +21,15 @@ GNU General Public License for more details. #include #include "layermanager.h" -#include "layervector.h" #include "colormanager.h" #include "strokemanager.h" +#include "viewmanager.h" +#include "preferencemanager.h" + #include "editor.h" #include "scribblearea.h" #include "blitrect.h" +#include "layervector.h" #include "vectorimage.h" @@ -271,7 +274,7 @@ void PencilTool::drawStroke() { qreal opacity = 1.0; mCurrentWidth = properties.width; - if (properties.pressure == true) + if (properties.pressure) { opacity = mCurrentPressure / 2; mCurrentWidth = properties.width * mCurrentPressure; @@ -361,7 +364,7 @@ void PencilTool::paintVectorStroke(Layer* layer) vectorImage->addCurve(curve, qAbs(mEditor->view()->scaling()), properties.vectorMergeEnabled); - if (properties.useFillContour == true) + if (properties.useFillContour) { vectorImage->fillContour(mStrokePoints, mEditor->color()->frontColorNumber()); diff --git a/core_lib/src/tool/pentool.cpp b/core_lib/src/tool/pentool.cpp index 7fd594c95..05c7da5ff 100644 --- a/core_lib/src/tool/pentool.cpp +++ b/core_lib/src/tool/pentool.cpp @@ -23,6 +23,7 @@ GNU General Public License for more details. #include "colormanager.h" #include "strokemanager.h" #include "layermanager.h" +#include "viewmanager.h" #include "editor.h" #include "scribblearea.h" #include "blitrect.h" diff --git a/core_lib/src/tool/polylinetool.cpp b/core_lib/src/tool/polylinetool.cpp index b2392b617..8a763fbfe 100644 --- a/core_lib/src/tool/polylinetool.cpp +++ b/core_lib/src/tool/polylinetool.cpp @@ -22,6 +22,8 @@ GNU General Public License for more details. #include "strokemanager.h" #include "layermanager.h" +#include "colormanager.h" +#include "viewmanager.h" #include "layervector.h" #include "layerbitmap.h" diff --git a/core_lib/src/tool/smudgetool.cpp b/core_lib/src/tool/smudgetool.cpp index cad084e6c..9567f8413 100644 --- a/core_lib/src/tool/smudgetool.cpp +++ b/core_lib/src/tool/smudgetool.cpp @@ -20,11 +20,13 @@ GNU General Public License for more details. #include "vectorimage.h" #include "editor.h" #include "scribblearea.h" + #include "layermanager.h" -#include "colormanager.h" +#include "strokemanager.h" +#include "viewmanager.h" + #include "layerbitmap.h" #include "layervector.h" -#include "strokemanager.h" #include "blitrect.h" SmudgeTool::SmudgeTool(QObject *parent) : diff --git a/core_lib/src/tool/stroketool.cpp b/core_lib/src/tool/stroketool.cpp index ccdefe8c6..5c37d8bf1 100644 --- a/core_lib/src/tool/stroketool.cpp +++ b/core_lib/src/tool/stroketool.cpp @@ -19,6 +19,7 @@ GNU General Public License for more details. #include "scribblearea.h" #include "strokemanager.h" +#include "viewmanager.h" #include "editor.h" #ifdef Q_OS_MAC From 1c8530ade2a2c23dfd116ef40626f5481ea729b4 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Thu, 19 Apr 2018 15:56:24 +1000 Subject: [PATCH 014/184] Delete unused functions: getView(), getViewRect() of ScribbleArea --- core_lib/src/interface/scribblearea.cpp | 34 ------------------------- core_lib/src/interface/scribblearea.h | 2 -- 2 files changed, 36 deletions(-) diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index 2a397d9de..6f00a94ac 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -1297,40 +1297,6 @@ void ScribbleArea::drawPolyline(QPainterPath path, QPen pen, bool useAA) /************************************************************************************/ // view handling -QTransform ScribbleArea::getView() -{ - Layer* layer = mEditor->layers()->currentLayer(); - if (layer == NULL) - { - Q_ASSERT(false); - return QTransform(); // TODO: error - } - - if (layer->type() == Layer::CAMERA) - { - return ((LayerCamera *)layer)->getViewAtFrame(mEditor->currentFrame()); - } - else - { - return mEditor->view()->getView(); - } -} - -QRectF ScribbleArea::getViewRect() -{ - QRectF rect = QRectF(-width() / 2, -height() / 2, width(), height()); - Layer* layer = mEditor->layers()->currentLayer(); - if (layer == NULL) { return rect; } - if (layer->type() == Layer::CAMERA) - { - return ((LayerCamera *)layer)->getViewRect(); - } - else - { - return rect; - } -} - QRectF ScribbleArea::getCameraRect() { return mCanvasPainter.getCameraRect(); diff --git a/core_lib/src/interface/scribblearea.h b/core_lib/src/interface/scribblearea.h index f960e9797..0b178da13 100644 --- a/core_lib/src/interface/scribblearea.h +++ b/core_lib/src/interface/scribblearea.h @@ -89,8 +89,6 @@ class ScribbleArea : public QWidget MoveMode getMoveMode() const { return mMoveMode; } void setMoveMode( MoveMode moveMode ) { mMoveMode = moveMode; } - QTransform getView(); - QRectF getViewRect(); QRectF getCameraRect(); QPointF getCentralPoint(); From 2a854081fd18956391c70a28e6587da575441c6f Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Thu, 19 Apr 2018 16:15:50 +1000 Subject: [PATCH 015/184] clang-tidy suggestions --- app/src/colordictionary.h | 7 ++++++- app/src/colorpalettewidget.cpp | 13 ++++--------- app/src/colorwheel.cpp | 3 +-- app/src/colorwheel.h | 10 +++++----- app/src/main.cpp | 3 +-- app/src/mainwindow2.cpp | 4 ++-- app/src/mainwindow2.h | 2 +- app/src/pencilapplication.h | 2 +- app/src/shortcutfilter.h | 2 +- app/src/timeline2.h | 2 +- core_lib/src/external/win32/win32.cpp | 4 ++-- core_lib/src/tool/basetool.h | 4 ++-- core_lib/src/tool/erasertool.cpp | 6 +++--- core_lib/src/tool/penciltool.cpp | 1 - core_lib/src/tool/pentool.cpp | 2 +- core_lib/src/tool/polylinetool.cpp | 2 +- core_lib/src/tool/smudgetool.cpp | 4 ++-- core_lib/src/tool/smudgetool.h | 18 +++++++++--------- tests/src/main.cpp | 1 - 19 files changed, 43 insertions(+), 47 deletions(-) diff --git a/app/src/colordictionary.h b/app/src/colordictionary.h index 140bb3d5e..543050f4d 100644 --- a/app/src/colordictionary.h +++ b/app/src/colordictionary.h @@ -1,5 +1,8 @@ +#ifndef _COLOR_DICTIONARY_H_ +#define _COLOR_DICTIONARY_H_ + // Initialize NBS/ISCC Color dictionary, John Foster version (http://tx4.us/nbs-iscc.htm), converted to CIE L*u*v with D65 white point and rounded. const int dictSize = 267; @@ -543,4 +546,6 @@ static const QString nameDict[dictSize] = QObject::tr("Medium Gray"), QObject::tr("Dark Gray"), QObject::tr("Black") -}; \ No newline at end of file +}; + +#endif \ No newline at end of file diff --git a/app/src/colorpalettewidget.cpp b/app/src/colorpalettewidget.cpp index 4aa022948..301d2e2a9 100644 --- a/app/src/colorpalettewidget.cpp +++ b/app/src/colorpalettewidget.cpp @@ -120,13 +120,10 @@ void ColorPaletteWidget::refreshColorList() swatchPainter.end(); QPixmap colourSwatch; - QListWidgetItem* colourItem; - ColourRef colourRef; for (int i = 0; i < editor()->object()->getColourCount(); i++) { - colourRef = editor()->object()->getColour(i); - - colourItem = new QListWidgetItem(ui->colorListWidget); + const ColourRef colourRef = editor()->object()->getColour(i); + QListWidgetItem* colourItem = new QListWidgetItem(ui->colorListWidget); if (ui->colorListWidget->viewMode() != QListView::IconMode) { @@ -356,10 +353,9 @@ QString ColorPaletteWidget::getDefaultColorName(QColor c) { // The color is grayscale so only compare to gray centroids so there is no 'false hue' qreal minDist = pow(colorDict[dictSize - 5][0] - l, 2) + pow(colorDict[dictSize - 5][1] - u, 2) + pow(colorDict[dictSize - 5][2] - v, 2); - qreal curDist; for (int i = dictSize - 4; i < dictSize; i++) { - curDist = pow(colorDict[i][0] - l, 2) + pow(colorDict[i][1] - u, 2) + pow(colorDict[i][2] - v, 2); + qreal curDist = pow(colorDict[i][0] - l, 2) + pow(colorDict[i][1] - u, 2) + pow(colorDict[i][2] - v, 2); if (curDist < minDist) { minDist = curDist; @@ -370,10 +366,9 @@ QString ColorPaletteWidget::getDefaultColorName(QColor c) else { qreal minDist = pow(colorDict[0][0] - l, 2) + pow(colorDict[0][1] - u, 2) + pow(colorDict[0][2] - v, 2); - qreal curDist; for (int i = 1; i < dictSize; i++) { - curDist = pow(colorDict[i][0] - l, 2) + pow(colorDict[i][1] - u, 2) + pow(colorDict[i][2] - v, 2); + qreal curDist = pow(colorDict[i][0] - l, 2) + pow(colorDict[i][1] - u, 2) + pow(colorDict[i][2] - v, 2); if (curDist < minDist) { minDist = curDist; diff --git a/app/src/colorwheel.cpp b/app/src/colorwheel.cpp index 9c2613ddf..3139391b1 100644 --- a/app/src/colorwheel.cpp +++ b/app/src/colorwheel.cpp @@ -313,13 +313,12 @@ void ColorWheel::drawSquareImage(const int &hue) qreal m2 = (height() / 2) - (ir / qSqrt(2)); QImage square(255, 255, QImage::Format_ARGB32_Premultiplied); - QColor color; for (int i = 0; i < 255; ++i) { for (int j = 0; j < 255; ++j) { - color = QColor::fromHsv(hue, i, 255 - j); + QColor color = QColor::fromHsv(hue, i, 255 - j); QRgb rgb = qRgb(color.red(), color.green(), color.blue()); square.setPixel(i, j, rgb); } diff --git a/app/src/colorwheel.h b/app/src/colorwheel.h index 714936a8c..10630c95e 100644 --- a/app/src/colorwheel.h +++ b/app/src/colorwheel.h @@ -36,11 +36,11 @@ public slots: void setColor(const QColor& color); protected: - void mousePressEvent(QMouseEvent*); - void mouseMoveEvent(QMouseEvent*); - void mouseReleaseEvent(QMouseEvent*); - void resizeEvent(QResizeEvent*); - void paintEvent(QPaintEvent*); + void mousePressEvent(QMouseEvent*) override; + void mouseMoveEvent(QMouseEvent*) override; + void mouseReleaseEvent(QMouseEvent*) override; + void resizeEvent(QResizeEvent*) override; + void paintEvent(QPaintEvent*) override; private: void changeColor(const QColor&); diff --git a/app/src/main.cpp b/app/src/main.cpp index 01982b690..2448d2224 100644 --- a/app/src/main.cpp +++ b/app/src/main.cpp @@ -269,7 +269,6 @@ int handleArguments( PencilApplication& app ) format = "PNG"; } - bool asMovie; QMap formatMapping; formatMapping[ "PNG" ] = false; formatMapping[ "JPG" ] = false; @@ -280,7 +279,7 @@ int handleArguments( PencilApplication& app ) formatMapping[ "GIF" ] = true; formatMapping[ "WEBM" ] = true; formatMapping[ "APNG" ] = true; - asMovie = formatMapping[format]; + bool asMovie = formatMapping[format]; if ( asMovie ) { diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index 1a78365b5..364e6b36b 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -976,7 +976,7 @@ void MainWindow2::clearKeyboardShortcuts() } } -void MainWindow2::undoActSetText(void) +void MainWindow2::undoActSetText() { if (mEditor->mBackupIndex < 0) { @@ -1005,7 +1005,7 @@ void MainWindow2::undoActSetText(void) } } -void MainWindow2::undoActSetEnabled(void) +void MainWindow2::undoActSetEnabled() { ui->actionUndo->setEnabled(true); ui->actionRedo->setEnabled(true); diff --git a/app/src/mainwindow2.h b/app/src/mainwindow2.h index e7b51d4b7..6933c0efc 100644 --- a/app/src/mainwindow2.h +++ b/app/src/mainwindow2.h @@ -136,7 +136,7 @@ private slots: RecentFileMenu* mRecentFileMenu = nullptr; PreferencesDialog* mPrefDialog = nullptr; //PreviewWidget* mPreview = nullptr; - TimeLine* mTimeLine; // be public temporary + TimeLine* mTimeLine = nullptr; // be public temporary // backup BackupElement* mBackupAtSave = nullptr; diff --git a/app/src/pencilapplication.h b/app/src/pencilapplication.h index 308d5b007..8e94d382d 100644 --- a/app/src/pencilapplication.h +++ b/app/src/pencilapplication.h @@ -27,7 +27,7 @@ class PencilApplication : public QApplication public: PencilApplication(int &argc, char **argv); - bool event(QEvent* event); + bool event(QEvent* event) override; void emitOpenFileRequest(); signals: diff --git a/app/src/shortcutfilter.h b/app/src/shortcutfilter.h index 68ab036ff..cce3fe4ad 100644 --- a/app/src/shortcutfilter.h +++ b/app/src/shortcutfilter.h @@ -27,7 +27,7 @@ class ShortcutFilter : public QObject public: ShortcutFilter(ScribbleArea* scribbleArea, QObject* parent); protected: - bool eventFilter(QObject* obj, QEvent* event); + bool eventFilter(QObject* obj, QEvent* event) override; ScribbleArea* mScribbleArea = nullptr; }; diff --git a/app/src/timeline2.h b/app/src/timeline2.h index 82236bd71..77bb25a92 100644 --- a/app/src/timeline2.h +++ b/app/src/timeline2.h @@ -17,9 +17,9 @@ GNU General Public License for more details. #ifndef TIMELINE2_H #define TIMELINE2_H -#include #include "basedockwidget.h" + namespace Ui { class Timeline2; } diff --git a/core_lib/src/external/win32/win32.cpp b/core_lib/src/external/win32/win32.cpp index c5eef7d11..45550ecb8 100644 --- a/core_lib/src/external/win32/win32.cpp +++ b/core_lib/src/external/win32/win32.cpp @@ -87,8 +87,8 @@ void Editor::importMovie( QString filePath, int fps ) QDir dir( tempPath ); QStringList filtername( "*.*" ); QStringList entries = dir.entryList( filtername, QDir::Files, QDir::Type ); - for ( int i = 0; i < entries.size(); i++ ) - dir.remove( entries[ i ] ); + for ( int e = 0; e < entries.size(); e++ ) + dir.remove( entries[ e ] ); } else { diff --git a/core_lib/src/tool/basetool.h b/core_lib/src/tool/basetool.h index c27ee25d0..7dae88fde 100644 --- a/core_lib/src/tool/basetool.h +++ b/core_lib/src/tool/basetool.h @@ -37,7 +37,7 @@ class Properties public: qreal width = 1.f; qreal feather = 1.f; - bool pressure = 1; + bool pressure = true; int invisibility = 0; int preserveAlpha = 0; bool vectorMergeEnabled = false; @@ -46,7 +46,7 @@ class Properties int useAA = 0; int inpolLevel = 0; qreal tolerance = 0; - bool useFillContour = 0; + bool useFillContour = false; }; const int ON = 1; diff --git a/core_lib/src/tool/erasertool.cpp b/core_lib/src/tool/erasertool.cpp index 80dc38ba8..94fd99916 100644 --- a/core_lib/src/tool/erasertool.cpp +++ b/core_lib/src/tool/erasertool.cpp @@ -63,7 +63,7 @@ void EraserTool::loadSettings() { setWidth(25); setFeather(50); - setPressure(1); + setPressure(true); } } @@ -285,8 +285,8 @@ void EraserTool::drawStroke() QPen pen( Qt::white, brushWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin ); int rad = qRound( ( brushWidth / 2 + 2 ) * mEditor->view()->scaling() ); - if ( p.size() == 4 ) { - QSizeF size( 2, 2 ); + if ( p.size() == 4 ) + { QPainterPath path( p[ 0 ] ); path.cubicTo( p[ 1 ], p[ 2 ], diff --git a/core_lib/src/tool/penciltool.cpp b/core_lib/src/tool/penciltool.cpp index 3fcf395af..b9f56c040 100644 --- a/core_lib/src/tool/penciltool.cpp +++ b/core_lib/src/tool/penciltool.cpp @@ -328,7 +328,6 @@ void PencilTool::drawStroke() if (p.size() == 4) { - QSizeF size(2, 2); QPainterPath path(p[0]); path.cubicTo(p[1], p[2], diff --git a/core_lib/src/tool/pentool.cpp b/core_lib/src/tool/pentool.cpp index 05c7da5ff..d65796e02 100644 --- a/core_lib/src/tool/pentool.cpp +++ b/core_lib/src/tool/pentool.cpp @@ -54,7 +54,7 @@ void PenTool::loadSettings() if ( properties.width <= 0 ) { setWidth(1.5); - setPressure(1); + setPressure(true); } mCurrentWidth = properties.width; diff --git a/core_lib/src/tool/polylinetool.cpp b/core_lib/src/tool/polylinetool.cpp index 8a763fbfe..0a899758c 100644 --- a/core_lib/src/tool/polylinetool.cpp +++ b/core_lib/src/tool/polylinetool.cpp @@ -50,7 +50,7 @@ void PolylineTool::loadSettings() properties.width = settings.value( "polyLineWidth" ).toDouble(); properties.feather = -1; - properties.pressure = 0; + properties.pressure = false; properties.invisibility = OFF; properties.preserveAlpha = OFF; properties.useAA = settings.value( "brushAA").toBool(); diff --git a/core_lib/src/tool/smudgetool.cpp b/core_lib/src/tool/smudgetool.cpp index 9567f8413..2679b4570 100644 --- a/core_lib/src/tool/smudgetool.cpp +++ b/core_lib/src/tool/smudgetool.cpp @@ -49,7 +49,7 @@ void SmudgeTool::loadSettings() QSettings settings( PENCIL2D, PENCIL2D ); properties.width = settings.value("smudgeWidth").toDouble(); properties.feather = settings.value("smudgeFeather").toDouble(); - properties.pressure = 0; + properties.pressure = false; properties.inpolLevel = -1; // First run @@ -57,7 +57,7 @@ void SmudgeTool::loadSettings() { setWidth(25); setFeather(200); - setPressure(0); + setPressure(false); } } diff --git a/core_lib/src/tool/smudgetool.h b/core_lib/src/tool/smudgetool.h index 4aec34fae..60b522b1f 100644 --- a/core_lib/src/tool/smudgetool.h +++ b/core_lib/src/tool/smudgetool.h @@ -25,16 +25,16 @@ class SmudgeTool : public StrokeTool Q_OBJECT public: explicit SmudgeTool(QObject *parent = 0); - ToolType type(); + ToolType type() override; uint toolMode; // 0=normal/smooth 1=smudge - todo: move to basetool? could be useful - void loadSettings(); - QCursor cursor(); - - void mousePressEvent(QMouseEvent *); - void mouseReleaseEvent(QMouseEvent *); - void mouseMoveEvent(QMouseEvent *); - bool keyPressEvent(QKeyEvent *); - bool keyReleaseEvent(QKeyEvent *); + void loadSettings() override; + QCursor cursor() override; + + void mousePressEvent(QMouseEvent *) override; + void mouseReleaseEvent(QMouseEvent *) override; + void mouseMoveEvent(QMouseEvent *) override; + bool keyPressEvent(QKeyEvent *) override; + bool keyReleaseEvent(QKeyEvent *) override; void adjustPressureSensitiveProperties(qreal pressure, bool mouseDevice); void drawStroke(); diff --git a/tests/src/main.cpp b/tests/src/main.cpp index 75746f93c..a3d6e64d8 100644 --- a/tests/src/main.cpp +++ b/tests/src/main.cpp @@ -13,7 +13,6 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ -#include #define CATCH_CONFIG_RUNNER #include "catch.hpp" From af3c699b7423ed680174ac46157ada306ab41bf4 Mon Sep 17 00:00:00 2001 From: CandyFace Date: Sun, 22 Apr 2018 19:17:49 +0200 Subject: [PATCH 016/184] Disable onion skin while playing --- app/src/mainwindow2.cpp | 2 ++ core_lib/src/canvaspainter.cpp | 2 ++ core_lib/src/canvaspainter.h | 1 + core_lib/src/interface/scribblearea.cpp | 1 + core_lib/src/interface/timecontrols.cpp | 10 +--------- core_lib/src/interface/timecontrols.h | 1 + core_lib/src/interface/timeline.cpp | 1 + core_lib/src/interface/timeline.h | 1 + 8 files changed, 10 insertions(+), 9 deletions(-) diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index 364e6b36b..e17516448 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -292,6 +292,7 @@ void MainWindow2::createMenus() connect(pPlaybackManager, &PlaybackManager::rangedPlaybackStateChanged, mTimeLine, &TimeLine::setRangeState); connect(pPlaybackManager, &PlaybackManager::playStateChanged, mTimeLine, &TimeLine::setPlaying); connect(pPlaybackManager, &PlaybackManager::playStateChanged, this, &MainWindow2::changePlayState); + connect(pPlaybackManager, &PlaybackManager::playStateChanged, mEditor, &Editor::updateCurrentFrame); connect(ui->actionAdd_Frame, &QAction::triggered, mCommands, &ActionCommands::addNewKey); connect(ui->actionRemove_Frame, &QAction::triggered, mCommands, &ActionCommands::removeKey); @@ -1073,6 +1074,7 @@ void MainWindow2::makeConnections(Editor* pEditor, TimeLine* pTimeline) connect(pTimeline, &TimeLine::newCameraLayer, mCommands, &ActionCommands::addNewCameraLayer); connect(pTimeline, &TimeLine::toogleAbsoluteOnionClick, pEditor, &Editor::toogleOnionSkinType); + connect(mTimeLine, &TimeLine::playButtonTriggered, mCommands, &ActionCommands::PlayStop); connect(pEditor->layers(), &LayerManager::currentLayerChanged, pTimeline, &TimeLine::updateUI); connect(pEditor->layers(), &LayerManager::layerCountChanged, pTimeline, &TimeLine::updateUI); diff --git a/core_lib/src/canvaspainter.cpp b/core_lib/src/canvaspainter.cpp index 1e85c68a1..04e1ef176 100644 --- a/core_lib/src/canvaspainter.cpp +++ b/core_lib/src/canvaspainter.cpp @@ -108,6 +108,8 @@ void CanvasPainter::paintBackground() void CanvasPainter::paintOnionSkin(QPainter& painter) { + if (mOptions.isPlaying) { return; } + Layer* layer = mObject->getLayer(mCurrentLayerIndex); if (layer->visible() == false) diff --git a/core_lib/src/canvaspainter.h b/core_lib/src/canvaspainter.h index b212cce30..78158b26c 100644 --- a/core_lib/src/canvaspainter.h +++ b/core_lib/src/canvaspainter.h @@ -49,6 +49,7 @@ struct CanvasPainterOptions int nShowAllLayers = 3; bool bIsOnionAbsolute = false; float scaling = 1.0f; + bool isPlaying = false; }; diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index 6f00a94ac..3ff731cc6 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -1120,6 +1120,7 @@ void ScribbleArea::drawCanvas(int frame, QRect rect) o.nShowAllLayers = mShowAllLayers; o.bIsOnionAbsolute = (mPrefs->getString(SETTING::ONION_TYPE) == "absolute"); o.scaling = mEditor->view()->scaling(); + o.isPlaying = mEditor->playback()->isPlaying() ? true : false; mCanvasPainter.setOptions(o); mCanvasPainter.setCanvas(&mCanvas); diff --git a/core_lib/src/interface/timecontrols.cpp b/core_lib/src/interface/timecontrols.cpp index de67c88d0..ed87e63bb 100644 --- a/core_lib/src/interface/timecontrols.cpp +++ b/core_lib/src/interface/timecontrols.cpp @@ -176,15 +176,7 @@ void TimeControls::makeConnections() void TimeControls::playButtonClicked() { - if (mEditor->playback()->isPlaying()) - { - mEditor->playback()->stop(); - } - else - { - mEditor->playback()->play(); - } - updatePlayState(); + emit playButtonTriggered(); } void TimeControls::updatePlayState() diff --git a/core_lib/src/interface/timecontrols.h b/core_lib/src/interface/timecontrols.h index 0cf08bee4..7038283c7 100644 --- a/core_lib/src/interface/timecontrols.h +++ b/core_lib/src/interface/timecontrols.h @@ -47,6 +47,7 @@ class TimeControls : public QToolBar Q_SIGNALS: void soundClick(bool); void fpsClick(int); + void playButtonTriggered(); public slots: void toggleLoop(bool); diff --git a/core_lib/src/interface/timeline.cpp b/core_lib/src/interface/timeline.cpp index b580142aa..323d2197a 100644 --- a/core_lib/src/interface/timeline.cpp +++ b/core_lib/src/interface/timeline.cpp @@ -203,6 +203,7 @@ void TimeLine::initUI() connect(mTimeControls, &TimeControls::soundClick, this, &TimeLine::soundClick); connect(mTimeControls, &TimeControls::fpsClick, this, &TimeLine::fpsClick); connect(mTimeControls, &TimeControls::fpsClick, this, &TimeLine::updateLength); + connect(mTimeControls, &TimeControls::playButtonTriggered, this, &TimeLine::playButtonTriggered); connect(newBitmapLayerAct, &QAction::triggered, this, &TimeLine::newBitmapLayer); connect(newVectorLayerAct, &QAction::triggered, this, &TimeLine::newVectorLayer); diff --git a/core_lib/src/interface/timeline.h b/core_lib/src/interface/timeline.h index 023e4366e..7085ffb47 100644 --- a/core_lib/src/interface/timeline.h +++ b/core_lib/src/interface/timeline.h @@ -70,6 +70,7 @@ class TimeLine : public BaseDockWidget void fpsClick( int ); void onionPrevClick(); void onionNextClick(); + void playButtonTriggered(); public: bool scrubbing = false; From ed3c4ecfa09b08d3d671cd6a44272500359117b4 Mon Sep 17 00:00:00 2001 From: CandyFace Date: Tue, 17 Apr 2018 19:55:33 +0200 Subject: [PATCH 017/184] Fix selection corner disappearing --- core_lib/src/interface/scribblearea.cpp | 50 +++++++++++++++ core_lib/src/interface/scribblearea.h | 2 + core_lib/src/tool/movetool.cpp | 27 +++++++- core_lib/src/tool/movetool.h | 2 + core_lib/src/tool/selecttool.cpp | 84 ++++++------------------- core_lib/src/tool/selecttool.h | 5 ++ 6 files changed, 101 insertions(+), 69 deletions(-) diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index 6f00a94ac..6124cbe77 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -1482,6 +1482,56 @@ void ScribbleArea::setSelection(QRectF rect, bool trueOrFalse) // displaySelectionProperties(); } +/** + * @brief ScribbleArea::manageSelectionOrigin + * switches anchor point when crossing threshold + */ +void ScribbleArea::manageSelectionOrigin(QPointF currentPoint, QPointF originPoint) +{ + int mouseX = currentPoint.x(); + int mouseY = currentPoint.y(); + + QRectF selectRect; + if (currentTool()->type() == ToolType::SELECT) { + selectRect = mySelection; + } + else // MOVE + { + selectRect = myTempTransformedSelection; + } + + if (mouseX <= originPoint.x()) + { + selectRect.setLeft(mouseX); + selectRect.setRight(originPoint.x()); + } + else + { + selectRect.setLeft(originPoint.x()); + selectRect.setRight(mouseX); + } + + if (mouseY <= originPoint.y()) + { + selectRect.setTop(mouseY); + selectRect.setBottom(originPoint.y()); + } + else + { + selectRect.setTop(originPoint.y()); + selectRect.setBottom(mouseY); + } + + if (currentTool()->type() == ToolType::SELECT) { + mySelection = selectRect; + } + else // MOVE + { + myTempTransformedSelection = selectRect; + } + +} + void ScribbleArea::displaySelectionProperties() { Layer* layer = mEditor->layers()->currentLayer(); diff --git a/core_lib/src/interface/scribblearea.h b/core_lib/src/interface/scribblearea.h index 0b178da13..f9a689f14 100644 --- a/core_lib/src/interface/scribblearea.h +++ b/core_lib/src/interface/scribblearea.h @@ -115,6 +115,8 @@ class ScribbleArea : public QWidget bool isMouseInUse() const { return mMouseInUse; } + void manageSelectionOrigin(QPointF currentPoint, QPointF originPoint); + signals: void modification( int ); void multiLayerOnionSkinChanged( bool ); diff --git a/core_lib/src/tool/movetool.cpp b/core_lib/src/tool/movetool.cpp index f22cd2eec..12d17e861 100644 --- a/core_lib/src/tool/movetool.cpp +++ b/core_lib/src/tool/movetool.cpp @@ -180,6 +180,8 @@ void MoveTool::pressOperation(QMouseEvent* event, Layer* layer) mScribbleArea->setSelection(mScribbleArea->myTransformedSelection, true); resetSelectionProperties(); + } else { + anchorOriginPoint = getLastPoint(); } if (mScribbleArea->getMoveMode() == ScribbleArea::MIDDLE) @@ -248,18 +250,22 @@ void MoveTool::whichTransformationPoint() if (QLineF(getLastPoint(), transformPoint.topLeft()).length() < 10) { mScribbleArea->setMoveMode(ScribbleArea::TOPLEFT); + anchorOriginPoint = mScribbleArea->mySelection.bottomRight(); } if (QLineF(getLastPoint(), transformPoint.topRight()).length() < 10) { mScribbleArea->setMoveMode(ScribbleArea::TOPRIGHT); + anchorOriginPoint = mScribbleArea->mySelection.bottomLeft(); } if (QLineF(getLastPoint(), transformPoint.bottomLeft()).length() < 10) { mScribbleArea->setMoveMode(ScribbleArea::BOTTOMLEFT); + anchorOriginPoint = mScribbleArea->mySelection.topRight(); } if (QLineF(getLastPoint(), transformPoint.bottomRight()).length() < 10) { mScribbleArea->setMoveMode(ScribbleArea::BOTTOMRIGHT); + anchorOriginPoint = mScribbleArea->mySelection.topLeft(); } } @@ -276,30 +282,45 @@ void MoveTool::transformSelection(qreal offsetX, qreal offsetY) break; case ScribbleArea::TOPRIGHT: + { mScribbleArea->myTempTransformedSelection = mScribbleArea->myTransformedSelection.adjusted(0, offsetY, offsetX, 0); - break; + mScribbleArea->manageSelectionOrigin(getCurrentPoint(), anchorOriginPoint); + break; + } case ScribbleArea::TOPLEFT: + { mScribbleArea->myTempTransformedSelection = mScribbleArea->myTransformedSelection.adjusted(offsetX, offsetY, 0, 0); - break; + mScribbleArea->manageSelectionOrigin(getCurrentPoint(), anchorOriginPoint); + break; + } case ScribbleArea::BOTTOMLEFT: + { mScribbleArea->myTempTransformedSelection = mScribbleArea->myTransformedSelection.adjusted(offsetX, 0, 0, offsetY); - break; + mScribbleArea->manageSelectionOrigin(getCurrentPoint(), anchorOriginPoint); + break; + } case ScribbleArea::BOTTOMRIGHT: + { mScribbleArea->myTempTransformedSelection = mScribbleArea->myTransformedSelection.adjusted(0, 0, offsetX, offsetY); + + mScribbleArea->manageSelectionOrigin(getCurrentPoint(), anchorOriginPoint); break; + } case ScribbleArea::ROTATION: + { mScribbleArea->myTempTransformedSelection = mScribbleArea->myTransformedSelection; // @ necessary? mScribbleArea->myRotatedAngle = getCurrentPixel().x() - getLastPressPixel().x(); break; + } default: break; } diff --git a/core_lib/src/tool/movetool.h b/core_lib/src/tool/movetool.h index fcb12e769..af5a3cbdc 100644 --- a/core_lib/src/tool/movetool.h +++ b/core_lib/src/tool/movetool.h @@ -49,6 +49,8 @@ class MoveTool : public BaseTool void actionOnVector(QMouseEvent *event, Layer *layer); void storeClosestVectorCurve(); QPointF maintainAspectRatio(qreal offsetX, qreal offsetY); + + QPointF anchorOriginPoint; }; #endif diff --git a/core_lib/src/tool/selecttool.cpp b/core_lib/src/tool/selecttool.cpp index 858086ba7..0e7f74fa2 100644 --- a/core_lib/src/tool/selecttool.cpp +++ b/core_lib/src/tool/selecttool.cpp @@ -25,11 +25,6 @@ GNU General Public License for more details. #include "layermanager.h" #include "toolmanager.h" - -// Store selection origin so we can calculate -// the selection rectangle in mousePressEvent. -static QPointF gSelectionOrigin; - SelectTool::SelectTool(QObject* parent) : BaseTool(parent) { @@ -57,13 +52,16 @@ void SelectTool::mousePressEvent(QMouseEvent* event) if (event->button() == Qt::LeftButton) { - gSelectionOrigin = getLastPoint(); // Store original click position for help with selection rectangle. + if (!mScribbleArea->somethingSelected) + { + anchorOriginPoint = getLastPoint(); // Store original click position for help with selection rectangle. + } - if (layer->type() == Layer::BITMAP || layer->type() == Layer::VECTOR) + if (layer->isPaintable()) { if (layer->type() == Layer::VECTOR) { - ((LayerVector*)layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0)->deselectAll(); + static_cast(layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0)->deselectAll(); } mScribbleArea->setMoveMode(ScribbleArea::NONE); @@ -72,18 +70,22 @@ void SelectTool::mousePressEvent(QMouseEvent* event) if (BezierCurve::mLength(getLastPoint() - mScribbleArea->myTransformedSelection.topLeft()) < 6) { mScribbleArea->setMoveMode(ScribbleArea::TOPLEFT); + anchorOriginPoint = mScribbleArea->mySelection.bottomRight(); } if (BezierCurve::mLength(getLastPoint() - mScribbleArea->myTransformedSelection.topRight()) < 6) { mScribbleArea->setMoveMode(ScribbleArea::TOPRIGHT); + anchorOriginPoint = mScribbleArea->mySelection.bottomLeft(); } if (BezierCurve::mLength(getLastPoint() - mScribbleArea->myTransformedSelection.bottomLeft()) < 6) { mScribbleArea->setMoveMode(ScribbleArea::BOTTOMLEFT); + anchorOriginPoint = mScribbleArea->mySelection.topRight(); } if (BezierCurve::mLength(getLastPoint() - mScribbleArea->myTransformedSelection.bottomRight()) < 6) { mScribbleArea->setMoveMode(ScribbleArea::BOTTOMRIGHT); + anchorOriginPoint = mScribbleArea->mySelection.topLeft(); } // the user did not click on one of the corners @@ -121,7 +123,7 @@ void SelectTool::mouseReleaseEvent(QMouseEvent* event) { mEditor->tools()->setCurrentTool(MOVE); - VectorImage* vectorImage = ((LayerVector*)layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0); + VectorImage* vectorImage = static_cast(layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0); mScribbleArea->setSelection(vectorImage->getSelectionRect(), true); if (mScribbleArea->mySelection.width() <= 0 && mScribbleArea->mySelection.height() <= 0) { @@ -147,70 +149,20 @@ void SelectTool::mouseMoveEvent(QMouseEvent* event) Layer* layer = mEditor->layers()->currentLayer(); if (layer == NULL) { return; } - if ((event->buttons() & Qt::LeftButton) && mScribbleArea->somethingSelected && (layer->type() == Layer::BITMAP || layer->type() == Layer::VECTOR)) + if ((event->buttons() & Qt::LeftButton) && + mScribbleArea->somethingSelected && + layer->isPaintable()) { - switch (mScribbleArea->getMoveMode()) - { - case ScribbleArea::NONE: - { - // Resize the selection rectangle so it goes from the origin point - // (i.e. where the mouse was clicked) to the current mouse - // position. - int mouseX = getCurrentPoint().x(); - int mouseY = getCurrentPoint().y(); - QRectF& selectRect = mScribbleArea->mySelection; - - if (mouseX < gSelectionOrigin.x()) - { - selectRect.setLeft(mouseX); - selectRect.setRight(gSelectionOrigin.x()); - } - else - { - selectRect.setLeft(gSelectionOrigin.x()); - selectRect.setRight(mouseX); - } - - if (mouseY < gSelectionOrigin.y()) - { - selectRect.setTop(mouseY); - selectRect.setBottom(gSelectionOrigin.y()); - } - else - { - selectRect.setTop(gSelectionOrigin.y()); - selectRect.setBottom(mouseY); - } - - break; - } - - case ScribbleArea::TOPLEFT: - mScribbleArea->mySelection.setTopLeft(getCurrentPoint()); - break; - - case ScribbleArea::TOPRIGHT: - mScribbleArea->mySelection.setTopRight(getCurrentPoint()); - break; - - case ScribbleArea::BOTTOMLEFT: - mScribbleArea->mySelection.setBottomLeft(getCurrentPoint()); - break; - - case ScribbleArea::BOTTOMRIGHT: - mScribbleArea->mySelection.setBottomRight(getCurrentPoint()); - break; - - default: - break; - } + mScribbleArea->manageSelectionOrigin(getCurrentPoint(), anchorOriginPoint); mScribbleArea->myTransformedSelection = mScribbleArea->mySelection.adjusted(0, 0, 0, 0); mScribbleArea->myTempTransformedSelection = mScribbleArea->mySelection.adjusted(0, 0, 0, 0); if (layer->type() == Layer::VECTOR) { - ((LayerVector*)layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0)->select(mScribbleArea->mySelection); + static_cast(layer)-> + getLastVectorImageAtFrame(mEditor->currentFrame(), 0)-> + select(mScribbleArea->mySelection); } mScribbleArea->update(); } diff --git a/core_lib/src/tool/selecttool.h b/core_lib/src/tool/selecttool.h index 7214d997e..ef03d7173 100644 --- a/core_lib/src/tool/selecttool.h +++ b/core_lib/src/tool/selecttool.h @@ -36,6 +36,11 @@ class SelectTool : public BaseTool void mouseMoveEvent(QMouseEvent*) override; bool keyPressEvent(QKeyEvent *event) override; + + + // Store selection origin so we can calculate + // the selection rectangle in mousePressEvent. + QPointF anchorOriginPoint; }; #endif From 6c4d6d28ce8926622d00f05e06801f39ee8c1e80 Mon Sep 17 00:00:00 2001 From: CandyFace Date: Mon, 23 Apr 2018 18:17:13 +0200 Subject: [PATCH 018/184] Add toggle to enable/disable --- app/src/preferencesdialog.cpp | 9 +++++ app/src/preferencesdialog.h | 1 + app/ui/timelinepage.ui | 41 +++++++++++++++++++-- core_lib/src/canvaspainter.cpp | 2 +- core_lib/src/canvaspainter.h | 1 + core_lib/src/interface/scribblearea.cpp | 3 +- core_lib/src/managers/preferencemanager.cpp | 4 ++ core_lib/src/managers/preferencemanager.h | 1 + core_lib/src/util/pencildef.h | 1 + 9 files changed, 58 insertions(+), 5 deletions(-) diff --git a/app/src/preferencesdialog.cpp b/app/src/preferencesdialog.cpp index e0e013d93..7a63be8bc 100644 --- a/app/src/preferencesdialog.cpp +++ b/app/src/preferencesdialog.cpp @@ -277,6 +277,7 @@ TimelinePage::TimelinePage(QWidget* parent) : connect(ui->radioButtonAddNewKey, &QRadioButton::toggled, this, &TimelinePage::radioButtonToggled); connect(ui->radioButtonDuplicate, &QRadioButton::toggled, this, &TimelinePage::radioButtonToggled); connect(ui->radioButtonDrawOnPrev, &QRadioButton::toggled, this, &TimelinePage::radioButtonToggled); + connect(ui->onionWhilePlayback, &QCheckBox::stateChanged, this, &TimelinePage::playbackStateChanged); } TimelinePage::~TimelinePage() @@ -318,6 +319,9 @@ void TimelinePage::updateValues() default: break; } + + SignalBlocker b7(ui->onionWhilePlayback); + ui->onionWhilePlayback->setChecked(mManager->getInt(SETTING::ONION_WHILE_PLAYBACK)); } void TimelinePage::timelineLengthChanged(int value) @@ -345,6 +349,11 @@ void TimelinePage::scrubChange(int value) mManager->set(SETTING::SHORT_SCRUB, value != Qt::Unchecked); } +void TimelinePage::playbackStateChanged(int value) +{ + mManager->set(SETTING::ONION_WHILE_PLAYBACK, value); +} + void TimelinePage::radioButtonToggled(bool) { if(ui->radioButtonAddNewKey->isChecked()) diff --git a/app/src/preferencesdialog.h b/app/src/preferencesdialog.h index 718394ab6..c7e41f8b0 100644 --- a/app/src/preferencesdialog.h +++ b/app/src/preferencesdialog.h @@ -135,6 +135,7 @@ public slots: void frameSizeChange(int); void labelChange(bool); void scrubChange(int); + void playbackStateChanged(int); void radioButtonToggled(bool); private: diff --git a/app/ui/timelinepage.ui b/app/ui/timelinepage.ui index 6d2ffb67f..e72998b6a 100644 --- a/app/ui/timelinepage.ui +++ b/app/ui/timelinepage.ui @@ -7,7 +7,7 @@ 0 0 342 - 374 + 457 @@ -144,15 +144,50 @@ + + + + + 0 + 60 + + + + + 16777215 + 60 + + + + Playback + + + + + 10 + 30 + 301 + 16 + + + + Show onion skin while playing + + + + Qt::Vertical + + QSizePolicy::Preferred + - 0 - 0 + 20 + 30 diff --git a/core_lib/src/canvaspainter.cpp b/core_lib/src/canvaspainter.cpp index 04e1ef176..dd7ce883c 100644 --- a/core_lib/src/canvaspainter.cpp +++ b/core_lib/src/canvaspainter.cpp @@ -108,7 +108,7 @@ void CanvasPainter::paintBackground() void CanvasPainter::paintOnionSkin(QPainter& painter) { - if (mOptions.isPlaying) { return; } + if (!mOptions.onionWhilePlayback && mOptions.isPlaying) { return; } Layer* layer = mObject->getLayer(mCurrentLayerIndex); diff --git a/core_lib/src/canvaspainter.h b/core_lib/src/canvaspainter.h index 78158b26c..a9f3cbe65 100644 --- a/core_lib/src/canvaspainter.h +++ b/core_lib/src/canvaspainter.h @@ -50,6 +50,7 @@ struct CanvasPainterOptions bool bIsOnionAbsolute = false; float scaling = 1.0f; bool isPlaying = false; + bool onionWhilePlayback = false; }; diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index 3ff731cc6..380e4c088 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -1120,7 +1120,8 @@ void ScribbleArea::drawCanvas(int frame, QRect rect) o.nShowAllLayers = mShowAllLayers; o.bIsOnionAbsolute = (mPrefs->getString(SETTING::ONION_TYPE) == "absolute"); o.scaling = mEditor->view()->scaling(); - o.isPlaying = mEditor->playback()->isPlaying() ? true : false; + o.onionWhilePlayback = mPrefs->getInt(SETTING::ONION_WHILE_PLAYBACK); + o.isPlaying = mEditor->playback()->isPlaying() ? true : false; mCanvasPainter.setOptions(o); mCanvasPainter.setCanvas(&mCanvas); diff --git a/core_lib/src/managers/preferencemanager.cpp b/core_lib/src/managers/preferencemanager.cpp index e04252a2c..3c3bc9d0f 100644 --- a/core_lib/src/managers/preferencemanager.cpp +++ b/core_lib/src/managers/preferencemanager.cpp @@ -96,6 +96,7 @@ void PreferenceManager::loadPrefs() set(SETTING::ONION_MIN_OPACITY, settings.value(SETTING_ONION_MIN_OPACITY, 20).toInt()); set(SETTING::ONION_PREV_FRAMES_NUM, settings.value(SETTING_ONION_PREV_FRAMES_NUM, 5).toInt()); set(SETTING::ONION_NEXT_FRAMES_NUM, settings.value(SETTING_ONION_NEXT_FRAMES_NUM, 5).toInt()); + set(SETTING::ONION_WHILE_PLAYBACK, settings.value(SETTING_ONION_WHILE_PLAYBACK, 0).toInt()); set(SETTING::ONION_TYPE, settings.value(SETTING_ONION_TYPE, "relative").toString()); set(SETTING::LANGUAGE, settings.value(SETTING_LANGUAGE).toString()); @@ -215,6 +216,9 @@ void PreferenceManager::set(SETTING option, int value) case SETTING::DRAW_ON_EMPTY_FRAME_ACTION: settings.setValue( SETTING_DRAW_ON_EMPTY_FRAME_ACTION, value); break; + case SETTING::ONION_WHILE_PLAYBACK: + settings.setValue(SETTING_ONION_WHILE_PLAYBACK, value); + break; default: Q_ASSERT(false); break; diff --git a/core_lib/src/managers/preferencemanager.h b/core_lib/src/managers/preferencemanager.h index 79cabea83..df816e428 100644 --- a/core_lib/src/managers/preferencemanager.h +++ b/core_lib/src/managers/preferencemanager.h @@ -52,6 +52,7 @@ enum class SETTING ONION_MIN_OPACITY, ONION_PREV_FRAMES_NUM, ONION_NEXT_FRAMES_NUM, + ONION_WHILE_PLAYBACK, ONION_TYPE, GRID_SIZE, QUICK_SIZING, diff --git a/core_lib/src/util/pencildef.h b/core_lib/src/util/pencildef.h index 4f10b2f4c..02e40c250 100644 --- a/core_lib/src/util/pencildef.h +++ b/core_lib/src/util/pencildef.h @@ -182,6 +182,7 @@ enum BackgroundStyle #define SETTING_ONION_MIN_OPACITY "OnionMinOpacity" #define SETTING_ONION_PREV_FRAMES_NUM "OnionPrevFramesNum" #define SETTING_ONION_NEXT_FRAMES_NUM "OnionNextFramesNum" +#define SETTING_ONION_WHILE_PLAYBACK "OnionWhilePlayback" #define SETTING_ONION_TYPE "OnionType" #define SETTING_DRAW_ON_EMPTY_FRAME_ACTION "DrawOnEmptyFrameAction" From 26e36266169b4e8209ab33da131a144fc2a97e48 Mon Sep 17 00:00:00 2001 From: CandyFace Date: Mon, 23 Apr 2018 20:07:21 +0200 Subject: [PATCH 019/184] Refactor stabilization --- app/src/tooloptionwidget.cpp | 12 +++++------ app/src/tooloptionwidget.h | 2 +- core_lib/src/managers/toolmanager.cpp | 12 +++++------ core_lib/src/managers/toolmanager.h | 2 +- core_lib/src/tool/basetool.cpp | 6 +++--- core_lib/src/tool/basetool.h | 4 ++-- core_lib/src/tool/brushtool.cpp | 12 +++++------ core_lib/src/tool/brushtool.h | 2 +- core_lib/src/tool/buckettool.cpp | 4 ++-- core_lib/src/tool/erasertool.cpp | 12 +++++------ core_lib/src/tool/erasertool.h | 2 +- core_lib/src/tool/penciltool.cpp | 12 +++++------ core_lib/src/tool/penciltool.h | 2 +- core_lib/src/tool/pentool.cpp | 12 +++++------ core_lib/src/tool/pentool.h | 2 +- core_lib/src/tool/polylinetool.cpp | 2 +- core_lib/src/tool/selecttool.cpp | 2 +- core_lib/src/tool/smudgetool.cpp | 2 +- core_lib/src/tool/strokemanager.cpp | 30 +++++++++++++-------------- core_lib/src/tool/strokemanager.h | 6 +++--- core_lib/src/util/pencildef.h | 9 +++++++- 21 files changed, 78 insertions(+), 71 deletions(-) diff --git a/app/src/tooloptionwidget.cpp b/app/src/tooloptionwidget.cpp index bdcad05e9..c8192fd88 100644 --- a/app/src/tooloptionwidget.cpp +++ b/app/src/tooloptionwidget.cpp @@ -77,7 +77,7 @@ void ToolOptionWidget::updateUI() setPreserveAlpha(p.preserveAlpha); setVectorMergeEnabled(p.vectorMergeEnabled); setAA(p.useAA); - setInpolLevel(p.inpolLevel); + setStabilizerLevel(p.stabilizerLevel); setTolerance(p.tolerance); setFillContour(p.useFillContour); } @@ -106,7 +106,7 @@ void ToolOptionWidget::makeConnectionToEditor(Editor* editor) connect(ui->vectorMergeBox, &QCheckBox::clicked, toolManager, &ToolManager::setVectorMergeEnabled); connect(ui->useAABox, &QCheckBox::clicked, toolManager, &ToolManager::setAA); - connect(ui->inpolLevelsCombo, static_cast(&QComboBox::activated), toolManager, &ToolManager::setInpolLevel); + connect(ui->inpolLevelsCombo, static_cast(&QComboBox::activated), toolManager, &ToolManager::setStabilizerLevel); connect(ui->toleranceSlider, &SpinSlider::valueChanged, toolManager, &ToolManager::setTolerance); connect(ui->toleranceSpinBox, static_cast(&QSpinBox::valueChanged), toolManager, &ToolManager::setTolerance); @@ -131,7 +131,7 @@ void ToolOptionWidget::onToolPropertyChanged(ToolType, ToolPropertyType ePropert case PRESERVEALPHA: setPreserveAlpha(p.preserveAlpha); break; case VECTORMERGE: setVectorMergeEnabled(p.vectorMergeEnabled); break; case ANTI_ALIASING: setAA(p.useAA); break; - case INTERPOLATION: setInpolLevel(p.inpolLevel); break; + case STABILIZATION: setStabilizerLevel(p.stabilizerLevel); break; case TOLERANCE: setTolerance(p.tolerance); break; case FILLCONTOUR: setFillContour(p.useFillContour); break; case BEZIER: setBezier(p.bezier_state); break; @@ -153,8 +153,8 @@ void ToolOptionWidget::setVisibility(BaseTool* tool) ui->makeInvisibleBox->setVisible(tool->isPropertyEnabled(INVISIBILITY)); ui->preserveAlphaBox->setVisible(tool->isPropertyEnabled(PRESERVEALPHA)); ui->useAABox->setVisible(tool->isPropertyEnabled(ANTI_ALIASING)); - ui->stabilizerLabel->setVisible(tool->isPropertyEnabled(INTERPOLATION)); - ui->inpolLevelsCombo->setVisible(tool->isPropertyEnabled(INTERPOLATION)); + ui->stabilizerLabel->setVisible(tool->isPropertyEnabled(STABILIZATION)); + ui->inpolLevelsCombo->setVisible(tool->isPropertyEnabled(STABILIZATION)); ui->toleranceSlider->setVisible(tool->isPropertyEnabled(TOLERANCE)); ui->toleranceSpinBox->setVisible(tool->isPropertyEnabled(TOLERANCE)); ui->fillContourBox->setVisible(tool->isPropertyEnabled(FILLCONTOUR)); @@ -295,7 +295,7 @@ void ToolOptionWidget::setAA(int x) } } -void ToolOptionWidget::setInpolLevel(int x) +void ToolOptionWidget::setStabilizerLevel(int x) { ui->inpolLevelsCombo->setCurrentIndex(qBound(0, x, ui->inpolLevelsCombo->count() - 1)); } diff --git a/app/src/tooloptionwidget.h b/app/src/tooloptionwidget.h index 41ee37c87..c4ea56ae6 100644 --- a/app/src/tooloptionwidget.h +++ b/app/src/tooloptionwidget.h @@ -61,7 +61,7 @@ public slots: void setPreserveAlpha(int); void setVectorMergeEnabled(int); void setAA(int); - void setInpolLevel(int); + void setStabilizerLevel(int); void setTolerance(int); void setFillContour(int); void setBezier(bool); diff --git a/core_lib/src/managers/toolmanager.cpp b/core_lib/src/managers/toolmanager.cpp index ef1152af9..2fdb9d7b4 100644 --- a/core_lib/src/managers/toolmanager.cpp +++ b/core_lib/src/managers/toolmanager.cpp @@ -110,16 +110,16 @@ void ToolManager::resetAllTools() // Beta-testers should be recommended to reset before sending tool related issues. // This can prevent from users to stop working on their project. getTool(PEN)->properties.width = 1.5; // not supposed to use feather - getTool(PEN)->properties.inpolLevel = -1; + getTool(PEN)->properties.stabilizerLevel = -1; getTool(POLYLINE)->properties.width = 1.5; // PEN dependent getTool(PENCIL)->properties.width = 1.0; getTool(PENCIL)->properties.feather = -1.0; // locks feather usage (can be changed) - getTool(PENCIL)->properties.inpolLevel = -1; + getTool(PENCIL)->properties.stabilizerLevel = -1; getTool(ERASER)->properties.width = 25.0; getTool(ERASER)->properties.feather = 50.0; getTool(BRUSH)->properties.width = 15.0; getTool(BRUSH)->properties.feather = 200.0; - getTool(BRUSH)->properties.inpolLevel = -1; + getTool(BRUSH)->properties.stabilizerLevel = -1; getTool(BRUSH)->properties.useFeather = false; getTool(SMUDGE)->properties.width = 25.0; getTool(SMUDGE)->properties.feather = 200.0; @@ -201,10 +201,10 @@ void ToolManager::setAA(int usingAA) Q_EMIT toolPropertyChanged(currentTool()->type(), ANTI_ALIASING); } -void ToolManager::setInpolLevel(int level) +void ToolManager::setStabilizerLevel(int level) { - currentTool()->setInpolLevel(level); - Q_EMIT toolPropertyChanged(currentTool()->type(), INTERPOLATION); + currentTool()->setStabilizerLevel(level); + Q_EMIT toolPropertyChanged(currentTool()->type(), STABILIZATION); } void ToolManager::setTolerance(int newTolerance) diff --git a/core_lib/src/managers/toolmanager.h b/core_lib/src/managers/toolmanager.h index ef4010bd6..9923e872c 100644 --- a/core_lib/src/managers/toolmanager.h +++ b/core_lib/src/managers/toolmanager.h @@ -65,7 +65,7 @@ public slots: void setBezier(bool); void setPressure(bool); void setAA(int); - void setInpolLevel(int); + void setStabilizerLevel(int); void setTolerance(int); void setUseFillContour(bool); diff --git a/core_lib/src/tool/basetool.cpp b/core_lib/src/tool/basetool.cpp index ad432f6c7..2e00ab6f0 100644 --- a/core_lib/src/tool/basetool.cpp +++ b/core_lib/src/tool/basetool.cpp @@ -63,7 +63,7 @@ BaseTool::BaseTool(QObject *parent) : QObject(parent) m_enabledProperties.insert(PRESERVEALPHA, false); m_enabledProperties.insert(BEZIER, false); m_enabledProperties.insert(ANTI_ALIASING, false); - m_enabledProperties.insert(INTERPOLATION, false); + m_enabledProperties.insert(STABILIZATION, false); } QCursor BaseTool::cursor() @@ -366,9 +366,9 @@ void BaseTool::setAA(const int useAA) properties.useAA = useAA; } -void BaseTool::setInpolLevel(const int level) +void BaseTool::setStabilizerLevel(const int level) { - properties.inpolLevel = level; + properties.stabilizerLevel = level; } void BaseTool::setTolerance(const int tolerance) diff --git a/core_lib/src/tool/basetool.h b/core_lib/src/tool/basetool.h index 7dae88fde..af6de240b 100644 --- a/core_lib/src/tool/basetool.h +++ b/core_lib/src/tool/basetool.h @@ -44,7 +44,7 @@ class Properties bool bezier_state = false; bool useFeather = true; int useAA = 0; - int inpolLevel = 0; + int stabilizerLevel = 0; qreal tolerance = 0; bool useFillContour = false; }; @@ -105,7 +105,7 @@ class BaseTool : public QObject virtual void setPreserveAlpha(const bool preserveAlpha); virtual void setVectorMergeEnabled(const bool vectorMergeEnabled); virtual void setAA(const int useAA); - virtual void setInpolLevel(const int level); + virtual void setStabilizerLevel(const int level); virtual void setTolerance(const int tolerance); virtual void setUseFillContour(const bool useFillContour); diff --git a/core_lib/src/tool/brushtool.cpp b/core_lib/src/tool/brushtool.cpp index c6ec857fa..8fd04717b 100644 --- a/core_lib/src/tool/brushtool.cpp +++ b/core_lib/src/tool/brushtool.cpp @@ -50,7 +50,7 @@ void BrushTool::loadSettings() m_enabledProperties[USEFEATHER] = true; m_enabledProperties[PRESSURE] = true; m_enabledProperties[INVISIBILITY] = true; - m_enabledProperties[INTERPOLATION] = true; + m_enabledProperties[STABILIZATION] = true; m_enabledProperties[ANTI_ALIASING] = true; QSettings settings( PENCIL2D, PENCIL2D ); @@ -135,12 +135,12 @@ void BrushTool::setPressure( const bool pressure ) settings.sync(); } -void BrushTool::setInpolLevel(const int level) +void BrushTool::setStabilizerLevel(const int level) { - properties.inpolLevel = level; + properties.stabilizerLevel = level; QSettings settings( PENCIL2D, PENCIL2D); - settings.setValue("lineInpol", level); + settings.setValue("brushStabilization", level); settings.sync(); } @@ -245,8 +245,8 @@ void BrushTool::mouseMoveEvent( QMouseEvent* event ) if ( event->buttons() & Qt::LeftButton ) { drawStroke(); - if (properties.inpolLevel != m_pStrokeManager->getInpolLevel()) - m_pStrokeManager->setInpolLevel(properties.inpolLevel); + if (properties.stabilizerLevel != m_pStrokeManager->getStabilizerLevel()) + m_pStrokeManager->setStabilizerLevel(properties.stabilizerLevel); } } } diff --git a/core_lib/src/tool/brushtool.h b/core_lib/src/tool/brushtool.h index 372e368a7..b6b65f7eb 100644 --- a/core_lib/src/tool/brushtool.h +++ b/core_lib/src/tool/brushtool.h @@ -47,7 +47,7 @@ class BrushTool : public StrokeTool void setPressure( const bool pressure ) override; void setInvisibility( const bool invisibility) override; void setAA( const int useAA ) override; - void setInpolLevel( const int level ) override; + void setStabilizerLevel( const int level ) override; protected: QPointF mLastBrushPoint; diff --git a/core_lib/src/tool/buckettool.cpp b/core_lib/src/tool/buckettool.cpp index a2008b4e8..5090bec97 100644 --- a/core_lib/src/tool/buckettool.cpp +++ b/core_lib/src/tool/buckettool.cpp @@ -188,8 +188,8 @@ void BucketTool::drawStroke() { StrokeTool::drawStroke(); - if (properties.inpolLevel != m_pStrokeManager->getInpolLevel()) { - m_pStrokeManager->setInpolLevel(properties.inpolLevel); + if (properties.stabilizerLevel != m_pStrokeManager->getStabilizerLevel()) { + m_pStrokeManager->setStabilizerLevel(properties.stabilizerLevel); } QList p = m_pStrokeManager->interpolateStroke(); diff --git a/core_lib/src/tool/erasertool.cpp b/core_lib/src/tool/erasertool.cpp index 94fd99916..382ea0056 100644 --- a/core_lib/src/tool/erasertool.cpp +++ b/core_lib/src/tool/erasertool.cpp @@ -45,7 +45,7 @@ void EraserTool::loadSettings() m_enabledProperties[WIDTH] = true; m_enabledProperties[FEATHER] = true; m_enabledProperties[PRESSURE] = true; - m_enabledProperties[INTERPOLATION] = true; + m_enabledProperties[STABILIZATION] = true; QSettings settings( PENCIL2D, PENCIL2D ); @@ -100,12 +100,12 @@ void EraserTool::setPressure( const bool pressure ) settings.sync(); } -void EraserTool::setInpolLevel(const int level) +void EraserTool::setStabilizerLevel(const int level) { - properties.inpolLevel = level; + properties.stabilizerLevel = level; QSettings settings( PENCIL2D, PENCIL2D); - settings.setValue("lineInpol", level); + settings.setValue("stabilizerLevel", level); settings.sync(); } @@ -170,8 +170,8 @@ void EraserTool::mouseMoveEvent( QMouseEvent *event ) if ( mScribbleArea->isLayerPaintable() ) { updateStrokes(); - if (properties.inpolLevel != m_pStrokeManager->getInpolLevel()) { - m_pStrokeManager->setInpolLevel(properties.inpolLevel); + if (properties.stabilizerLevel != m_pStrokeManager->getStabilizerLevel()) { + m_pStrokeManager->setStabilizerLevel(properties.stabilizerLevel); } } } diff --git a/core_lib/src/tool/erasertool.h b/core_lib/src/tool/erasertool.h index 11e2d44f8..24f10e5ab 100644 --- a/core_lib/src/tool/erasertool.h +++ b/core_lib/src/tool/erasertool.h @@ -44,7 +44,7 @@ class EraserTool : public StrokeTool void setWidth( const qreal width ) override; void setFeather( const qreal feather ) override; void setPressure( const bool pressure ) override; - void setInpolLevel(const int level) override; + void setStabilizerLevel(const int level) override; protected: QPointF mLastBrushPoint; diff --git a/core_lib/src/tool/penciltool.cpp b/core_lib/src/tool/penciltool.cpp index b9f56c040..82b06799e 100644 --- a/core_lib/src/tool/penciltool.cpp +++ b/core_lib/src/tool/penciltool.cpp @@ -43,7 +43,7 @@ void PencilTool::loadSettings() m_enabledProperties[WIDTH] = true; m_enabledProperties[PRESSURE] = true; m_enabledProperties[VECTORMERGE] = false; - m_enabledProperties[INTERPOLATION] = true; + m_enabledProperties[STABILIZATION] = true; m_enabledProperties[FILLCONTOUR] = true; QSettings settings(PENCIL2D, PENCIL2D); @@ -119,12 +119,12 @@ void PencilTool::setPreserveAlpha(const bool preserveAlpha) properties.preserveAlpha = 0; } -void PencilTool::setInpolLevel(const int level) +void PencilTool::setStabilizerLevel(const int level) { - properties.inpolLevel = level; + properties.stabilizerLevel = level; QSettings settings(PENCIL2D, PENCIL2D); - settings.setValue("lineInpol", level); + settings.setValue("stabilizerLevel", level); settings.sync(); } @@ -181,9 +181,9 @@ void PencilTool::mouseMoveEvent(QMouseEvent* event) if (event->buttons() & Qt::LeftButton) { drawStroke(); - if (properties.inpolLevel != m_pStrokeManager->getInpolLevel()) + if (properties.stabilizerLevel != m_pStrokeManager->getStabilizerLevel()) { - m_pStrokeManager->setInpolLevel(properties.inpolLevel); + m_pStrokeManager->setStabilizerLevel(properties.stabilizerLevel); } } } diff --git a/core_lib/src/tool/penciltool.h b/core_lib/src/tool/penciltool.h index c232c2056..11a279481 100644 --- a/core_lib/src/tool/penciltool.h +++ b/core_lib/src/tool/penciltool.h @@ -49,7 +49,7 @@ class PencilTool : public StrokeTool void setInvisibility( const bool invisibility ) override; void setPressure( const bool pressure ) override; void setPreserveAlpha( const bool preserveAlpha ) override; - void setInpolLevel(const int level) override; + void setStabilizerLevel(const int level) override; void setUseFillContour(const bool useFillContour) override; private: diff --git a/core_lib/src/tool/pentool.cpp b/core_lib/src/tool/pentool.cpp index d65796e02..fb81595de 100644 --- a/core_lib/src/tool/pentool.cpp +++ b/core_lib/src/tool/pentool.cpp @@ -39,7 +39,7 @@ void PenTool::loadSettings() m_enabledProperties[PRESSURE] = true; m_enabledProperties[VECTORMERGE] = true; m_enabledProperties[ANTI_ALIASING] = true; - m_enabledProperties[INTERPOLATION] = true; + m_enabledProperties[STABILIZATION] = true; QSettings settings( PENCIL2D, PENCIL2D ); @@ -93,12 +93,12 @@ void PenTool::setAA(const int AA ) settings.sync(); } -void PenTool::setInpolLevel(const int level) +void PenTool::setStabilizerLevel(const int level) { - properties.inpolLevel = level; + properties.stabilizerLevel = level; QSettings settings( PENCIL2D, PENCIL2D); - settings.setValue("lineInpol", level); + settings.setValue("stabilizerLevel", level); settings.sync(); } @@ -174,8 +174,8 @@ void PenTool::mouseMoveEvent( QMouseEvent *event ) if ( event->buttons() & Qt::LeftButton ) { drawStroke(); - if (properties.inpolLevel != m_pStrokeManager->getInpolLevel()) { - m_pStrokeManager->setInpolLevel(properties.inpolLevel); + if (properties.stabilizerLevel != m_pStrokeManager->getStabilizerLevel()) { + m_pStrokeManager->setStabilizerLevel(properties.stabilizerLevel); } //qDebug() << "DrawStroke" << event->pos() ; } diff --git a/core_lib/src/tool/pentool.h b/core_lib/src/tool/pentool.h index f8c502867..459856cb6 100644 --- a/core_lib/src/tool/pentool.h +++ b/core_lib/src/tool/pentool.h @@ -45,7 +45,7 @@ class PenTool : public StrokeTool void setWidth( const qreal width ) override; void setPressure( const bool pressure ) override; void setAA( const int AA ) override; - void setInpolLevel(const int level) override; + void setStabilizerLevel(const int level) override; private: QPointF mLastBrushPoint; diff --git a/core_lib/src/tool/polylinetool.cpp b/core_lib/src/tool/polylinetool.cpp index 0a899758c..9e5e72a57 100644 --- a/core_lib/src/tool/polylinetool.cpp +++ b/core_lib/src/tool/polylinetool.cpp @@ -54,7 +54,7 @@ void PolylineTool::loadSettings() properties.invisibility = OFF; properties.preserveAlpha = OFF; properties.useAA = settings.value( "brushAA").toBool(); - properties.inpolLevel = -1; + properties.stabilizerLevel = -1; // First run if ( properties.width <= 0 ) diff --git a/core_lib/src/tool/selecttool.cpp b/core_lib/src/tool/selecttool.cpp index 0e7f74fa2..566e3a28e 100644 --- a/core_lib/src/tool/selecttool.cpp +++ b/core_lib/src/tool/selecttool.cpp @@ -34,7 +34,7 @@ void SelectTool::loadSettings() { properties.width = -1; properties.feather = -1; - properties.inpolLevel = -1; + properties.stabilizerLevel = -1; properties.useAA = -1; } diff --git a/core_lib/src/tool/smudgetool.cpp b/core_lib/src/tool/smudgetool.cpp index 2679b4570..d0dea9c5d 100644 --- a/core_lib/src/tool/smudgetool.cpp +++ b/core_lib/src/tool/smudgetool.cpp @@ -50,7 +50,7 @@ void SmudgeTool::loadSettings() properties.width = settings.value("smudgeWidth").toDouble(); properties.feather = settings.value("smudgeFeather").toDouble(); properties.pressure = false; - properties.inpolLevel = -1; + properties.stabilizerLevel = -1; // First run if (properties.width <= 0) diff --git a/core_lib/src/tool/strokemanager.cpp b/core_lib/src/tool/strokemanager.cpp index 70dbab3ac..d41b28411 100644 --- a/core_lib/src/tool/strokemanager.cpp +++ b/core_lib/src/tool/strokemanager.cpp @@ -48,7 +48,7 @@ void StrokeManager::reset() pressure = 0.0f; hasTangent = false; timer.stop(); - mInpolLevel = -1; + mStabilizerLevel = -1; } void StrokeManager::setPressure(float pressure) @@ -113,9 +113,9 @@ void StrokeManager::tabletEvent(QTabletEvent* event) setPressure(event->pressure()); } -void StrokeManager::setInpolLevel(int level) +void StrokeManager::setStabilizerLevel(int level) { - mInpolLevel = level; + mStabilizerLevel = level; } void StrokeManager::mouseMoveEvent(QMouseEvent* event) @@ -123,7 +123,7 @@ void StrokeManager::mouseMoveEvent(QMouseEvent* event) QPointF pos = getEventPosition(event); // only applied to drawing tools. - if (mInpolLevel != -1){ + if (mStabilizerLevel != -1){ smoothMousePos(pos); } else { // No smoothing @@ -140,13 +140,13 @@ void StrokeManager::smoothMousePos(QPointF pos) // Smooth mouse position before drawing QPointF smoothPos; - if (mInpolLevel == 0) { + if (mStabilizerLevel == StabilizationLevel::NONE) { mLastPixel = mCurrentPixel; mCurrentPixel = pos; mLastInterpolated = mCurrentPixel; } - else if (mInpolLevel == 1) { + else if (mStabilizerLevel == StabilizationLevel::SIMPLE) { // simple interpolation smoothPos = QPointF( ( pos.x() + mCurrentPixel.x() ) / 2.0, ( pos.y() + mCurrentPixel.y() ) / 2.0 ); @@ -161,7 +161,7 @@ void StrokeManager::smoothMousePos(QPointF pos) } strokeQueue.push_back( smoothPos ); - } else if (mInpolLevel == 2 ) { + } else if (mStabilizerLevel == StabilizationLevel::STRONG ) { smoothPos = QPointF( ( pos.x() + mLastInterpolated.x() ) / 2.0, ( pos.y() + mLastInterpolated.y() ) / 2.0 ); @@ -186,7 +186,7 @@ void StrokeManager::smoothMousePos(QPointF pos) QPointF StrokeManager::interpolateStart(QPointF firstPoint) { - if (mInpolLevel == 1) { + if (mStabilizerLevel == StabilizationLevel::SIMPLE) { // Clear queue strokeQueue.clear(); pressureQueue.clear(); @@ -196,7 +196,7 @@ QPointF StrokeManager::interpolateStart(QPointF firstPoint) mLastPixel = firstPoint; } - else if (mInpolLevel == 2){ + else if (mStabilizerLevel == StabilizationLevel::STRONG){ mSingleshotTime.start(); previousTime = mSingleshotTime.elapsed(); @@ -220,7 +220,7 @@ QPointF StrokeManager::interpolateStart(QPointF firstPoint) // draw and poll each millisecond timer.setInterval(sampleSize); timer.start(); - } else if (mInpolLevel == 0) { + } else if (mStabilizerLevel == StabilizationLevel::NONE) { // Clear queue strokeQueue.clear(); pressureQueue.clear(); @@ -241,7 +241,7 @@ void StrokeManager::interpolatePoll() void StrokeManager::interpolatePollAndPaint() { - //qDebug() <<"inpol:" << mInpolLevel << "strokes"<< strokeQueue; + //qDebug() <<"inpol:" << mStabilizerLevel << "strokes"<< strokeQueue; if (!strokeQueue.isEmpty()) { interpolatePoll(); @@ -258,16 +258,16 @@ QList StrokeManager::interpolateStroke() y = 0, pressure = 0; - if (mInpolLevel == 1) { + if (mStabilizerLevel == StabilizationLevel::SIMPLE) { result = tangentInpolOp(result); } - else if (mInpolLevel == 2){ + else if (mStabilizerLevel == StabilizationLevel::STRONG){ result = meanInpolOp(result, x, y, pressure); - } else if (mInpolLevel == 0) { + } else if (mStabilizerLevel == StabilizationLevel::NONE) { result = noInpolOp(result); @@ -379,7 +379,7 @@ void StrokeManager::interpolateEnd() { // Stop timer timer.stop(); - if (mInpolLevel == 2) { + if (mStabilizerLevel == StabilizationLevel::STRONG) { if (!strokeQueue.isEmpty()) { diff --git a/core_lib/src/tool/strokemanager.h b/core_lib/src/tool/strokemanager.h index 0839e2d9b..ed05cef5a 100644 --- a/core_lib/src/tool/strokemanager.h +++ b/core_lib/src/tool/strokemanager.h @@ -39,10 +39,10 @@ class StrokeManager : public QObject void mouseMoveEvent(QMouseEvent* event); void mouseReleaseEvent(QMouseEvent* event); void setPressure(float pressure); - void setInpolLevel(int level); + void setStabilizerLevel(int level); float getPressure() { return mTabletPressure; } - int getInpolLevel() { return mInpolLevel; } + int getStabilizerLevel() { return mStabilizerLevel; } bool isTabletInUse() { return mTabletInUse; } QList interpolateStroke(); @@ -91,7 +91,7 @@ class StrokeManager : public QObject bool mTabletInUse = false; float mTabletPressure = 1.f; - int mInpolLevel = 0; + int mStabilizerLevel = 0; QPointF mTabletPosition; qreal mMeanPressure; diff --git a/core_lib/src/util/pencildef.h b/core_lib/src/util/pencildef.h index 4f10b2f4c..bae2e3496 100644 --- a/core_lib/src/util/pencildef.h +++ b/core_lib/src/util/pencildef.h @@ -53,7 +53,7 @@ enum ToolPropertyType USEFEATHER, VECTORMERGE, ANTI_ALIASING, - INTERPOLATION, + STABILIZATION, TOLERANCE, FILLCONTOUR }; @@ -63,6 +63,13 @@ enum BackgroundStyle }; +enum StabilizationLevel +{ + NONE, + SIMPLE, + STRONG +}; + // shortcuts command code #define CMD_NEW_FILE "CmdNewFile" #define CMD_OPEN_FILE "CmdOpenFile" From f1e93c375877f71df6314602989f1df5ba1b0f7b Mon Sep 17 00:00:00 2001 From: CandyFace Date: Mon, 23 Apr 2018 20:10:22 +0200 Subject: [PATCH 020/184] Fix stabilization and AA not being saved --- core_lib/src/tool/brushtool.cpp | 4 ++-- core_lib/src/tool/buckettool.cpp | 4 ++-- core_lib/src/tool/erasertool.cpp | 2 +- core_lib/src/tool/handtool.cpp | 2 +- core_lib/src/tool/movetool.cpp | 2 +- core_lib/src/tool/penciltool.cpp | 4 ++-- core_lib/src/tool/pentool.cpp | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core_lib/src/tool/brushtool.cpp b/core_lib/src/tool/brushtool.cpp index 8fd04717b..f4b24cd74 100644 --- a/core_lib/src/tool/brushtool.cpp +++ b/core_lib/src/tool/brushtool.cpp @@ -61,8 +61,8 @@ void BrushTool::loadSettings() properties.pressure = settings.value( "brushPressure", false ).toBool(); properties.invisibility = settings.value("brushInvisibility", true).toBool(); properties.preserveAlpha = OFF; - properties.inpolLevel = 0; - properties.useAA = 1; + properties.stabilizerLevel = settings.value("brushStabilization").toInt(); + properties.useAA = settings.value("brushAA").toInt(); if (properties.useFeather == true) { properties.useAA = -1; diff --git a/core_lib/src/tool/buckettool.cpp b/core_lib/src/tool/buckettool.cpp index 5090bec97..ec6db74d6 100644 --- a/core_lib/src/tool/buckettool.cpp +++ b/core_lib/src/tool/buckettool.cpp @@ -47,8 +47,8 @@ void BucketTool::loadSettings() { properties.width = 4; properties.feather = 10; - properties.inpolLevel = 0; - properties.useAA = -1; + properties.stabilizerLevel = StabilizationLevel::NONE; + properties.useAA = DISABLED; properties.tolerance = 10; m_enabledProperties[TOLERANCE] = true; diff --git a/core_lib/src/tool/erasertool.cpp b/core_lib/src/tool/erasertool.cpp index 382ea0056..755f5d8f5 100644 --- a/core_lib/src/tool/erasertool.cpp +++ b/core_lib/src/tool/erasertool.cpp @@ -56,7 +56,7 @@ void EraserTool::loadSettings() properties.pressure = settings.value( "eraserPressure" ).toBool(); properties.invisibility = DISABLED; properties.preserveAlpha = OFF; - properties.inpolLevel = 0; + properties.stabilizerLevel = settings.value("stabilizerLevel").toInt(); // First run if ( properties.width <= 0 ) diff --git a/core_lib/src/tool/handtool.cpp b/core_lib/src/tool/handtool.cpp index 7068dd9e7..e41939c84 100644 --- a/core_lib/src/tool/handtool.cpp +++ b/core_lib/src/tool/handtool.cpp @@ -39,7 +39,7 @@ void HandTool::loadSettings() properties.width = -1; properties.feather = -1; properties.useFeather = false; - properties.inpolLevel = -1; + properties.stabilizerLevel = -1; properties.useAA = -1; } diff --git a/core_lib/src/tool/movetool.cpp b/core_lib/src/tool/movetool.cpp index 12d17e861..f5093f222 100644 --- a/core_lib/src/tool/movetool.cpp +++ b/core_lib/src/tool/movetool.cpp @@ -43,7 +43,7 @@ void MoveTool::loadSettings() properties.width = -1; properties.feather = -1; properties.useFeather = false; - properties.inpolLevel = -1; + properties.stabilizerLevel = -1; properties.useAA = -1; } diff --git a/core_lib/src/tool/penciltool.cpp b/core_lib/src/tool/penciltool.cpp index 82b06799e..d8a3ce4b3 100644 --- a/core_lib/src/tool/penciltool.cpp +++ b/core_lib/src/tool/penciltool.cpp @@ -50,8 +50,8 @@ void PencilTool::loadSettings() properties.width = settings.value("pencilWidth").toDouble(); properties.feather = 50; properties.pressure = settings.value("pencilPressure").toBool(); - properties.inpolLevel = 0; - properties.useAA = -1; + properties.stabilizerLevel = settings.value("stabilizerLevel").toInt(); + properties.useAA = DISABLED; properties.useFeather = true; properties.useFillContour = false; diff --git a/core_lib/src/tool/pentool.cpp b/core_lib/src/tool/pentool.cpp index fb81595de..61298f698 100644 --- a/core_lib/src/tool/pentool.cpp +++ b/core_lib/src/tool/pentool.cpp @@ -48,7 +48,7 @@ void PenTool::loadSettings() properties.invisibility = OFF; properties.preserveAlpha = OFF; properties.useAA = settings.value( "brushAA").toBool(); - properties.inpolLevel = 0; + properties.stabilizerLevel = settings.value("stabilizerLevel").toInt(); // First run if ( properties.width <= 0 ) From 3dfb3191573a7d90a33cd845061e7040edc443fe Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 27 Apr 2018 10:10:24 +1000 Subject: [PATCH 021/184] Update v0.6.1 what's new link and date - remove ubuntu installation commands from Readme, but users can still find it on the donwload page. --- README.md | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 33d6e3e85..4d7b8eb0c 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,9 @@ ## Download ### -### Pencil2D 0.6.1 (15 April 2018) +### Pencil2D 0.6.1 (16 April 2018) -[What's new?](https://www.pencil2d.org/2017/12/introducing-pencil2d-0.6.html) +[What's new?](https://www.pencil2d.org/2018/04/maintenance-release-0.6.1.html) | Windows 64 bit | Windows 32 bit | Mac | Linux | | :--------------: | :---------------: | :-------------: | :---------------: | @@ -21,18 +21,6 @@ [2]: https://github.com/pencil2d/pencil/releases/download/v0.6.1.1/pencil2d-mac-0.6.1.1.zip [3]: https://github.com/pencil2d/pencil/releases/download/v0.6.1.1/pencil2d-linux-amd64-0.6.1.1.AppImage -### Debian & Ubuntu - -```bash -sudo apt-get install pencil2d -``` - -### Homebrew Cask (macOS) - -```bash -brew cask install pencil2d -``` - ### Nightly build Nightly builds are the bleeding edge versions of Pencil2D, which contains the most recent fixes and features. From 9a286304420e880ddeb2f564d13f65882aa78460 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Fri, 27 Apr 2018 12:58:44 +1000 Subject: [PATCH 022/184] Add Polish translation --- pencil2d.pro | 1 + translations/pencil_pl.qm | Bin 0 -> 76190 bytes translations/pencil_pl.ts | 3965 +++++++++++++++++++++++++++++++++ translations/translations.qrc | 1 + 4 files changed, 3967 insertions(+) create mode 100644 translations/pencil_pl.qm create mode 100644 translations/pencil_pl.ts diff --git a/pencil2d.pro b/pencil2d.pro index b718634ea..cd867b586 100644 --- a/pencil2d.pro +++ b/pencil2d.pro @@ -32,6 +32,7 @@ TRANSLATIONS += translations/pencil.ts \ translations/pencil_id.ts \ translations/pencil_it.ts \ translations/pencil_ja.ts \ + translations/pencil_pl.ts \ translations/pencil_pt.ts \ translations/pencil_pt_BR.ts \ translations/pencil_ru.ts \ diff --git a/translations/pencil_pl.qm b/translations/pencil_pl.qm new file mode 100644 index 0000000000000000000000000000000000000000..9919a286b84576be878181e2c822c29a9db3044a GIT binary patch literal 76190 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≪eR$KdyylK=e1J&@OV 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 + + + + AboutDialog + + + About + About Dialog Window Title + O programie + + + + Official site: <a href="https://www.pencil2d.org">pencil2d.org</a><br>Developed by: <b>Pascal Naidon, Patrick Corrieri, Matt Chang</b><br>Thanks to Qt Framework <a href="https://www.qt.io/download">https://www.qt.io/</a><br>miniz: <a href="https://github.com/richgel999/miniz">https://github.com/richgel999/miniz</a><br>Distributed under the <a href="http://www.gnu.org/licenses/gpl-2.0.html">GNU General Public License, version 2</a> + Strona domowa: <a href="https://www.pencil2d.org">pencil2d.org</a><br>Autorzy: <b>Pascal Naidon, Patrick Corrieri, Matt Chang</b><br>Podziękowania dla Qt Framework <a href="https://www.qt.io/download">https://www.qt.io/</a><br>miniz: <a href="https://github.com/richgel999/miniz">https://github.com/richgel999/miniz</a><br>Rozpowszechniono na podstawie <a href="http://www.gnu.org/licenses/gpl-2.0.html">GNU General Public License, version 2</a><br><br> +Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">reptile@o2.pl</a>, <a href="http://www.rpgmaker.pl">www.rpgmaker.pl</a></a>) + + + + Version: %1 + Version Number in About Dialog + Wersja %1 + + + + Copy to clipboard + Copy system info from About Dialog + Kopiuj do schowka + + + + ActionCommands + + + No sound layer exists as a destination for your import. Create a new sound layer? + Żadna warstwa dźwiękowa nie istnieje jako miejsce docelowe dla importu. Utwórz nową warstwę dźwiękową? + + + + Create sound layer + Utwórz warstwę dźwiękową + + + + Don't create layer + Nie twórz warstwy + + + + Layer Properties + Dialog title on creating a sound layer + Właściwości warstwy + + + + Sound Layer + Default name on creating a sound layer + Warstwa dźwiękowa + + + + Exporting movie + Eksportowanie filmu + + + + Finished. Open movie now? + When movie export done. + Gotowe. Czy otworzyć film? + + + + + + + Layer Properties + Właściwości warstwy + + + + + + + + Layer name: + Nazwa warstwy: + + + + A sound clip already exists on this frame! Please select another frame or layer. + Do tej ramki już dźwięk został przyposany! Wybierz inną ramkę lub warstwę. + + + + Exporting image sequence... + Eksportowanie sekwencji obrazów ... + + + + Abort + Anuluj + + + + Warning + Uwaga + + + + Unable to export image. + Nie można wyeksportować obrazu. + + + + Bitmap Layer + Warstwa bitmapowa + + + + Vector Layer + Warstwa wektorowa + + + + Camera Layer + Warstwa kamery + + + + Sound Layer + Warstwa dźwiękowa + + + + Delete Layer + Windows title of Delete current layer pop-up. + Usuń warstwę + + + + Are you sure you want to delete layer: + Czy na pewno usunąć zaznaczoną warstwę: + + + + Please keep at least one camera layer in project + text when failed to delete camera layer + Nie można usunąć warstwy kamery.Chociaż jedna warstwa kamery jest potrzebna w projekcie + + + + BaseTool + + + Pencil + Ołówek + + + + Eraser + Gumka + + + + Select + Zaznaczenie + + + + Move + Przesunięcie + + + + Hand + Ręka + + + + Smudge + Rozmazanie + + + + Pen + Pióro + + + + Polyline + Linia + + + + Bucket + Wypełniacz + + + + Eyedropper + Selektor kolorów + + + + Brush + Pędzel + + + + CameraPropertiesDialog + + + Camera Properties + Właściwości kamery + + + + Camera name: + Nazwa kamery: + + + + Camera size: + Rozmiar kamery: + + + + ColorBox + + + Color Wheel + Color Wheel's window title + Koło kolorów + + + + ColorInspector + + + HSV + HSV + + + + RGB + RGB + + + + + Red + Czerwony + + + + + Green + Zielony + + + + + Blue + Niebieski + + + + + + Alpha + Alfa + + + + Hue + Odcień + + + + Saturation + Nasycenie + + + + Value + Wartość + + + + ColorPalette + + + Color Palette + Window title of color palette. + Paleta kolorów + + + + Add Color + Dodaj kolor + + + + Remove Color + Usuń kolor + + + + ... + ... + + + + List Mode + Lista + + + + Show palette as a list + Wyświetlenie kolorów w palecie jako lista + + + + Grid Mode + Kafelki + + + + Show palette as icons + Wyświetlenie kolorów w palecie jako kafelki + + + + Small swatch + Małe ikony + + + + Sets swatch size to: 16x16px + Ustawienie próbki kolorów na rozmiar: 16x16px + + + + Medium Swatch + Średnie ikony + + + + Sets swatch size to: 26x26px + Ustawienie próbki kolorów na rozmiar: 26x26px + + + + Large Swatch + Duże ikony + + + + Sets swatch size to: 36x36px + Ustawienie próbki kolorów na rozmiar: 36x36px + + + + ColorPaletteWidget + + + + Colour name + Nazwa koloru + + + + DisplayOption + + + Horizontal flip + Obrót poziomy + + + + + + + + + + ... + ... + + + + Display + Window title of display options like . + Ekspozycja + + + + + Onion skin previous frame + Skóra cebuli: poprzednia ramka + + + + Show invisible lines + Wyświetl niewidzialne linie + + + + + Onion skin color: blue + Kolor skóry cebuli: niebieski + + + + + Onion skin next frame + Skóra cebuli: następna ramka + + + + + Onion skin color: red + Kolor skóry cebuli: czerwony + + + + Show outlines only + Wyświetl kontury + + + + Vertical flip + Obrót pionowy + + + + DoubleProgressDialog + + + Loading... + Wczytuje... + + + + Cancel + Anuluj + + + + Editor + + + + Paste + Wklej + + + + Remove frame + Usuń kratke + + + + + Import Image + Importuj obraz + + + + ErrorDialog + + + Dialog + Dialog + + + + <h3>Title</h3> + <h3>Tytuł</h3> + + + + Description + Opis + + + + ExportImageDialog + + + Export image sequence + Eksportuj sekwencję obrazów + + + + Export image + Eksportuj obraz + + + + ExportImageOptions + + + Camera + Kamera + + + + Resolution + Rozdzielczość + + + + Format + Format + + + + PNG + PNG + + + + JPG + JPG + + + + BMP + BMP + + + + Transparency + Przezroczystość + + + + ExportMovieDialog + + + Export Movie + Eksportuj film + + + + ExportMovieOptions + + + Camera + Kamera + + + + Resolution + Rozdzielczość + + + + Width + Szerokość + + + + Height + Wysokość + + + + Range + Zasięg + + + + The last frame you want to include in the exported movie + Ostatnia klatka, którą chcesz uwzględnić w wyeksportowanym filmie + + + + End Frame + Klatka końcowa + + + + The first frame you want to include in the exported movie + Pierwsza klatka, którą chcesz uwzględnić w wyeksportowanym filmie + + + + Start Frame + Klatka początkowa + + + + <html><head/><body><p>End frame is set to last paintable keyframe (Useful when you only want to export to the last animated frame)</p></body></html> + <html><head/><body><p>Klatka końcowa jest ustawiona na ostatnią możliwą do malowania klatkę kluczową (przydatna, gdy chcesz eksportować tylko do ostatniej animowanej klatki)</p></body></html> + + + + To the end of sound clips + Do końca dźwięku + + + + GIF and APNG only + Tylko GIF i APNG + + + + Loop + Pętla + + + + FileDialog + + + Open animation + Otwórz animacje + + + + Import image + Importuj obraz + + + + Import image sequence + Importuj sekwencje obrazów + + + + Import movie + Importuj film + + + + Import sound + Importuj dźwięk + + + + Import palette + Importuj palete + + + + Save animation + Zapisz animacje + + + + Export image + Eksportuj obraz + + + + Export image sequence + Eksportuj sekwencje obrazów + + + + Export movie + Eksportuj film + + + + Export sound + Eksportuj dźwięk + + + + Export palette + Eksportuj palete + + + + Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) + Dźwięk (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) + + + + + Palette (*.xml) + Paleta (*.xml) + + + + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) + + + + MyAnimation.pclx + moja_animacja.pclx + + + + FileManager + + + + + Invalid Save Path + Nieprawidłowa ścieżka zapisu + + + + The path ("%1") points to a directory. + Ścieżka ("%1") odnosi się do folderu. + + + + The directory ("%1") does not exist. + Folder ("%1") nie istnieje. + + + + The path ("%1") is not writable. + Ścieżka ("%1") nie umożliwia zapisu. + + + + + Cannot Create Data Directory + Nie można utworzyć folderu danych + + + + Failed to create directory "%1". Please make sure you have sufficient permissions. + Nie można utworzyć folderu "%1". Upewnij się, że masz wystarczające uprawnienia. + + + + "%1" is a file. Please delete the file and try again. + "%1" jest plikiem. Usuń plik i spróbuj ponownie. + + + + + Internal Error + Błąd wewnętrzny + + + + + An internal error occurred. Your file may not be saved successfully. + Wystąpił błąd wewnętrzny. Twój plik może nie zostać pomyślnie zapisany. + + + + FilesPage + + + Autosave documents + Preference + Automatyczny zapis dokumentu + + + + Enable autosave + Preference + Włącz autozapisywanie + + + + Number of modifications before autosaving: + Preference + Liczba modyfikacji przed autozapisaniem: + + + + GeneralPage + + + Language + GroupBox title in Preference + Język + + + + Window opacity + GroupBox title in Preference + Przezroczystość okna + + + + Background + GroupBox title in Preference + Tło + + + + Appearance + GroupBox title in Preference + Wygląd + + + + + [System-Language] + First item of the language list + [Język systemu] + + + + Canvas + GroupBox title in Preference + Kanwa + + + + Editing + GroupBox title in Preference + Edycja + + + + Grid + groupBox title in Preference + Siatka + + + + Czech + Czech + + + + Danish + Danish + + + + English + English + + + + German + German + + + + Spanish + Spanish + + + + French + French + + + + Hebrew + Hebrew + + + + Hungarian + Hungarian + + + + Indonesian + Indonesian + + + + Italian + Italian + + + + Japanese + Japanese + + + + Portuguese - Portugal + Portuguese - Portugal + + + + Portuguese - Brazil + Portuguese - Brazil + + + + Russian + Russian + + + + Slovenian + Slovenian + + + + Vietnamese + Vietnamese + + + + Chinese - Taiwan + Chinese - Taiwan + + + + Opacity + Przezroczystość + + + + Shadows + Cienie + + + + Tool Cursors + Kursor narzędzi + + + + Antialiasing + Wygładzanie krawędzi + + + + Dotted Cursor + Kursor wykropkowany + + + + Enable Grid + Włącz siatkę + + + + Vector curve smoothing + Wygładzanie krzywej wektorowej + + + + Tablet high-resolution position + Tablet wysokiej rozdzielczości + + + + Restart Required + Wymagane jest ponowne uruchomienie + + + + The language change will take effect after a restart of Pencil2D + Zmiana języka zostanie zastosowana po ponownym uruchomieniu Pencil2D + + + + ImportExportDialog + + + File + Plik + + + + Browse... + Przeglądaj... + + + + Options + Opcje + + + + ImportImageSeqDialog + + + Import image sequence + Import sekwencji obrazów + + + + ImportImageSeqOptions + + + Import an image every # frame + Importuj obraz co każdą # klatkę + + + + Layer + + + Undefined Layer + Niezdefiniowana warstwa + + + + LayerBitmap + + + Bitmap Layer + Warstwa bitmapowa + + + + LayerCamera + + + Camera Layer + Warstwa kamery + + + + LayerSound + + + Sound Layer + Warstwa dźwięku + + + + LayerVector + + + Vector Layer + Warstwa wektorowa + + + + MainWindow2 + + + MainWindow + Okno główne + + + + File + Plik + + + + Import + Import + + + + Export + Eksport + + + + Edit + Edycja + + + + Selection + Zaznaczenie + + + + View + Widok + + + + Onion Skin + Skóra cebuli + + + + Animation + Animacja + + + + + Tools + Narzędzia + + + + Layer + Warstwa + + + + + Help + Pomoc + + + + Windows + Okna + + + + New + Nowy + + + + Open + Otwórz + + + + Save + Zapisz + + + + Save As .. + Zapisz jako .. + + + + Exit + Zamknij + + + + + Image Sequence... + Sekwencje obrazów... + + + + + Image... + Obraz... + + + + + Movie... + Film... + + + + + Palette... + Paleta... + + + + Sound... + Dźwięk... + + + + Undo + Cofnij + + + + Redo + Ponów + + + + Cut + Wytnij + + + + Copy + Kopiuj + + + + Paste + Wklej + + + + Crop + Przytnij + + + + Crop To Selection + Przytnij do zaznaczenia + + + + Select All + Zaznacz wszystko + + + + Deselect All + Odznacz wszystko + + + + + Clear Frame + Czyść klate + + + + Preferences + Preferencje + + + + Reset Windows + Resetuj okna + + + + Zoom In + Powiększenie + + + + Zoom Out + Pomniejszenie + + + + Rotate Clockwise + Obrót w prawo (wg wskazówek zegarka) + + + + Rotate AntiClosewise + Obrót w lewo (przeciwnie do wskazówek zegarka) + + + + Reset Zoom/Rotate + Resetuj powiększenie/obrót + + + + Horizontal Flip + Obrót poziomy + + + + Vertical Flip + Obrót pionowy + + + + Preview + Podgląd + + + + Grid + Siatka + + + + Previous + Poprzednia + + + + Show previous onion skin + Wyświetl poprzednią skórę cebuli + + + + Next + Następna + + + + Show next onion skin + Wyświetl następną skórę cebuli + + + + + Play + Graj + + + + Loop + Pętla + + + + Next Frame + Następna klatka + + + + Previous Frame + Poprzednia klatka + + + + Extend Frame + Wydłuż klatkę + + + + Add Frame + Dodaj klatkę + + + + Duplicate Frame + Duplikuj klatki + + + + Remove Frame + Usuń klatkę + + + + Move + Przesuń + + + + Select + Zaznacz + + + + Brush + Pędzel + + + + Polyline + Linia + + + + Smudge + Rozmazanie + + + + Pen + Pióro + + + + Hand + Ręka + + + + Pencil + Ołówek + + + + Bucket + Wypełniacz + + + + Eyedropper + Selektor kolorów + + + + Eraser + Gumka + + + + New Bitmap Layer + Nowa warstwa bitmapowa + + + + New Vector Layer + Nowa warstwa wektorowa + + + + New Sound Layer + Nowa warstwa dźwiękowa + + + + New Camera Layer + Nowa warstwa kamery + + + + Delete Current Layer + Usuń aktualną warstwę + + + + About + O programie + + + + + Reset to default + Ustawienie podstawowe + + + + MultiLayer Onion Skin + Wielowarstwowa skóra cebuli + + + + Range + Zasięg + + + + Pencil2D Website + Strona Pencil2D + + + + Report a Bug + Zgłoś błąd + + + + Quick Reference Guide + Szybka instrukcja obsługi + + + + F1 + F1 + + + + + Next KeyFrame + Następna kluczowa klatka + + + + + Previous KeyFrame + Poprzednia kluczowa klatka + + + + Timeline + Oś czasu + + + + Options + Opcje + + + + Color Wheel + Koło koloru + + + + Color Palette + Paleta kolorów + + + + Display Options + Właściwości wyświetlenia + + + + Flip X + Obrót X + + + + Flip Y + Obrót Y + + + + Move Frame Forward + Przesuń klatkę do przodu + + + + Move Frame Backward + Przesuń klatkę do tyłu + + + + color palette:<br>use <b>(C)</b><br>toggle at cursor + Paleta kolorów: <br>użyj <b>(C)</b><br>by przełączyć kursor + + + + Lock Windows + Zablokuj okna + + + + Open Recent + Otwórz ostatnie pliki + + + + + + You have successfully cleared the list + + + Pomyślnie wyczyszczono listę + + + + + + + Warning + Uwaga + + + + + Pencil cannot read this file. If you want to import images, use the command import. + Pencil nie może odczytać tego pliku. Jeżeli chcesz wczytać obraz, użyj polecenia <b>importu</b>. + + + + Opening document... + Otwórz dokument... + + + + + + Abort + Anuluj + + + + Saving document... + Zapisuje dokument... + + + + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: + <br><br>Wystąpił błąd i plik nie został pomyślnie zapisany. Jeśli uważasz, że ten błąd dotyczy programu Pencil2D, utwórz nowy problem na stronie:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Pamiętaj, by w swoim zgłoszeniu uwzględnić następujące szczegóły: + + + + This animation has been modified. + Do you want to save your changes? + Animacja została zmieniona. +Czy zapisać zmiany? + + + + The animation is not saved yet. + Do you want to save now? + Animacja jeszcze nie została zapisana. +Czy zapisać ją teraz? + + + + Never ask again + AutoSave reminder button + Nigdy więcej nie pytaj + + + + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. + Nie można importować obrazu.<br><b>Podpowiedź:</b> Użyj warstwy bitmapowej dla importu bitmapy. + + + + Importing image sequence... + Importowanie sekwencji obrazów... + + + + + Undo + Menu item text + Cofnij + + + + Redo + Menu item text + Ponów + + + + Stop + Stop + + + + Object + + + Black + czarny + + + + Red + Czerwony + + + + Dark Red + Ciemny czerwony + + + + Orange + Pomarańczowy + + + + Dark Orange + Ciemny pomarańczowy + + + + Yellow + Żółty + + + + Dark Yellow + Ciemny żółty + + + + Green + Zielony + + + + Dark Green + Ciemny zielony + + + + Cyan + Cyan + + + + Dark Cyan + Ciemny cyan + + + + Blue + Niebieski + + + + Dark Blue + Ciemny niebieski + + + + White + Biały + + + + Very Light Grey + Bardzo jasny szary + + + + Light Grey + Jasny szary + + + + Grey + Szary + + + + Dark Grey + Ciemny szary + + + + Light Skin + Jasna skóra + + + + Light Skin - shade + Jasna skóra - odcień + + + + Skin + Skóra + + + + Skin - shade + Skóra - odcień + + + + Dark Skin + Ciemna skóra + + + + Dark Skin - shade + Ciemna skóra - odcień + + + + PencilApplication + + + Pencil2D is an animation/drawing software for Mac OS X, Windows, and Linux. It lets you create traditional hand-drawn animation (cartoon) using both bitmap and vector graphics. + Pencil2D to program do animacji / rysowania dla systemów Mac OS X, Windows i Linux. Pozwala tworzyć tradycyjne ręcznie rysowane animacje (rysunki) za pomocą zarówno bitmapy, jak i grafiki wektorowej. + + + + Path to the input pencil file. + Ścieżka dla pliku programu pencil. + + + + + Render the file to <output_path> + Renderuj plik do: <output_path> + + + + + output_path + ścieżka wyjścia + + + + Name of the camera layer to use + Nazwa warstwy kamery do użycia + + + + layer_name + Nazwa warstwy + + + + Width of the output frames + Szerokość krawędzi klatek + + + + + integer + liczba całkowita + + + + Height of the output frames + Wysokość krawędzi klatek + + + + The first frame you want to include in the exported movie + Pierwsza klatka, którą chcesz uwzględnić w wyeksportowanym filmie + + + + + frame + klatka + + + + The last frame you want to include in the exported movie. Can also be last or last-sound to automatically use the last frame containing animation or sound, respectively + Ostatnia klatka, którą chcesz uwzględnić w wyeksportowanym filmie. Może również być ostatnią lub ostatnim-dźwiękiem, aby automatycznie użyć ostatniej klatki zawierającej odpowiednio animację lub dźwięk + + + + Render transparency when possible + Renderuj przezroczystość, gdy to możliwe + + + + Warning: width value %1 is not an integer, ignoring. + Uwaga: szerokość: %1 nie jest wartością całkowitą, wprowadzonie zostaje zignorowane. + + + + Warning: height value %1 is not an integer, ignoring. + Uwaga: wysokość: %1 nie jest wartością całkowitą, wprowadzonie zostaje zignorowane. + + + + Warning: start value %1 is not an integer, ignoring. + Uwaga: wartość początkowa: %1 nie jest wartością całkowitą, wprowadzonie zostaje zignorowane. + + + + Warning: start value must be at least 1, ignoring. + Uwaga: wartość początkowa musi wynosić co najmniej 1, wprowadzonie zostaje zignorowane. + + + + Warning: end value %1 is not an integer, last or last-sound, ignoring. + Uwaga: wartość końcowa: %1 nie jest wartością całkowitą, wprowadzonie zostaje zignorowane. + + + + Warning: end value %1 is smaller than start value %2, ignoring. + Uwaga: wartość końca: %1 jest mniejsza niż wartość początkowa %2, wprowadzonie zostaje zignorowane. + + + + Error: No input file specified. + Błąd: nie określono pliku. + + + + Error: the input file at '%1' does not exist + Command line error + Błąd: wskazany plik w '%1' nie istnieje + + + + Error: the input path '%1' is not a file + Command line error + Błąd: wskazana ścieżka '%1' nie jest plikiem + + + + Warning: the specified camera layer %1 was not found, ignoring. + Uwaga: nie znaleziono określonej warstwa kamery %1, ignoruję akcję. + + + + Warning: Output format is not specified or unsupported. Using PNG. + Command line warning + Uwaga: format wyjściowy jest nie określony lub nie obsługiwany. Przejście do użycia PNG. + + + + Warning: Transparency is not currently supported in movie files + Command line warning + Uwaga: przezroczystość aktualnie nie jest obsługiwana dla plików filmowych + + + + Exporting movie... + Command line task progress + Eksportuje film... + + + + + Done. + Command line task done + Gotowe. + + + + Exporting image sequence... + Command line task progress + Eksportowanie sekwencji obrazów... + + + + PreferencesDialog + + + Preferences + Preferencje + + + + General + Ogólne + + + + Files + Pliki + + + + Timeline + Oś czasu + + + + Tools + Narzędzia + + + + Shortcuts + Skróty + + + + QApplication + + + Checking environment... + Sprawdzanie środowiska... + + + + Done + Gotowe + + + + QObject + + + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) + + + + Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) + Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) + + + + Everything ok. + Wszystko ok. + + + + Ooops, Something went wrong. + Oj, coś poszło nie tak. + + + + File doesn't exist. + Plik nie istnieje. + + + + Cannot open file. + Nie można otworzyć pliku. + + + + The file is not a valid xml document. + Plik nie jest prawidłowym dokumentem XML. + + + + The file is not valid pencil document. + Plik nie jest prawidłowym dokumentem ołówka. + + + + All Pencil Files PCLX & PCL(*.pclx *.pcl);;Pencil Animation File PCLX(*.pclx);;Old Pencil Animation File PCL(*.pcl);;Any files (*) + Wszystkie pliki Pencil PCLX & PCL(*.pclx *.pcl);;Pliki Pencil Animation PCLX(*.pclx);;Starsze pliki Pencil Animation PCL(*.pcl);;Wszystkie pliki (*) + + + + Pencil Animation File PCLX(*.pclx);;Old Pencil Animation File PCL(*.pcl) + Pliki Pencil Animation PCLX(*.pclx);;Stare pliki Pencil Animation PCL(*.pcl) + + + + Vivid Pink + Żywy różowy + + + + Strong Pink + Mocny różowy + + + + Deep Pink + Głęboki róż + + + + Light Pink + Jasny róż + + + + Moderate Pink + Umiarkowany róż + + + + Dark Pink + Ciemny róż + + + + Pale Pink + Blady róż + + + + Grayish Pink + Szary róż + + + + Pinkish White + Różowaty biały + + + + Pinkish Gray + Różowaty szary + + + + Vivid Red + Żywy czerwony + + + + Strong Red + Mocny czerwony + + + + Deep Red + Głęboki czerwony + + + + Very Deep Red + Bardzo głęboki czerwony + + + + Moderate Red + Umiarkowany czerwień + + + + Dark Red + Ciemny czerwony + + + + Very Dark Red + Bardzo ciemny czerwień + + + + Light Grayish Red + Jasny szary czerwień + + + + Grayish Red + Szary czerwień + + + + Dark Grayish Red + Ciemny szary czerwień + + + + Blackish Red + Czarny czerwień + + + + Reddish Gray + Czerwony szary + + + + Dark Reddish Gray + Ciemny czerwony szary + + + + Reddish Black + Czerwień czarny + + + + Vivid Yellowish Pink + Żywy żółty róż + + + + Strong Yellowish Pink + Mocny żółty róż + + + + Deep Yellowish Pink + Głęboki żółty róż + + + + Light Yellowish Pink + Jasny żółty róż + + + + Moderate Yellowish Pink + Umiarkowany żółty róż + + + + Dark Yellowish Pink + Ciemny żółty róż + + + + Pale Yellowish Pink + Blady żółty róż + + + + Grayish Yellowish Pink + Szary żółty róż + + + + Brownish Pink + Brązowaty róż + + + + Vivid Reddish Orange + Żywy czerwień pomarańcz + + + + Strong Reddish Orange + Mocny czerwień pomarańcz + + + + Deep Reddish Orange + Głęboki czerwień pomarańcz + + + + Moderate Reddish Orange + Umiarkowany czerwień pomarańcz + + + + Dark Reddish Orange + Ciemny czerwień pomarańcz + + + + Grayish Reddish Orange + Szary czerwień pomarańcz + + + + Strong Reddish Brown + Mocny czerwień brąz + + + + Deep Reddish Brown + Głęboki czerwień brąz + + + + Light Reddish Brown + Jasny czerwień brąz + + + + Moderate Reddish Brown + Umiarkowany czerwień brąz + + + + Dark Reddish Brown + Ciemny czerwień brąz + + + + Light Grayish Reddish Brown + Jasny szarawy czerwień brąz + + + + Grayish Reddish Brown + Szarawy czerwień brąz + + + + Dark Grayish Reddish Brown + Ciemny szarawy czerwień brąz + + + + Vivid Orange + Żywy pomarańcz + + + + Brilliant Orange + Błyszczący pomarańcz + + + + Strong Orange + Mocny pomarańcz + + + + Deep Orange + Głęboki pomarańcz + + + + Light Orange + Jasny pomarańcz + + + + Moderate Orange + Umiarkowany pomarańcz + + + + Brownish Orange + Brązowy pomarańcz + + + + Strong Brown + Mocny brąz + + + + Deep Brown + Głęboki brąz + + + + Light Brown + Jasny brąz + + + + Moderate Brown + Umiarkowany brąz + + + + Dark Brown + Ciemny brąz + + + + Light Grayish Brown + Jasny szarawy brąz + + + + Grayish Brown + Szarawy brąz + + + + Dark Grayish Brown + Ciemny szarawy brąz + + + + Light Brownish Gray + Jasny brązowaty szary + + + + Brownish Gray + Brązowaty szary + + + + Brownish Black + Brązowata czerń + + + + Vivid Orange Yellow + Żywy pomarańczowo żółty + + + + Brilliant Orange Yellow + Błyszczący pomarańczowo żółty + + + + Strong Orange Yellow + Mocny pomarańczowo żółty + + + + Deep Orange Yellow + Głęboki pomarańczowo żółty + + + + Light Orange Yellow + Jasny pomarańczowo żółty + + + + Moderate Orange Yellow + Umiarkowany pomarańczowo żółty + + + + Dark Orange Yellow + Ciemny pomarańczowo żółty + + + + Pale Orange Yellow + Blady pomarańczowo żółty + + + + Strong Yellowish Brown + Mocny żółty brąz + + + + Deep Yellowish Brown + Głęboki żółty brąz + + + + Light Yellowish Brown + Jasny żółty brąz + + + + Moderate Yellowish Brown + Umiarkowany żółty brąz + + + + Dark Yellowish Brown + Ciemny żółty brąz + + + + Light Grayish Yellowish Brown + Jasny szarowaty żółty brąz + + + + Grayish Yellowish Brown + Szarowaty żółty brąz + + + + Dark Grayish Yellowish Brown + Ciemny szarawy żółty brąz + + + + Vivid Yellow + Żywy żółty + + + + Brilliant Yellow + Błyszczący żółty + + + + Strong Yellow + Mocny żółty + + + + Deep Yellow + Głęboki żółty + + + + Light Yellow + Jasny żółty + + + + Moderate Yellow + Umiarkowany żółty + + + + Dark Yellow + Ciemny żółty + + + + Pale Yellow + Blady żółty + + + + Grayish Yellow + Szarawy żółty + + + + Dark Grayish Yellow + Ciemny szarawy żółty + + + + Yellowish White + Żółtawa biel + + + + Yellowish Gray + Żółtawy szary + + + + Light Olive Brown + Jasny oliwkowo brązowy + + + + Moderate Olive Brown + Umiarkowany oliwkowo brązowy + + + + Dark Olive Brown + Ciemny oliwkowo brązowy + + + + Vivid Greenish Yellow + Żywy zielono żółty + + + + Brilliant Greenish Yellow + Błyszczący zielono żółty + + + + Strong Greenish Yellow + Mocny zielono żółty + + + + Deep Greenish Yellow + Głęboki zielono żółty + + + + Light Greenish Yellow + Jasny zielono żółty + + + + Moderate Greenish Yellow + Umiarkowany zielono żółty + + + + Dark Greenish Yellow + Ciemny zielono żółty + + + + Pale Greenish Yellow + Blady zielono żółty + + + + Grayish Greenish Yellow + Szarawy zielono żółty + + + + Light Olive + Jasny oliwkowy + + + + Moderate Olive + Umiarkowany oliwkowy + + + + Dark Olive + Ciemny oliwkowy + + + + Light Grayish Olive + Jasny szarawy oliwkowy + + + + Grayish Olive + Szarawy oliwkowy + + + + Dark Grayish Olive + Ciemny szarawy oliwkowy + + + + Light Olive Gray + Jasny oliwkowo szary + + + + Olive Gray + Oliwkowo szary + + + + Olive Black + Oliwkowo czarny + + + + Vivid Yellow Green + Żywy żółto zielony + + + + Brilliant Yellow Green + Błyszczący żółto zielony + + + + Strong Yellow Green + Mocny żółto zielony + + + + Deep Yellow Green + Głęboki żółto zielony + + + + Light Yellow Green + Jasny żółto zielony + + + + Moderate Yellow Green + Umiarkowany żółto zielony + + + + Pale Yellow Green + Blady żółto zielony + + + + Grayish Yellow Green + Szarawy żółto zielony + + + + Strong Olive Green + Mocny oliwkowo zielony + + + + Deep Olive Green + Głęboki oliwkowo zielony + + + + Moderate Olive Green + Umiarkowany oliwkowo zielony + + + + Dark Olive Green + Ciemny oliwkowo zielony + + + + Grayish Olive Green + Szarawy oliwkowo zielony + + + + Dark Grayish Olive Green + Ciemny szarawy oliwkowo zielony + + + + Vivid Yellowish Green + Żywy żółtawo zielony + + + + Brilliant Yellowish Green + Błyszczący żółtawo zielony + + + + Strong Yellowish Green + Mocny żółtawo zielony + + + + Deep Yellowish Green + Głęboki żółtawo zielony + + + + Very Deep Yellowish Green + Bardzo błęboki żółtawo zielony + + + + Very Light Yellowish Green + Bardzo jasny żółtawo zielony + + + + Light Yellowish Green + Jasny żółtawo zielony + + + + Moderate Yellowish Green + Umiarkowany żółtawo zielony + + + + Dark Yellowish Green + Ciemny żółtawo zielony + + + + Very Dark Yellowish Green + Bardzo ciemny żółtawo zielony + + + + Vivid Green + Żywy zielony + + + + Brilliant Green + Błyszczący zielony + + + + Strong Green + Mocny zielony + + + + Deep Green + Głęboki zielony + + + + Very Light Green + Bardzo jasny zielony + + + + Light Green + Jasny zielony + + + + Moderate Green + Umiarkowany zielony + + + + Dark Green + Ciemny zielony + + + + Very Dark Green + Bardzo ciemny zielony + + + + Very Pale Green + Bardzo blady zielony + + + + Pale Green + Blady zielony + + + + Grayish Green + Szarawy zielony + + + + Dark Grayish Green + Ciemny szarawy zielony + + + + Blackish Green + Czarnowata zieleń + + + + Greenish White + Zielonkowaty biały + + + + Light Greenish Gray + Jasny zielony szary + + + + Greenish Gray + Zielony szary + + + + Dark Greenish Gray + Ciemny zielony szary + + + + Greenish Black + Zielonkowata czerń + + + + Vivid Bluish Green + Żywy niebieskawo zielony + + + + Brilliant Bluish Green + Błyszczący niebieskawo zielony + + + + Strong Bluish Green + Mocny niebieskawo zielony + + + + Deep Bluish Green + Głęboki niebieskawo zielony + + + + Very Light Bluish Green + Bardzo jasny niebieskawo zielony + + + + Light Bluish Green + Jasny niebieskawo zielony + + + + Moderate Bluish Green + Umiarkowany niebieskawo zielony + + + + Dark Bluish Green + Ciemny niebieskawo zielony + + + + Very Dark Bluish Green + Bardzo ciemny niebieskawo zielony + + + + Vivid Greenish Blue + Żywy zielonkowaty niebieski + + + + Brilliant Greenish Blue + Błyszczący zielonkowaty niebieski + + + + Strong Greenish Blue + Mocny zielonkowaty niebieski + + + + Deep Greenish Blue + Głęboki zielonkowaty niebieski + + + + Very Light Greenish Blue + Bardzo jasny zielonkowaty niebieski + + + + Light Greenish Blue + Jasny zielonkowaty niebieski + + + + Moderate Greenish Blue + Umiarkowany zielonkowaty niebieski + + + + Dark Greenish Blue + Ciemny zielonkowaty niebieski + + + + Very Dark Greenish Blue + Bardzo ciemny zielonkowaty niebieski + + + + Vivid Blue + Żywy niebieski + + + + Brilliant Blue + Błyszczący niebieski + + + + Strong Blue + Mocny niebieski + + + + Deep Blue + Głęboki niebieski + + + + Very Light Blue + Bardzo jasny niebieski + + + + Light Blue + Jasny niebieski + + + + Moderate Blue + Umiarkowany niebieski + + + + Dark Blue + Ciemny niebieski + + + + Very Pale Blue + Bardzo blady niebieski + + + + Pale Blue + Blady niebieski + + + + Grayish Blue + Szarawy niebieski + + + + Dark Grayish Blue + Ciemny szarawy niebieski + + + + Blackish Blue + Czarny niebieski + + + + Bluish White + Niebieskowata biel + + + + Light Bluish Gray + Jasny niebiesko szary + + + + Bluish Gray + Niebiesko szary + + + + Dark Bluish Gray + Ciemny niebiesko szary + + + + Bluish Black + Niebiesko czarny + + + + Vivid Purplish Blue + Żywy fioletowato niebieski + + + + Brilliant Purplish Blue + Błyszczący fioletowato niebieski + + + + Strong Purplish Blue + Mocny fioletowato niebieski + + + + Deep Purplish Blue + Głęboki fioletowato niebieski + + + + Very Light Purplish Blue + Bardzo jasny fioletowato niebieski + + + + Light Purplish Blue + Jasny fioletowato niebieski + + + + Moderate Purplish Blue + Umiarkowany fioletowato niebieski + + + + Dark Purplish Blue + Ciemny fioletowato niebieski + + + + Very Pale Purplish Blue + Bardzo blady fioletowato niebieski + + + + Pale Purplish Blue + Blady fioletowato niebieski + + + + Grayish Purplish Blue + Szarawy fioletowato niebieski + + + + Vivid Violet + Żywy fioletowy + + + + Brilliant Violet + Błyszczący fioletowy + + + + Strong Violet + Mocny fioletowy + + + + Deep Violet + Głęboki fioletowy + + + + Very Light Violet + Bardzo jasny fioletowy + + + + Light Violet + Jasny fioletowy + + + + Moderate Violet + Umiarkowany fioletowy + + + + Dark Violet + Ciemny fioletowy + + + + Very Pale Violet + Bardzo blady fioletowy + + + + Pale Violet + Blady fioletowy + + + + Grayish Violet + Szarawy fioletowy + + + + Vivid Purple + Żywy purpurowy + + + + Brilliant Purple + Błyszczący purpurowy + + + + Strong Purple + Mocny purpurowy + + + + Deep Purple + Głęboki purpurowy + + + + Very Deep Purple + Bardzo głęboki purpurowy + + + + Very Light Purple + Bardzo jasny purpurowy + + + + Light Purple + Jasny purpurowy + + + + Moderate Purple + Umiarkowany purpurowy + + + + Dark Purple + Ciemny purpurowy + + + + Very Dark Purple + Bardzo ciemny purpurowy + + + + Very Pale Purple + Bardzo blady purpurowy + + + + Pale Purple + Blady purpurowy + + + + Grayish Purple + Szarawy purpurowy + + + + Dark Grayish Purple + Ciemny szarawy purpurowy + + + + Blackish Purple + Czarny purpurowy + + + + Purplish White + Purpurowa biel + + + + Light Purplish Gray + Jasny purpurowy szary + + + + Purplish Gray + Purpurowo szary + + + + Dark Purplish Gray + Ciemny purpurowo szary + + + + Purplish Black + Purpurowo czarny + + + + Vivid Reddish Purple + Żywy fuksja + + + + Strong Reddish Purple + Mocny fuksja + + + + Deep Reddish Purple + Głęboki fuksja + + + + Very Deep Reddish Purple + Bardzo głęboki fuksja + + + + Light Reddish Purple + Jasny fuksja + + + + Moderate Reddish Purple + Umiarkowany fuksja + + + + Dark Reddish Purple + Ciemny fuksja + + + + Very Dark Reddish Purple + Bardzo ciemny fuksja + + + + Pale Reddish Purple + Blady fuksja + + + + Grayish Reddish Purple + Szarawy fuksja + + + + Brilliant Purplish Pink + Błyszczący malinowy + + + + Strong Purplish Pink + Mocny malinowy + + + + Deep Purplish Pink + Głęboki malinowy + + + + Light Purplish Pink + Jasny malinowy + + + + Moderate Purplish Pink + Umiarkowany malinowy + + + + Dark Purplish Pink + Ciemny malinowy + + + + Pale Purplish Pink + Blady malinowy + + + + Grayish Purplish Pink + Szarawy malinowy + + + + Vivid Purplish Red + Żywy magenta + + + + Strong Purplish Red + Mocny magenta + + + + Deep Purplish Red + Głęboki magenta + + + + Very Deep Purplish Red + Bardzo głęboki magenta + + + + Moderate Purplish Red + Umiarkowany magenta + + + + Dark Purplish Red + Ciemny magenta + + + + Very Dark Purplish Red + Bardzo ciemny magenta + + + + Light Grayish Purplish Red + Jasny szarawy magenta + + + + Grayish Purplish Red + Szarawy magenta + + + + White + Biały + + + + Light Gray + Jasny szary + + + + Medium Gray + Średni szary + + + + Dark Gray + Ciemny szary + + + + Black + Czarny + + + + RecentFileMenu + + + Open Recent + Otwórz ostatnie pliki + + + + Clear + Czyść + + + + ScribbleArea + + + Warning + Uwaga + + + + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). + Aktualnie rysujesz na ukrytej warstwie! Użyj innej warstwy (albo zmień obecną warstwę na widoczną). + + + + Delete Selection + Undo Step: clear the selection area. + Usuń zaznaczenie + + + + + Clear Image + Undo step text + Czyść obraz + + + + There is a gap in your drawing (or maybe you have zoomed too much). + Znaleziono lukę w rysunku (bądź obraz został za bardzo powiększony). + + + + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). + Przepraszam! Ta opcja nie zawsze działa poprawnie. Spróbuj ponownie (powiększ nieco, kliknij w inne miejsce...)<br> +jeżeli to nie pomoże, to spróbuj powiększyć i sprawdź, czy ścieżki są połączone (naciskając klawisz F1). + + + + Out of bound. + Brak powiązania. + + + + Could not find a closed path. + Nie można znaleźć zamkniętej ścieżki. + + + + Could not find the root index. + Nie można znaleźć głównego indeksu. + + + + %1<br><br>Error: %2 + %1<br><br>Błąd: %2 + + + + Flood fill error + Błąd napełnianiu wypełnienia + + + + ShortcutsPage + + + Form + Forma + + + + Action: + Akcja: + + + + None + Brak + + + + Shortcuts: + Skróty: + + + + clear + czyść + + + + Restore Default Shortcuts + Przywróć domyślne skróty + + + + Shortcut Conflict! + Konflikt skrótów! + + + + %1 is already used, overwrite? + %1 jest już w użyciu, czy chcesz go nadpisać? + + + + TimeControls + + + Range + Zasięg + + + + Frames per second + Klatek na sekundę + + + + Start of playback loop + Początek pętli odtwarzania + + + + End of playback loop + Koniec pętli odtwarzania + + + + Playback range + Zakres odtwarzania + + + + Play + Graj + + + + Loop + Pętla + + + + Sound on/off + Dźwięk ON/OFF + + + + End + Koniec + + + + + Start + Początek + + + + Stop + Stop + + + + TimeLine + + + Timeline + Oś czasu + + + + Layers: + Warstwy: + + + + Add Layer + Dodaj warstwę + + + + Remove Layer + Usuń warstwę + + + + New Bitmap Layer + Nowa warstwa bitmapowa + + + + New Vector Layer + Nowa warstwa wektorowa + + + + New Sound Layer + Nowa warstwa dźwiękowa + + + + New Camera Layer + Nowa warstwa kamery + + + + &Layer + Timeline add-layer menu + &Warstwa + + + + Keys: + Klucze: + + + + Add Frame + Dodaj ramkę + + + + Remove Frame + Usuń ramkę + + + + Duplicate Frame + Duplikuj ramkę + + + + Onion skin: + Skóra cebuli: + + + + Toggle match keyframes + Przełącz dopasowane klatki kluczowe + + + + Delete Layer + Windows title of Delete current layer pop-up. + Usuń warstwę + + + + Please keep at least one camera layer in project + Zachowaj co najmniej jedną warstwę kamery w projekcie + + + + Are you sure you want to delete layer: + Czy na pewno chcesz usunąć warstwę: + + + + TimeLineCells + + + Layer Properties + Właściwości warstwy + + + + Layer name: + Nazwa warstwy: + + + + Timeline2 + + + Timeline + Oś czasu + + + + Layers + Warstwa + + + + + ... + ... + + + + TimelinePage + + + Timeline + Oś czasu + + + + Timeline length: + Preferences + Długość osi czasu: + + + + Frame size + Rozmiar ramki + + + + Short scrub + Króta organizacja + + + + ToolBoxWidget + + + Tools + Window title of tool box + Narzędzia + + + + Pencil Tool (%1): Sketch with pencil + Ołówek (%1): Szkic ołówkiem + + + + Select Tool (%1): Select an object + Zaznaczenie (%1): zaznacz obszar lub objekt + + + + Move Tool (%1): Move an object + Przesunięcie (%1): przesuń obiekt + + + + Hand Tool (%1): Move the canvas + Ręka (%1): przesunięcie kanwy + + + + Pen Tool (%1): Sketch with pen + Pióro (%1): Szkic piórem + + + + Eraser Tool (%1): Erase + Gumka (%1): narzędzie do czyszczenia + + + + Polyline Tool (%1): Create line/curves + Linia (%1): narzędzie do tworzenia liń i krzywych + + + + Paint Bucket Tool (%1): Fill selected area with a color + Wypełniacz (%1): wypełnia kolorem zaznaczony obszar + + + + Brush Tool (%1): Paint smooth stroke with a brush + Pędzel (%1) rysuje gładklie kreski za pomocą pędzla + + + + Eyedropper Tool (%1): Set color from the stage<br>[ALT] for instant access + Selektor kolorów (%1) Pobiera zaznaczony kolor<br>[ALT] by osiągnąc natychmiastowy dostęp + + + + Clear Frame (%1): Erases content of selected frame + Czyść ramkę (%1) Usuwa zawartość zaznaczonej ramki + + + + Smudge Tool (%1):<br>Edit polyline/curves<br>Liquify bitmap pixels<br> (%1)+[Alt]: Smooth + Rozmazanie (%1):<br> Edytuje linie i krzywe<br>Rozmazuje bitmapowe pixele<br> (%1)+[Alt]: rozmazanie + + + + Pencil Tool (%1) + Ołówek (%1) + + + + Select Tool (%1) + Zaznaczenie (%1) + + + + Move Tool (%1) + Przesunięcie (%1) + + + + Hand Tool (%1) + Ręka (%1) + + + + Pen Tool (%1) + Pióro (%1) + + + + Eraser Tool (%1) + Gumka (%1) + + + + Polyline Tool (%1) + Linia (%1) + + + + Paint Bucket Tool (%1) + Wypełniacz (%1) + + + + Brush Tool (%1) + Pędzel (%1) + + + + Eyedropper Tool (%1) + Selektor kolorów (%1) + + + + Clear Tool (%1) + Czyść (%1) + + + + Smudge Tool (%1) + Rozmazanie (%1) + + + + ToolOptionWidget + + + Brush + Pędzel + + + + Feather + Piórko + + + + Color Tolerance + Tolerancja koloru + + + + Options + Window title of tool option panel like pen width, feather etc.. + Opcje + + + + Stroke Thickness + Grubość + + + + Width + Szerokość + + + + ToolOptions + + + Form + Forma + + + + Set Pen Width <br><b>[SHIFT]+drag</b><br>for quick adjustment + Ustawienie szerokości pędzla<br><b>[SHIFT]+przesunięcie muszką</b> dla szybkiego ustawienia + + + + Set Pen Feather <br><b>[CTRL]+drag</b><br>for quick adjustment + Ustawienia dla piórka<br><b>[SHIFT]+przesunięcie muszką</b> dla szybkiego ustawienia + + + + Enable or disable feathering + Włącz lub wyłącz wtapianie + + + + Use Feather + Wtapianie + + + + Contour will be filled + Kontur do wypełnienia + + + + Fill Contour + Wypełnij kontur + + + + The extend to which the color variation will be treated as being equal + Zakres, w jakim zmiana koloru będzie traktowana jako równa + + + + Bezier + Bezier + + + + Pressure + Brush + Nacisk + + + + Anti-Aliasing + Brush AA + Wygładzanie krawędzi + + + + Merge + Vector line merge + Łączenie + + + + None + Stabilizer option + Brak + + + + Simple + Stabilizer option + Proste + + + + Strong + Stabilizer option + Mocne + + + + Make invisible + Zrób niewidzialne + + + + Invisible + Niewidzialność + + + + Preserve Alpha + Zachowaj kanał alfa + + + + Alpha + Alfa + + + + Merge vector lines when they are close together + Łącz linie wektorowe kiedy są blisko siebie + + + + Stabilizer + Stabilizator + + + + ToolsPage + + + Onion skin + Skóra cebuli + + + + Maximum onion opacity % + Maksymalny prześwit cebuli % + + + + Minimum onion opacity % + Minimalny prześwit cebuli % + + + + Number of previous onion frames shown + Ilość poprzednich ramek cebuli do pokazania + + + + Number of next onion frames shown + Ilość następnych ramek cebuli do pokazania + + + + Brush Tools + Pędzel + + + + Use Quick Sizing + Szybkie wymiarowanie + + + diff --git a/translations/translations.qrc b/translations/translations.qrc index d21345432..e04b3aeb0 100644 --- a/translations/translations.qrc +++ b/translations/translations.qrc @@ -10,6 +10,7 @@ pencil_id.qm pencil_it.qm pencil_ja.qm + pencil_pl.qm pencil_pt.qm pencil_pt_BR.qm pencil_ru.qm From 2db47d58bfe8f165308d343f45bb12f38f09f892 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Fri, 27 Apr 2018 13:06:36 +1000 Subject: [PATCH 023/184] Add Estonian translation --- pencil2d.pro | 1 + translations/pencil_et.qm | Bin 0 -> 30527 bytes translations/pencil_et.ts | 3959 +++++++++++++++++++++++++++++++++ translations/translations.qrc | 1 + 4 files changed, 3961 insertions(+) create mode 100644 translations/pencil_et.qm create mode 100644 translations/pencil_et.ts diff --git a/pencil2d.pro b/pencil2d.pro index cd867b586..40ef49ca6 100644 --- a/pencil2d.pro +++ b/pencil2d.pro @@ -26,6 +26,7 @@ TRANSLATIONS += translations/pencil.ts \ translations/pencil_da.ts \ translations/pencil_de.ts \ translations/pencil_es.ts \ + translations/pencil_et.ts \ translations/pencil_fr.ts \ translations/pencil_he.ts \ translations/pencil_hu_HU.ts \ diff --git a/translations/pencil_et.qm b/translations/pencil_et.qm new file mode 100644 index 0000000000000000000000000000000000000000..d4fada340ad4350c96ca626d253135c644be9c72 GIT binary patch literal 30527 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%0A^1n;>A*gPm%Bv}?Y!O?Q2Hp$|9{(kEfCXoeZD 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 Nhv8PtP1U@4{~v9A8>j#P literal 0 HcmV?d00001 diff --git a/translations/pencil_et.ts b/translations/pencil_et.ts new file mode 100644 index 000000000..a06e4d9e7 --- /dev/null +++ b/translations/pencil_et.ts @@ -0,0 +1,3959 @@ + + + AboutDialog + + + About + About Dialog Window Title + Info + + + + Official site: <a href="https://www.pencil2d.org">pencil2d.org</a><br>Developed by: <b>Pascal Naidon, Patrick Corrieri, Matt Chang</b><br>Thanks to Qt Framework <a href="https://www.qt.io/download">https://www.qt.io/</a><br>miniz: <a href="https://github.com/richgel999/miniz">https://github.com/richgel999/miniz</a><br>Distributed under the <a href="http://www.gnu.org/licenses/gpl-2.0.html">GNU General Public License, version 2</a> + Ametlik veebisait: <a href="https://www.pencil2d.org">pencil2d.org</a><br>Arendaja: <b>Pascal Naidon, Patrick Corrieri, Matt Chang</b><br>Suur tänu Qt Frameworkile <a href="https://www.qt.io/download">https://www.qt.io/</a><br>miniz: <a href="https://github.com/richgel999/miniz">https://github.com/richgel999/miniz</a><br>Levitatakse <a href="http://www.gnu.org/licenses/gpl-2.0.html">GNU General Public License, version 2</a> alusel + + + + Version: %1 + Version Number in About Dialog + Versioon: %1 + + + + Copy to clipboard + Copy system info from About Dialog + Kopeeri lõikelauale + + + + ActionCommands + + + No sound layer exists as a destination for your import. Create a new sound layer? + Importimise sihtkohas pole helikihti. Kas loon uue helikihi? + + + + Create sound layer + Loo helikiht + + + + Don't create layer + Ära loo kihti + + + + Layer Properties + Dialog title on creating a sound layer + Kihi omadused + + + + Sound Layer + Default name on creating a sound layer + Helikiht + + + + Exporting movie + Video eksportimine + + + + Finished. Open movie now? + When movie export done. + Lõpetatud. Kas avada video? + + + + + + + Layer Properties + Kihi omadused + + + + + + + + Layer name: + Kihi nimi: + + + + A sound clip already exists on this frame! Please select another frame or layer. + + + + + Exporting image sequence... + Pildiseeria importimine... + + + + Abort + Katkesta + + + + Warning + Hoiatus + + + + Unable to export image. + Pildi eksportimine ebaõnnestus. + + + + Bitmap Layer + + + + + Vector Layer + Vektorkiht + + + + Camera Layer + Kaamera kiht + + + + Sound Layer + Helikiht + + + + Delete Layer + Windows title of Delete current layer pop-up. + Kustuta kiht + + + + Are you sure you want to delete layer: + Oled sa kindel, et soovid kusutada kihti: + + + + Please keep at least one camera layer in project + text when failed to delete camera layer + Palun hoia projektis alles vähemalt üks kaamerakiht + + + + BaseTool + + + Pencil + Pliiats + + + + Eraser + Kustukumm + + + + Select + Valimine + + + + Move + Liigutamine + + + + Hand + Käsi + + + + Smudge + Hägustamine + + + + Pen + Pliiats + + + + Polyline + + + + + Bucket + + + + + Eyedropper + + + + + Brush + Pintsel + + + + CameraPropertiesDialog + + + Camera Properties + Kaamera omadused + + + + Camera name: + Kaamera nimi: + + + + Camera size: + Kaamera suurus: + + + + ColorBox + + + Color Wheel + Color Wheel's window title + Värvi ratas + + + + ColorInspector + + + HSV + HSV + + + + RGB + RGB + + + + + Red + Punane + + + + + Green + Roheline + + + + + Blue + Sinine + + + + + + Alpha + Alfa + + + + Hue + + + + + Saturation + Küllastus + + + + Value + Väärtus + + + + ColorPalette + + + Color Palette + Window title of color palette. + Värvipalett + + + + Add Color + Lisa värv + + + + Remove Color + Eemalda värv + + + + ... + ... + + + + List Mode + Nimekirjarežiim + + + + Show palette as a list + Näita paletti nimekirjana + + + + Grid Mode + Võrgustiku režiim + + + + Show palette as icons + Näita palette ikoonidena + + + + Small swatch + + + + + Sets swatch size to: 16x16px + + + + + Medium Swatch + + + + + Sets swatch size to: 26x26px + + + + + Large Swatch + + + + + Sets swatch size to: 36x36px + + + + + ColorPaletteWidget + + + + Colour name + Värvi nimi + + + + DisplayOption + + + Horizontal flip + + + + + + + + + + + ... + ... + + + + Display + Window title of display options like . + Vaade + + + + + Onion skin previous frame + + + + + Show invisible lines + Näita nähtamatuid jooni + + + + + Onion skin color: blue + + + + + + Onion skin next frame + + + + + + Onion skin color: red + + + + + Show outlines only + + + + + Vertical flip + Vertikaalne peegeldamine + + + + DoubleProgressDialog + + + Loading... + Laadimine... + + + + Cancel + LOobu + + + + Editor + + + + Paste + Aseta + + + + Remove frame + Eemalda kaader + + + + + Import Image + Impordi pilt + + + + ErrorDialog + + + Dialog + Dialoog + + + + <h3>Title</h3> + <h3>Pealkiri</h3> + + + + Description + Kirjeldus + + + + ExportImageDialog + + + Export image sequence + + + + + Export image + Ekspordi pilt + + + + ExportImageOptions + + + Camera + Kaamera + + + + Resolution + Resolutsioon + + + + Format + Vorming + + + + PNG + PNG + + + + JPG + JPG + + + + BMP + BMP + + + + Transparency + Läbipaistvus + + + + ExportMovieDialog + + + Export Movie + Ekspordi video + + + + ExportMovieOptions + + + Camera + Kaamera + + + + Resolution + Resolutsioon + + + + Width + Laius + + + + Height + Kõrgus + + + + Range + Vahemik + + + + The last frame you want to include in the exported movie + + + + + End Frame + Lõpukaader + + + + The first frame you want to include in the exported movie + + + + + Start Frame + Alguse kaader + + + + <html><head/><body><p>End frame is set to last paintable keyframe (Useful when you only want to export to the last animated frame)</p></body></html> + + + + + To the end of sound clips + + + + + GIF and APNG only + Ainult GIF ja APNG + + + + Loop + + + + + FileDialog + + + Open animation + Ava animatsioon + + + + Import image + Impordi pilt + + + + Import image sequence + + + + + Import movie + Impordi video + + + + Import sound + Impordi heli + + + + Import palette + Impordi palett + + + + Save animation + Salvesta animatsioon + + + + Export image + Ekspordi pilt + + + + Export image sequence + + + + + Export movie + Ekspordi video + + + + Export sound + Ekspordi heli + + + + Export palette + Ekspordi palett + + + + Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) + Helifailid (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) + + + + + Palette (*.xml) + Palett (*.xml) + + + + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) + + + + MyAnimation.pclx + MinuAnimatsioon.pclx + + + + FileManager + + + + + Invalid Save Path + Vigane salvestamise asukoht + + + + The path ("%1") points to a directory. + Asukoht ("%1") viitab kaustale. + + + + The directory ("%1") does not exist. + Kausta ("%1") pole olemas. + + + + The path ("%1") is not writable. + Kaust ("%1") pole kirjutatav. + + + + + Cannot Create Data Directory + Andmete kausta loomine ebaõnnestus + + + + Failed to create directory "%1". Please make sure you have sufficient permissions. + + + + + "%1" is a file. Please delete the file and try again. + + + + + + Internal Error + Sisemine tõrge + + + + + An internal error occurred. Your file may not be saved successfully. + + + + + FilesPage + + + Autosave documents + Preference + Salvesta dokumendid automaatselt + + + + Enable autosave + Preference + Luba automaatne salvestamine + + + + Number of modifications before autosaving: + Preference + Muudatuste arv enne automaatset salvestamist: + + + + GeneralPage + + + Language + GroupBox title in Preference + Keel + + + + Window opacity + GroupBox title in Preference + Akna läbipaistvus + + + + Background + GroupBox title in Preference + Taust + + + + Appearance + GroupBox title in Preference + Välimus + + + + + [System-Language] + First item of the language list + [Süsteemi keel] + + + + Canvas + GroupBox title in Preference + Lõuend + + + + Editing + GroupBox title in Preference + Muutmine + + + + Grid + groupBox title in Preference + Võrgustik + + + + Czech + Tšehhi + + + + Danish + Taani + + + + English + Inglise + + + + German + Saksa + + + + Spanish + Hispaania + + + + French + Prantsuse + + + + Hebrew + eebrea + + + + Hungarian + Ungari + + + + Indonesian + Indoneesia + + + + Italian + Itaalia + + + + Japanese + Jaapani + + + + Portuguese - Portugal + Portugali - Portugal + + + + Portuguese - Brazil + Portugali - Brasiilia + + + + Russian + Vene + + + + Slovenian + Sloveenia + + + + Vietnamese + Vietnami + + + + Chinese - Taiwan + Hiina - Taivani + + + + Opacity + Läbipasitmatus + + + + Shadows + Varjud + + + + Tool Cursors + + + + + Antialiasing + + + + + Dotted Cursor + + + + + Enable Grid + Võrgustiku kasutamine + + + + Vector curve smoothing + Vektori kaare sujuvaks muutmine + + + + Tablet high-resolution position + + + + + Restart Required + Nõutud on taaskäivitamine + + + + The language change will take effect after a restart of Pencil2D + + + + + ImportExportDialog + + + File + Fail + + + + Browse... + Sirvi... + + + + Options + Valikud + + + + ImportImageSeqDialog + + + Import image sequence + Impordi pildiseeria + + + + ImportImageSeqOptions + + + Import an image every # frame + Impordi pilt iga # kaadri kohta + + + + Layer + + + Undefined Layer + Määramata kiht + + + + LayerBitmap + + + Bitmap Layer + Pildifaili kiht + + + + LayerCamera + + + Camera Layer + Kaamera kiht + + + + LayerSound + + + Sound Layer + Helikiht + + + + LayerVector + + + Vector Layer + Vektorkiht + + + + MainWindow2 + + + MainWindow + PeamineAken + + + + File + Fail + + + + Import + Impordi + + + + Export + Ekspordi + + + + Edit + Muuda + + + + Selection + Valik + + + + View + Vaade + + + + Onion Skin + + + + + Animation + Animatsioon + + + + + Tools + Tööriistad + + + + Layer + Kiht + + + + + Help + Aviinfo + + + + Windows + Aken + + + + New + Uus + + + + Open + Ava + + + + Save + Salvesta + + + + Save As .. + Salvesta kui ... + + + + Exit + Välju + + + + + Image Sequence... + Pildiseeria... + + + + + Image... + Pilt... + + + + + Movie... + Video... + + + + + Palette... + Palett... + + + + Sound... + Heli... + + + + Undo + Samm tagasi + + + + Redo + Korda + + + + Cut + Lõika + + + + Copy + Kopeeri + + + + Paste + Aseta + + + + Crop + Kärbi + + + + Crop To Selection + Kärbi valiku järgi + + + + Select All + Vali kõik + + + + Deselect All + Tühista valik + + + + + Clear Frame + Tühjenda kaader + + + + Preferences + Eelistused + + + + Reset Windows + Nulli aknad + + + + Zoom In + Suumi sisse + + + + Zoom Out + Suumi välja + + + + Rotate Clockwise + Pööra päripäeva + + + + Rotate AntiClosewise + Pööra vastupäeva + + + + Reset Zoom/Rotate + Nulli suurendus/pööramine + + + + Horizontal Flip + Horisontaalne peegeldamine + + + + Vertical Flip + Vertikaalne peegeldamine + + + + Preview + Eelvaade + + + + Grid + Võrgustik + + + + Previous + Eelmine + + + + Show previous onion skin + + + + + Next + Järgmine + + + + Show next onion skin + + + + + + Play + Esita + + + + Loop + Kordamine + + + + Next Frame + Järgmine kaader + + + + Previous Frame + Eelmine kaader + + + + Extend Frame + Laienda kaadrit + + + + Add Frame + Lisa kaader + + + + Duplicate Frame + Tee kaadrist koopia + + + + Remove Frame + Eemalda kaader + + + + Move + Liigutamine + + + + Select + Valimine + + + + Brush + Pintsel + + + + Polyline + + + + + Smudge + + + + + Pen + Pliiats + + + + Hand + Käsi + + + + Pencil + Pliiats + + + + Bucket + + + + + Eyedropper + + + + + Eraser + Kustukumm + + + + New Bitmap Layer + Uus pildifaili kiht + + + + New Vector Layer + Uus vektorkiht + + + + New Sound Layer + Uus helikiht + + + + New Camera Layer + Uus kaamera kiht + + + + Delete Current Layer + Kustuta praegune kiht + + + + About + Info + + + + + Reset to default + Taasta vaikeväärtused + + + + MultiLayer Onion Skin + + + + + Range + Vahemik + + + + Pencil2D Website + Pencil2D veebisait + + + + Report a Bug + Teavita veast + + + + Quick Reference Guide + Kiirjuhend + + + + F1 + F1 + + + + + Next KeyFrame + + + + + + Previous KeyFrame + + + + + Timeline + Ajatelg + + + + Options + Valikud + + + + Color Wheel + Värviratas + + + + Color Palette + Värvipalett + + + + Display Options + Vaate valikud + + + + Flip X + + + + + Flip Y + + + + + Move Frame Forward + Liigut akaadrit edasi + + + + Move Frame Backward + Liiguta kaadrit tagasi + + + + color palette:<br>use <b>(C)</b><br>toggle at cursor + + + + + Lock Windows + Lukusta aknad + + + + Open Recent + Ava hiljutised + + + + + + You have successfully cleared the list + + +Nimekiri on tühjendatud + + + + + + + Warning + Hoiatus + + + + + Pencil cannot read this file. If you want to import images, use the command import. + + + + + Opening document... + Dokumendi avamine... + + + + + + Abort + Info + + + + Saving document... + Dokumendi salvestamine... + + + + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: + + + + + This animation has been modified. + Do you want to save your changes? + + + + + The animation is not saved yet. + Do you want to save now? + + + + + Never ask again + AutoSave reminder button + Ära küsi kunagi uuesti + + + + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. + + + + + Importing image sequence... + + + + + + Undo + Menu item text + Samm tagasi + + + + Redo + Menu item text + Korda + + + + Stop + Peata + + + + Object + + + Black + Must + + + + Red + Punane + + + + Dark Red + Tumepunane + + + + Orange + Oraanž + + + + Dark Orange + Tumeoraanž + + + + Yellow + Kollane + + + + Dark Yellow + Tumekollane + + + + Green + Roheline + + + + Dark Green + Tumeroheline + + + + Cyan + Tsüaan + + + + Dark Cyan + Tume tsüaan + + + + Blue + Sinine + + + + Dark Blue + Tumesinine + + + + White + Valge + + + + Very Light Grey + Väga hele hall + + + + Light Grey + Helehall + + + + Grey + Hall + + + + Dark Grey + Tumehall + + + + Light Skin + Hele nahk + + + + Light Skin - shade + Hele nahk - varjuga + + + + Skin + Nahk + + + + Skin - shade + Nahk - varjuga + + + + Dark Skin + Tume nahk + + + + Dark Skin - shade + Tume nahk - varjuga + + + + PencilApplication + + + Pencil2D is an animation/drawing software for Mac OS X, Windows, and Linux. It lets you create traditional hand-drawn animation (cartoon) using both bitmap and vector graphics. + + + + + Path to the input pencil file. + + + + + + Render the file to <output_path> + + + + + + output_path + + + + + Name of the camera layer to use + Kasutatava kaamera kihi nimi + + + + layer_name + kihi_nimi + + + + Width of the output frames + + + + + + integer + täisarv + + + + Height of the output frames + Väljundkaadrite kõrgus + + + + The first frame you want to include in the exported movie + + + + + + frame + kaader + + + + The last frame you want to include in the exported movie. Can also be last or last-sound to automatically use the last frame containing animation or sound, respectively + + + + + Render transparency when possible + Kui võimalik, siis säilita läbipaistvus + + + + Warning: width value %1 is not an integer, ignoring. + Hoiatus: %1 laiuse väärtus pole täisarv. Seda ignoreeritakse. + + + + Warning: height value %1 is not an integer, ignoring. + Hoiatus: %1 kõrguse väärtus pole täisarv. Seda ignoreeritakse. + + + + Warning: start value %1 is not an integer, ignoring. + Hoiatus: %1 alguse väärtus pole täisarv. Seda ignoreeritakse. + + + + Warning: start value must be at least 1, ignoring. + Hoiatus: alguse väärtus peab olema vähemalt 1. Seda ignoreeritakse. + + + + Warning: end value %1 is not an integer, last or last-sound, ignoring. + + + + + Warning: end value %1 is smaller than start value %2, ignoring. + + + + + Error: No input file specified. + Tõrge: Sisendfaili pole määratud. + + + + Error: the input file at '%1' does not exist + Command line error + + + + + Error: the input path '%1' is not a file + Command line error + + + + + Warning: the specified camera layer %1 was not found, ignoring. + + + + + Warning: Output format is not specified or unsupported. Using PNG. + Command line warning + + + + + Warning: Transparency is not currently supported in movie files + Command line warning + + + + + Exporting movie... + Command line task progress + Video eksportimine... + + + + + Done. + Command line task done + Valmis. + + + + Exporting image sequence... + Command line task progress + + + + + PreferencesDialog + + + Preferences + Eelistused + + + + General + Üldine + + + + Files + Failid + + + + Timeline + Ajatelg + + + + Tools + Tööriistad + + + + Shortcuts + Otseteed + + + + QApplication + + + Checking environment... + Keskkonna kontrollimine... + + + + Done + Valmis + + + + QObject + + + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) + + + + Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) + Pildid (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) + + + + Everything ok. + Kõik on OK. + + + + Ooops, Something went wrong. + Oih, midagi läks valesti. + + + + File doesn't exist. + Faili pole olemas. + + + + Cannot open file. + Faili ei saa avada. + + + + The file is not a valid xml document. + Fail pole korrektne XML dokument. + + + + The file is not valid pencil document. + Fail pole korrektne pencil dokument. + + + + All Pencil Files PCLX & PCL(*.pclx *.pcl);;Pencil Animation File PCLX(*.pclx);;Old Pencil Animation File PCL(*.pcl);;Any files (*) + + + + + Pencil Animation File PCLX(*.pclx);;Old Pencil Animation File PCL(*.pcl) + + + + + Vivid Pink + Erk roosa + + + + Strong Pink + Tugev roosa + + + + Deep Pink + Sügav roosa + + + + Light Pink + Heleroosa + + + + Moderate Pink + Keskmine roosa + + + + Dark Pink + Tumeroosa + + + + Pale Pink + Kahvatu roosa + + + + Grayish Pink + Hallikasroosa + + + + Pinkish White + Roosakasvalge + + + + Pinkish Gray + Roosakashall + + + + Vivid Red + Erk punane + + + + Strong Red + Tugev punane + + + + Deep Red + Sügav punane + + + + Very Deep Red + Väga sügav punane + + + + Moderate Red + Keskmine punane + + + + Dark Red + Tumepunane + + + + Very Dark Red + Väga tume punane + + + + Light Grayish Red + Hele hallikaspunane + + + + Grayish Red + Hallikas-punane + + + + Dark Grayish Red + Tume hallikaspunane + + + + Blackish Red + Mustjaspunane + + + + Reddish Gray + Punakas-hall + + + + Dark Reddish Gray + Tume punakashall + + + + Reddish Black + Punakasmust + + + + Vivid Yellowish Pink + + + + + Strong Yellowish Pink + + + + + Deep Yellowish Pink + + + + + Light Yellowish Pink + + + + + Moderate Yellowish Pink + + + + + Dark Yellowish Pink + + + + + Pale Yellowish Pink + + + + + Grayish Yellowish Pink + + + + + Brownish Pink + + + + + Vivid Reddish Orange + + + + + Strong Reddish Orange + + + + + Deep Reddish Orange + + + + + Moderate Reddish Orange + + + + + Dark Reddish Orange + + + + + Grayish Reddish Orange + + + + + Strong Reddish Brown + + + + + Deep Reddish Brown + + + + + Light Reddish Brown + + + + + Moderate Reddish Brown + + + + + Dark Reddish Brown + + + + + Light Grayish Reddish Brown + + + + + Grayish Reddish Brown + + + + + Dark Grayish Reddish Brown + + + + + Vivid Orange + + + + + Brilliant Orange + + + + + Strong Orange + + + + + Deep Orange + + + + + Light Orange + + + + + Moderate Orange + + + + + Brownish Orange + + + + + Strong Brown + + + + + Deep Brown + + + + + Light Brown + + + + + Moderate Brown + + + + + Dark Brown + + + + + Light Grayish Brown + + + + + Grayish Brown + + + + + Dark Grayish Brown + + + + + Light Brownish Gray + + + + + Brownish Gray + + + + + Brownish Black + + + + + Vivid Orange Yellow + + + + + Brilliant Orange Yellow + + + + + Strong Orange Yellow + + + + + Deep Orange Yellow + + + + + Light Orange Yellow + + + + + Moderate Orange Yellow + + + + + Dark Orange Yellow + + + + + Pale Orange Yellow + + + + + Strong Yellowish Brown + + + + + Deep Yellowish Brown + + + + + Light Yellowish Brown + + + + + Moderate Yellowish Brown + + + + + Dark Yellowish Brown + + + + + Light Grayish Yellowish Brown + + + + + Grayish Yellowish Brown + + + + + Dark Grayish Yellowish Brown + + + + + Vivid Yellow + + + + + Brilliant Yellow + + + + + Strong Yellow + + + + + Deep Yellow + + + + + Light Yellow + + + + + Moderate Yellow + + + + + Dark Yellow + + + + + Pale Yellow + + + + + Grayish Yellow + + + + + Dark Grayish Yellow + + + + + Yellowish White + + + + + Yellowish Gray + + + + + Light Olive Brown + + + + + Moderate Olive Brown + + + + + Dark Olive Brown + + + + + Vivid Greenish Yellow + + + + + Brilliant Greenish Yellow + + + + + Strong Greenish Yellow + + + + + Deep Greenish Yellow + + + + + Light Greenish Yellow + + + + + Moderate Greenish Yellow + + + + + Dark Greenish Yellow + + + + + Pale Greenish Yellow + + + + + Grayish Greenish Yellow + + + + + Light Olive + + + + + Moderate Olive + + + + + Dark Olive + Tume oliiv + + + + Light Grayish Olive + + + + + Grayish Olive + Hallikas oliiv + + + + Dark Grayish Olive + + + + + Light Olive Gray + + + + + Olive Gray + + + + + Olive Black + + + + + Vivid Yellow Green + + + + + Brilliant Yellow Green + + + + + Strong Yellow Green + + + + + Deep Yellow Green + + + + + Light Yellow Green + + + + + Moderate Yellow Green + + + + + Pale Yellow Green + + + + + Grayish Yellow Green + + + + + Strong Olive Green + + + + + Deep Olive Green + + + + + Moderate Olive Green + + + + + Dark Olive Green + + + + + Grayish Olive Green + + + + + Dark Grayish Olive Green + + + + + Vivid Yellowish Green + + + + + Brilliant Yellowish Green + + + + + Strong Yellowish Green + + + + + Deep Yellowish Green + + + + + Very Deep Yellowish Green + + + + + Very Light Yellowish Green + + + + + Light Yellowish Green + + + + + Moderate Yellowish Green + + + + + Dark Yellowish Green + + + + + Very Dark Yellowish Green + + + + + Vivid Green + + + + + Brilliant Green + + + + + Strong Green + + + + + Deep Green + + + + + Very Light Green + + + + + Light Green + + + + + Moderate Green + + + + + Dark Green + + + + + Very Dark Green + + + + + Very Pale Green + + + + + Pale Green + + + + + Grayish Green + + + + + Dark Grayish Green + + + + + Blackish Green + + + + + Greenish White + + + + + Light Greenish Gray + + + + + Greenish Gray + + + + + Dark Greenish Gray + + + + + Greenish Black + + + + + Vivid Bluish Green + + + + + Brilliant Bluish Green + + + + + Strong Bluish Green + + + + + Deep Bluish Green + + + + + Very Light Bluish Green + + + + + Light Bluish Green + + + + + Moderate Bluish Green + + + + + Dark Bluish Green + + + + + Very Dark Bluish Green + + + + + Vivid Greenish Blue + + + + + Brilliant Greenish Blue + + + + + Strong Greenish Blue + + + + + Deep Greenish Blue + + + + + Very Light Greenish Blue + + + + + Light Greenish Blue + + + + + Moderate Greenish Blue + + + + + Dark Greenish Blue + + + + + Very Dark Greenish Blue + + + + + Vivid Blue + + + + + Brilliant Blue + + + + + Strong Blue + + + + + Deep Blue + + + + + Very Light Blue + + + + + Light Blue + + + + + Moderate Blue + + + + + Dark Blue + + + + + Very Pale Blue + + + + + Pale Blue + + + + + Grayish Blue + + + + + Dark Grayish Blue + + + + + Blackish Blue + + + + + Bluish White + + + + + Light Bluish Gray + + + + + Bluish Gray + + + + + Dark Bluish Gray + + + + + Bluish Black + + + + + Vivid Purplish Blue + + + + + Brilliant Purplish Blue + + + + + Strong Purplish Blue + + + + + Deep Purplish Blue + + + + + Very Light Purplish Blue + + + + + Light Purplish Blue + + + + + Moderate Purplish Blue + + + + + Dark Purplish Blue + + + + + Very Pale Purplish Blue + + + + + Pale Purplish Blue + + + + + Grayish Purplish Blue + + + + + Vivid Violet + + + + + Brilliant Violet + + + + + Strong Violet + + + + + Deep Violet + + + + + Very Light Violet + + + + + Light Violet + + + + + Moderate Violet + + + + + Dark Violet + + + + + Very Pale Violet + + + + + Pale Violet + + + + + Grayish Violet + + + + + Vivid Purple + + + + + Brilliant Purple + + + + + Strong Purple + + + + + Deep Purple + + + + + Very Deep Purple + + + + + Very Light Purple + + + + + Light Purple + + + + + Moderate Purple + + + + + Dark Purple + + + + + Very Dark Purple + + + + + Very Pale Purple + + + + + Pale Purple + + + + + Grayish Purple + + + + + Dark Grayish Purple + + + + + Blackish Purple + + + + + Purplish White + + + + + Light Purplish Gray + + + + + Purplish Gray + + + + + Dark Purplish Gray + + + + + Purplish Black + + + + + Vivid Reddish Purple + + + + + Strong Reddish Purple + + + + + Deep Reddish Purple + + + + + Very Deep Reddish Purple + + + + + Light Reddish Purple + + + + + Moderate Reddish Purple + + + + + Dark Reddish Purple + + + + + Very Dark Reddish Purple + + + + + Pale Reddish Purple + + + + + Grayish Reddish Purple + + + + + Brilliant Purplish Pink + + + + + Strong Purplish Pink + + + + + Deep Purplish Pink + + + + + Light Purplish Pink + + + + + Moderate Purplish Pink + + + + + Dark Purplish Pink + + + + + Pale Purplish Pink + + + + + Grayish Purplish Pink + + + + + Vivid Purplish Red + + + + + Strong Purplish Red + + + + + Deep Purplish Red + + + + + Very Deep Purplish Red + + + + + Moderate Purplish Red + + + + + Dark Purplish Red + + + + + Very Dark Purplish Red + + + + + Light Grayish Purplish Red + + + + + Grayish Purplish Red + + + + + White + Valge + + + + Light Gray + Helehall + + + + Medium Gray + Keskmine hall + + + + Dark Gray + Tumehall + + + + Black + Must + + + + RecentFileMenu + + + Open Recent + Ava hiljutised + + + + Clear + Tühjenda + + + + ScribbleArea + + + Warning + Hoiatus + + + + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). + + + + + Delete Selection + Undo Step: clear the selection area. + Kustuta valik + + + + + Clear Image + Undo step text + + + + + There is a gap in your drawing (or maybe you have zoomed too much). + + + + + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). + + + + + Out of bound. + Piiridest väljas. + + + + Could not find a closed path. + + + + + Could not find the root index. + + + + + %1<br><br>Error: %2 + + + + + Flood fill error + + + + + ShortcutsPage + + + Form + + + + + Action: + Tegevus: + + + + None + Pole + + + + Shortcuts: + Otseteed: + + + + clear + tühjenda + + + + Restore Default Shortcuts + + + + + Shortcut Conflict! + + + + + %1 is already used, overwrite? + + + + + TimeControls + + + Range + Vahemik + + + + Frames per second + Kaadrit sekundis + + + + Start of playback loop + + + + + End of playback loop + + + + + Playback range + + + + + Play + Esita + + + + Loop + + + + + Sound on/off + Heli sees või väljas + + + + End + Lõpp + + + + + Start + Algus + + + + Stop + Peata + + + + TimeLine + + + Timeline + + + + + Layers: + Kihid: + + + + Add Layer + Lisa kiht + + + + Remove Layer + Eemalda kiht + + + + New Bitmap Layer + + + + + New Vector Layer + Uus vektorkiht + + + + New Sound Layer + Uus helikiht + + + + New Camera Layer + Uus kaamerakiht + + + + &Layer + Timeline add-layer menu + &Kiht + + + + Keys: + + + + + Add Frame + Lisa kaader + + + + Remove Frame + Eemalda kaader + + + + Duplicate Frame + Tee kaadrist koopia + + + + Onion skin: + + + + + Toggle match keyframes + + + + + Delete Layer + Windows title of Delete current layer pop-up. + Kustuta kiht + + + + Please keep at least one camera layer in project + + + + + Are you sure you want to delete layer: + + + + + TimeLineCells + + + Layer Properties + Kihi omadused + + + + Layer name: + Kihi nimi: + + + + Timeline2 + + + Timeline + + + + + Layers + Kihid + + + + + ... + ... + + + + TimelinePage + + + Timeline + Ajatelg + + + + Timeline length: + Preferences + Ajatelje pikkus: + + + + Frame size + Kaadri suurus + + + + Short scrub + + + + + ToolBoxWidget + + + Tools + Window title of tool box + Tööriistad + + + + Pencil Tool (%1): Sketch with pencil + + + + + Select Tool (%1): Select an object + + + + + Move Tool (%1): Move an object + + + + + Hand Tool (%1): Move the canvas + + + + + Pen Tool (%1): Sketch with pen + + + + + Eraser Tool (%1): Erase + + + + + Polyline Tool (%1): Create line/curves + + + + + Paint Bucket Tool (%1): Fill selected area with a color + + + + + Brush Tool (%1): Paint smooth stroke with a brush + + + + + Eyedropper Tool (%1): Set color from the stage<br>[ALT] for instant access + + + + + Clear Frame (%1): Erases content of selected frame + + + + + Smudge Tool (%1):<br>Edit polyline/curves<br>Liquify bitmap pixels<br> (%1)+[Alt]: Smooth + + + + + Pencil Tool (%1) + + + + + Select Tool (%1) + + + + + Move Tool (%1) + + + + + Hand Tool (%1) + + + + + Pen Tool (%1) + + + + + Eraser Tool (%1) + + + + + Polyline Tool (%1) + + + + + Paint Bucket Tool (%1) + + + + + Brush Tool (%1) + + + + + Eyedropper Tool (%1) + + + + + Clear Tool (%1) + + + + + Smudge Tool (%1) + + + + + ToolOptionWidget + + + Brush + Pintsel + + + + Feather + + + + + Color Tolerance + + + + + Options + Window title of tool option panel like pen width, feather etc.. + Valikud + + + + Stroke Thickness + Joone paksus + + + + Width + Laius + + + + ToolOptions + + + Form + + + + + Set Pen Width <br><b>[SHIFT]+drag</b><br>for quick adjustment + + + + + Set Pen Feather <br><b>[CTRL]+drag</b><br>for quick adjustment + + + + + Enable or disable feathering + + + + + Use Feather + + + + + Contour will be filled + + + + + Fill Contour + + + + + The extend to which the color variation will be treated as being equal + + + + + Bezier + + + + + Pressure + Brush + Surve + + + + Anti-Aliasing + Brush AA + + + + + Merge + Vector line merge + Liida + + + + None + Stabilizer option + Pole + + + + Simple + Stabilizer option + Lihtne + + + + Strong + Stabilizer option + Tugev + + + + Make invisible + Tee nähtamatuks + + + + Invisible + Nähtamatu + + + + Preserve Alpha + Säilita alfakanal + + + + Alpha + Alfa + + + + Merge vector lines when they are close together + + + + + Stabilizer + + + + + ToolsPage + + + Onion skin + + + + + Maximum onion opacity % + + + + + Minimum onion opacity % + + + + + Number of previous onion frames shown + + + + + Number of next onion frames shown + + + + + Brush Tools + + + + + Use Quick Sizing + + + + \ No newline at end of file diff --git a/translations/translations.qrc b/translations/translations.qrc index e04b3aeb0..df02732a7 100644 --- a/translations/translations.qrc +++ b/translations/translations.qrc @@ -4,6 +4,7 @@ pencil_da.qm pencil_de.qm pencil_es.qm + pencil_et.qm pencil_fr.qm pencil_he.qm pencil_hu_HU.qm From 3431ead8c8b3f3c45881d676c7da648adf985b24 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Fri, 27 Apr 2018 13:08:42 +1000 Subject: [PATCH 024/184] Sync translations with Transifex --- translations/pencil_cs.ts | 314 +++++++++++++++++----------------- translations/pencil_da.ts | 314 +++++++++++++++++----------------- translations/pencil_de.ts | 314 +++++++++++++++++----------------- translations/pencil_es.ts | 314 +++++++++++++++++----------------- translations/pencil_fr.ts | 322 ++++++++++++++++++----------------- translations/pencil_he.ts | 314 +++++++++++++++++----------------- translations/pencil_hu_HU.ts | 314 +++++++++++++++++----------------- translations/pencil_id.ts | 314 +++++++++++++++++----------------- translations/pencil_it.ts | 314 +++++++++++++++++----------------- translations/pencil_ja.ts | 314 +++++++++++++++++----------------- translations/pencil_pt.ts | 316 +++++++++++++++++----------------- translations/pencil_pt_BR.ts | 314 +++++++++++++++++----------------- translations/pencil_ru.ts | 314 +++++++++++++++++----------------- translations/pencil_sl.ts | 314 +++++++++++++++++----------------- translations/pencil_vi.ts | 314 +++++++++++++++++----------------- translations/pencil_zh_TW.ts | 314 +++++++++++++++++----------------- 16 files changed, 2597 insertions(+), 2437 deletions(-) diff --git a/translations/pencil_cs.ts b/translations/pencil_cs.ts index 69b25ee1c..d23c5efe7 100644 --- a/translations/pencil_cs.ts +++ b/translations/pencil_cs.ts @@ -28,118 +28,118 @@ ActionCommands - + No sound layer exists as a destination for your import. Create a new sound layer? Neexistuje žádná zvuková vrsva jako cíl zavedení. Vytvořit novou zvukovou vrstvu? - + Create sound layer Vytvořit zvukovou vrstvu - + Don't create layer Nevytvářet vrstvu - + Layer Properties Dialog title on creating a sound layer Vlastnosti vrstvy - + Sound Layer Default name on creating a sound layer Zvuková vrstva - + Exporting movie - + Finished. Open movie now? When movie export done. Dokončeno. Otevřít záznam nyní? - - - - - Layer Properties - Vlastnosti vrstvy - - - + Layer Properties + Vlastnosti vrstvy + + + + + + + Layer name: Název vrstvy: - + A sound clip already exists on this frame! Please select another frame or layer. Zvukový klip již v tomto snímku existuje! Vyberte, prosím, jiný klip nebo vrstvu. - + Exporting image sequence... Vyvádí se řada obrázků... - + Abort Zrušit - + Warning Varování - + Unable to export image. Obrázek nelze vyvést. - + Bitmap Layer Bitmapová vrstva - + Vector Layer Vektorová vrstva - + Camera Layer Kamerová vrstva - + Sound Layer Zvuková vrstva - + Delete Layer Windows title of Delete current layer pop-up. Smazat vrstvu - + Are you sure you want to delete layer: Opravdu chcete smazat vrstvu: - + Please keep at least one camera layer in project text when failed to delete camera layer Ponechejte, prosím, v projektu alespoň jednu vrstvu s kamerou @@ -446,19 +446,19 @@ Editor - - + + Paste Vložit - + Remove frame Odstranit snímek - - + + Import Image Zavést obrázek @@ -1076,7 +1076,7 @@ - + Tools Nástroje @@ -1087,401 +1087,411 @@ - + Help Nápověda - + Windows Okno - + New Nový - + Open Otevřít - + Save Uložit - + Save As .. Uložit jako... - + Exit Ukončit - - + + Image Sequence... Řada obrázků... - - + + Image... Obrázek... - - + + Movie... Film... - - + + Palette... Paleta... - + Sound... Zvuk... - + Undo Zpět - + Redo Znovu - + Cut Vyjmout - + Copy Kopírovat - + Paste Vložit - + Crop Oříznout - + Crop To Selection Oříznout k výběru - + Select All Vybrat vše - + Deselect All Zrušit výběr všeho - - + + Clear Frame Vyčistit snímek - + Preferences Nastavení - + Reset Windows Vrátit okna na výchozí - + Zoom In Přiblížit - + Zoom Out Oddálit - + Rotate Clockwise Otočit po směru hodinových ručiček - + Rotate AntiClosewise Otočit proti směru hodinových ručiček - + Reset Zoom/Rotate Vrátit na výchozí zvětšení/otočení - + Horizontal Flip Vodorovné převrácení - + Vertical Flip Svislé převrácení - + Preview Náhled - + Grid Mřížka - + Previous Předchozí - + Show previous onion skin Zobrazit předchozí cibulovou slupku - + Next Další - + Show next onion skin Zobrazit následující cibulovou slupku - - + + Play Přehrát - + Loop Smyčka - + Next Frame Další snímek - + Previous Frame Předchozí snímek - + Extend Frame Rozšířit snímek - + Add Frame Přidat snímek - + Duplicate Frame Zdvojit snímek - + Remove Frame Odstranit snímek - + Move Posunout - + Select Vybrat - + Brush Štětec - + Polyline Lomená čára - + Smudge Šmouha - + Pen Pero - + Hand Ruka - + Pencil Tužka - + Bucket Kbelík - + Eyedropper Kapátko - + Eraser Guma - + New Bitmap Layer Nová bitmapová vrstva - + New Vector Layer Nová vektorová vrstva - + New Sound Layer Nová zvuková vrstva - + New Camera Layer Nová kamerová vrstva - + Delete Current Layer Smazat nynější vrstvu - + About O programu - - + + Reset to default Vrátit na výchozí - + MultiLayer Onion Skin Vícevrstvý cibulový vzhled - + Range Rozsah - + Pencil2D Website Stránka Pencil2D - + Report a Bug Nahlásit chybu - - + + Quick Reference Guide + + + + + F1 + + + + + Next KeyFrame Další klíčový snímek - - + + Previous KeyFrame Předchozí Klíčový Snímek - + Timeline Časová osa - + Options Možnosti - + Color Wheel Kolo barev - + Color Palette Paleta barev - + Display Options Nastavení zobrazení - + Flip X Převrátit X - + Flip Y Převrátit Y - + Move Frame Forward Posunout snímek vpřed - + Move Frame Backward Posunout snímek vzad @@ -1496,12 +1506,12 @@ Zamknout okna - + Open Recent Otevřít nedávné - + You have successfully cleared the list @@ -1510,86 +1520,86 @@ Úspěšně jste vyprázdnil seznam - - - - + + + + Warning Varování - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil není schopen přečíst tento soubor. Pokud chcete zavést obrázky, použijte příkaz Zavést. - + Opening document... Otevírám dokument... - - - + + + Abort Zrušit - + Saving document... Ukládám dokument... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: - + This animation has been modified. Do you want to save your changes? Tato animace byla změněna. Přejete si uložit změny? - + The animation is not saved yet. Do you want to save now? Animace ještě není uložena. Chcete ji uložit nyní? - + Never ask again AutoSave reminder button Už se znovu neptat - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Obrázek nelze zavést.<br><b>Rada:</b> K zavedení bitmap použijte bitmapovou vrstvu. - + Importing image sequence... - - + + Undo Menu item text - + Redo Menu item text - + Stop Zastavit @@ -1931,32 +1941,32 @@ Chcete ji uložit nyní? Obrázky (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - + Everything ok. Vše v pořádku. - + Ooops, Something went wrong. Ouč, něco se pokazilo. - + File doesn't exist. Soubor neexistuje. - + Cannot open file. Soubor nelze otevřít. - + The file is not a valid xml document. Tento soubor není validní xml dokument - + The file is not valid pencil document. Tento soubor není validní dokument pencil. @@ -3580,12 +3590,12 @@ Chcete ji uložit nyní? TimeLineCells - + Layer Properties Vlastnosti vrstvy - + Layer name: Název vrstvy: diff --git a/translations/pencil_da.ts b/translations/pencil_da.ts index 498933527..709cdf069 100644 --- a/translations/pencil_da.ts +++ b/translations/pencil_da.ts @@ -28,118 +28,118 @@ ActionCommands - + No sound layer exists as a destination for your import. Create a new sound layer? Der er ikke noget lyd lag som du kan importere til. Opret et nyt lyd lag? - + Create sound layer Opret nyt lyd Lag - + Don't create layer Opret ikke et nyt lag - + Layer Properties Dialog title on creating a sound layer - + Sound Layer Default name on creating a sound layer - + Exporting movie - + Finished. Open movie now? When movie export done. - - - - - Layer Properties - Lag Præferencer - - - + Layer Properties + Lag Præferencer + + + + + + + Layer name: Lag navn: - + A sound clip already exists on this frame! Please select another frame or layer. Et lydklip eksisterer allerede på dette frame! Vælg venligst et andet frame eller lag - + Exporting image sequence... - + Abort - + Warning - + Unable to export image. - + Bitmap Layer Bitmap Lag - + Vector Layer Vector Lag - + Camera Layer Kamera Lag - + Sound Layer Lyd Lag - + Delete Layer Windows title of Delete current layer pop-up. - + Are you sure you want to delete layer: - + Please keep at least one camera layer in project text when failed to delete camera layer @@ -446,19 +446,19 @@ Editor - - + + Paste Indsæt - + Remove frame - - + + Import Image @@ -1076,7 +1076,7 @@ - + Tools Værktøjer @@ -1087,401 +1087,411 @@ - + Help Hjælp - + Windows Vinduer - + New Ny - + Open Åben - + Save Gem - + Save As .. Gem Som .. - + Exit Afslut - - + + Image Sequence... Billede Sekvens... - - + + Image... Billede... - - + + Movie... Film... - - + + Palette... Palet... - + Sound... Lyd... - + Undo Fortryd - + Redo Gentag - + Cut Klip - + Copy Kopier - + Paste Indsæt - + Crop Beskær - + Crop To Selection Beskær til Markering - + Select All Vælg Alt - + Deselect All Fravælg Alt - - + + Clear Frame Ryd Ramme - + Preferences Præferencer - + Reset Windows Nulstil Vinduer - + Zoom In Zoom Ind - + Zoom Out Zoom Ud - + Rotate Clockwise Roter Med Uret - + Rotate AntiClosewise Roter Mod Uret - + Reset Zoom/Rotate Nulstil Zoom/Rotation - + Horizontal Flip Vend Horisontalt - + Vertical Flip Vend Vertikalt - + Preview Vis Eksempel - + Grid Gitter - + Previous Tidligere - + Show previous onion skin - + Next Næste - + Show next onion skin - - + + Play Afspil - + Loop Lykke - + Next Frame Næste Ramme - + Previous Frame Forrige Ramme - + Extend Frame Forlæng Ramme - + Add Frame Tilføj Ramme - + Duplicate Frame dupliker Ramme - + Remove Frame Fjern Ramme - + Move Flyt - + Select Vælg - + Brush Pencel - + Polyline Polylinje - + Smudge Udtværd - + Pen Pen - + Hand Hånd - + Pencil Blyant - + Bucket Spand - + Eyedropper Pipette - + Eraser Viskelæder - + New Bitmap Layer Nyt Bitmap Lag - + New Vector Layer Nyt Vector Lag - + New Sound Layer Nyt Lyd Lag - + New Camera Layer Nyt Kamera Lag - + Delete Current Layer Fjern Nuværende Lag - + About Om - - + + Reset to default Nulstil til standard indstillinger - + MultiLayer Onion Skin - + Range - + Pencil2D Website - + Report a Bug - - + + Quick Reference Guide + + + + + F1 + + + + + Next KeyFrame - - + + Previous KeyFrame - + Timeline Tidslinje - + Options Instillinger - + Color Wheel Farvehjul - + Color Palette Farve Palet - + Display Options Vis instillinger - + Flip X - + Flip Y - + Move Frame Forward - + Move Frame Backward @@ -1496,96 +1506,96 @@ - + Open Recent Åben Seneste - + You have successfully cleared the list - - - - + + + + Warning Advarsel - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil kan ikke læse denne fil. hvis du vil importere billeder, brug kommandoen importer. - + Opening document... Åbner dokument... - - - + + + Abort Om - + Saving document... Gemmer dokument... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: - + This animation has been modified. Do you want to save your changes? - + The animation is not saved yet. Do you want to save now? - + Never ask again AutoSave reminder button - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. - + Importing image sequence... - - + + Undo Menu item text - + Redo Menu item text - + Stop @@ -1927,32 +1937,32 @@ - + Everything ok. - + Ooops, Something went wrong. - + File doesn't exist. - + Cannot open file. - + The file is not a valid xml document. - + The file is not valid pencil document. @@ -3576,12 +3586,12 @@ TimeLineCells - + Layer Properties - + Layer name: diff --git a/translations/pencil_de.ts b/translations/pencil_de.ts index 8dfe1fcbe..da97d6f2f 100644 --- a/translations/pencil_de.ts +++ b/translations/pencil_de.ts @@ -28,118 +28,118 @@ ActionCommands - + No sound layer exists as a destination for your import. Create a new sound layer? Es existiert keine Ton-Ebene als Ziel für diesen Import. Neue Ebene erstellen? - + Create sound layer Ton-Ebene erstellen - + Don't create layer Keine Ebene erstellen - + Layer Properties Dialog title on creating a sound layer Ebeneneigenschaften - + Sound Layer Default name on creating a sound layer Ton-Ebene - + Exporting movie Film wird exportiert - + Finished. Open movie now? When movie export done. Erledigt. Film jetzt öffnen? - - - - - Layer Properties - Ebenen-Eigenschaften - - - + Layer Properties + Ebenen-Eigenschaften + + + + + + + Layer name: Name der Ebene: - + A sound clip already exists on this frame! Please select another frame or layer. Auf diesem Frame existiert bereits eine Tonspur! Bitte wähle einen anderen Frame oder eine andere Ebene. - + Exporting image sequence... Bildsequenz wird exportiert... - + Abort Abbrechen - + Warning Warnung - + Unable to export image. Bild kann nicht exportiert werden. - + Bitmap Layer Rasterbild-Ebene - + Vector Layer Vektor-Ebene - + Camera Layer Kamera-Ebene - + Sound Layer Ton-Ebene - + Delete Layer Windows title of Delete current layer pop-up. Ebene löschen - + Are you sure you want to delete layer: Sind Sie sicher, dass Sie die Ebene löschen möchten: - + Please keep at least one camera layer in project text when failed to delete camera layer Bitte belassen Sie mindestens eine Kamera-Ebene im Projekt @@ -446,19 +446,19 @@ Editor - - + + Paste Einfügen - + Remove frame Einzelbild entfernen - - + + Import Image Bild importieren @@ -1076,7 +1076,7 @@ - + Tools Werkzeuge @@ -1087,401 +1087,411 @@ - + Help Hilfe - + Windows Fenster - + New Neu - + Open Öffnen - + Save Speichern - + Save As .. Speichern unter... - + Exit Beenden - - + + Image Sequence... Bildsequenz... - - + + Image... Bild... - - + + Movie... Film... - - + + Palette... Palette... - + Sound... Ton... - + Undo Rückgängig - + Redo Wiederholen - + Cut Ausschneiden - + Copy Kopieren - + Paste Einfügen - + Crop Zuschneiden - + Crop To Selection Auf Auswahl zuscheiden - + Select All Alles auswählen - + Deselect All Nichts auswählen - - + + Clear Frame Einzelbild leeren - + Preferences Einstellungen - + Reset Windows Fenster zurücksetzen - + Zoom In Hineinzoomen - + Zoom Out Herauszoomen - + Rotate Clockwise Im Uhrzeigersinn rotieren - + Rotate AntiClosewise Gegen den Uhrzeigersinn rotieren - + Reset Zoom/Rotate Zoom/Drehung zurücksetzen - + Horizontal Flip Horizontal spiegeln - + Vertical Flip Vertikal spiegeln - + Preview Vorschau - + Grid Raster - + Previous Vorige - + Show previous onion skin Zeige vorige Zwiebelhaut - + Next Nächste - + Show next onion skin Zeige nächste Zwiebelhaut - - + + Play Abspielen - + Loop Wiederholen - + Next Frame Nächstes Einzelbild - + Previous Frame Vorheriges Einzelbild - + Extend Frame Einzelbild erweitern - + Add Frame Einzelbild hinzufügen - + Duplicate Frame Einzelbild duplizieren - + Remove Frame Einzelbild entfernen - + Move Verschieben - + Select Auswählen - + Brush Pinsel - + Polyline Polygonzug - + Smudge Verwischen - + Pen Stift - + Hand Hand - + Pencil Bleistift - + Bucket Farbeimer - + Eyedropper Pipette - + Eraser Radierer - + New Bitmap Layer Neue Rasterbild-Ebene - + New Vector Layer Neue Vektor-Ebene - + New Sound Layer Neue Ton-Ebene - + New Camera Layer Neue Kamera-Ebene - + Delete Current Layer Aktuelle Ebene löschen - + About Über - - + + Reset to default Auf Standard zurücksetzen - + MultiLayer Onion Skin - + Range Bereich - + Pencil2D Website Pencil2D-Website - + Report a Bug Einen Fehler melden - - + + Quick Reference Guide + + + + + F1 + + + + + Next KeyFrame Nächstes Schlüsselbild - - + + Previous KeyFrame Voriges Schlüsselbild - + Timeline Zeitleiste - + Options Optionen - + Color Wheel Farbrad - + Color Palette Farbpalette - + Display Options Anzeige-Optionen - + Flip X Horizontal spiegeln - + Flip Y Vertikal spiegeln - + Move Frame Forward - + Move Frame Backward @@ -1496,12 +1506,12 @@ Fenster sperren - + Open Recent Zuletzt geöffnet - + You have successfully cleared the list @@ -1510,86 +1520,86 @@ Sie haben die Liste erfolgreich geleert - - - - + + + + Warning Warnung - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil kann die Datei nicht lesen. Wenn Sie Bilder importieren möchten, benutzen sie die Importfunktion. - + Opening document... Dokument wird geöffnet... - - - + + + Abort Abbrechen - + Saving document... Dokument wird gespeichert... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>Ein Fehler ist aufgetreten und Ihre Datei wurde womöglich nicht erfolgreich gespeichert. Falls Sie glauben, dass es sich hierbei um einen Programmfehler in Pencil2D handelt, erstellen Sie bitte auf Englisch eine neue Meldung unter:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Bitte fügen Sie Ihrer Meldung unbedingt die folgenden Details bei: - + This animation has been modified. Do you want to save your changes? Diese Animation wurde geändert. Möchten Sie Ihre Änderungen speichern? - + The animation is not saved yet. Do you want to save now? Die Animation wurde noch nicht gespeichert. Möchten Sie sie jetzt speichern? - + Never ask again AutoSave reminder button Nicht mehr fragen - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Bild kann nicht importiert werden.<br><b>TIPP:</b> Verwenden Sie eine Rasterebene um Rasterbilder zu importieren. - + Importing image sequence... - - + + Undo Menu item text - + Redo Menu item text - + Stop @@ -1934,32 +1944,32 @@ Sie haben die Liste erfolgreich geleert Bilder (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - + Everything ok. Alles ok. - + Ooops, Something went wrong. Uups, etwas ist schiefgegangen. - + File doesn't exist. Datei existiert nicht. - + Cannot open file. Kann Datei nicht öffnen. - + The file is not a valid xml document. Die Datei ist kein gültiges XML-Dokument. - + The file is not valid pencil document. Die Datei ist kein gültiges Pencil-Dokument. @@ -3583,12 +3593,12 @@ Sie haben die Liste erfolgreich geleert TimeLineCells - + Layer Properties Ebeneneigenschaften - + Layer name: Ebenenname: diff --git a/translations/pencil_es.ts b/translations/pencil_es.ts index fd27f4fe1..f863b4365 100644 --- a/translations/pencil_es.ts +++ b/translations/pencil_es.ts @@ -28,118 +28,118 @@ ActionCommands - + No sound layer exists as a destination for your import. Create a new sound layer? No existe capa de sonido como destino para el archivo importado. ¿Crear nueva capa de sonido? - + Create sound layer Crear capa de sonido - + Don't create layer No crear capa - + Layer Properties Dialog title on creating a sound layer Propiedades de la Capa - + Sound Layer Default name on creating a sound layer Capa de Sonido - + Exporting movie Exportando película - + Finished. Open movie now? When movie export done. Terminado. ¿Ver ahora? - - - - - Layer Properties - Propiedades de la capa - - - + Layer Properties + Propiedades de la capa + + + + + + + Layer name: Nombre de la capa: - + A sound clip already exists on this frame! Please select another frame or layer. Un clip de sonido ya existe en este fotograma! Por favor seleccionar otro fotograma o capa - + Exporting image sequence... Exportando secuencia de imágenes... - + Abort Abortar - + Warning Advertencia - + Unable to export image. No se puede exportar imagen. - + Bitmap Layer Capa de bitmap - + Vector Layer Capa de vector - + Camera Layer Capa de cámara - + Sound Layer Capa de sonido - + Delete Layer Windows title of Delete current layer pop-up. Eliminar Capa - + Are you sure you want to delete layer: ¿Seguro que deseas eliminar la capa? - + Please keep at least one camera layer in project text when failed to delete camera layer Favor de mantener al menos una capa de cámara en el proyecto @@ -446,19 +446,19 @@ Editor - - + + Paste Pegar - + Remove frame Eliminar fotograma - - + + Import Image Importar imagen @@ -1076,7 +1076,7 @@ - + Tools Herramientas @@ -1087,401 +1087,411 @@ - + Help Ayuda - + Windows Ventanas - + New Nuevo - + Open Abrir - + Save Grabar - + Save As .. Grabar como ... - + Exit Salir - - + + Image Sequence... Secuencia de Imagenes... - - + + Image... Imagen... - - + + Movie... Película... - - + + Palette... Paleta... - + Sound... Sonido... - + Undo Deshacer - + Redo Rehacer - + Cut Cortar - + Copy Copiar - + Paste Pegar - + Crop Recortar - + Crop To Selection Recortar por la Selección - + Select All Seleccionar Todo - + Deselect All Deseleccionar Todo - - + + Clear Frame Limpiar Fotograma - + Preferences Preferencias - + Reset Windows Restaurar Ventanas - + Zoom In Acercar - + Zoom Out Alejar - + Rotate Clockwise Rotar Derecha - + Rotate AntiClosewise Rotar Izquierda - + Reset Zoom/Rotate Restaurar Zoom/Rotación - + Horizontal Flip Girar Horizontalmente - + Vertical Flip Girar Verticalmente - + Preview Vista Previa - + Grid Cuadricula - + Previous Anterior - + Show previous onion skin Mostrar papel cebolla anterior - + Next Siguiente - + Show next onion skin Mostrar papel cebolla posterior  - - + + Play Reproducir - + Loop Ciclo - + Next Frame Fotograma posterior - + Previous Frame Fotograma anterior - + Extend Frame Extender Fotograma - + Add Frame Añadir Fotograma - + Duplicate Frame Duplicar Fotograma - + Remove Frame Eliminar Fotograma - + Move Mover - + Select Seleccionar - + Brush Pincel - + Polyline Polilínea - + Smudge Dedo - + Pen Pluma - + Hand Mano - + Pencil Lápiz - + Bucket Bote de pintura - + Eyedropper Pipeta - + Eraser Borrador - + New Bitmap Layer Nueva Capa Bitmap - + New Vector Layer Nueva Capa Vector - + New Sound Layer Nueva Capa Sonido - + New Camera Layer Nueva Capa Cámara - + Delete Current Layer Eliminar Capa Actual - + About Acerca de - - + + Reset to default Restaurar Predeterminado - + MultiLayer Onion Skin MultiCapas Papel Cebolla - + Range Alcance - + Pencil2D Website Sitio web de Pencil2D - + Report a Bug Reportar una falla - - + + Quick Reference Guide + Quia de Consulta Rápida + + + + F1 + F1 + + + + Next KeyFrame Fotograma-Clave posterior - - + + Previous KeyFrame Fotograma-Clave anterior - + Timeline Línea de Tiempo - + Options Opciones - + Color Wheel Rueda de Color - + Color Palette Paleta de Color - + Display Options Opciones de Visualización - + Flip X Girar Horizontalmente - + Flip Y Girar Verticalmente - + Move Frame Forward Avanzar un fotograma - + Move Frame Backward Retroceder un fotograma @@ -1496,98 +1506,98 @@ Bloquear Ventanas - + Open Recent Abrir Reciente - + You have successfully cleared the list Lista eliminada con éxito - - - - + + + + Warning Advertencia - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil no puede leer este archivo. Si desea importar imágenes, utilice la opción Importar. - + Opening document... Abriendo Documento... - - - + + + Abort Abortar - + Saving document... Grabando Documento... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>Una falla ha ocurrido y el archivo puede que no se haya grabado correctamente. Si piensa que este error es un problema de Pencil2D, por favor haga un informe en:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Asegúrese de incluir los siguientes detalles en su reporte: - + This animation has been modified. Do you want to save your changes? Esta animación ha sido modificada. ¿Desea guardar sus cambios? - + The animation is not saved yet. Do you want to save now? La animación aun no ha sido gravada. Quiere gravarla ahora? - + Never ask again AutoSave reminder button No volver a preguntar - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. No se puede importar imagen<br><b>TIP:</b> Use una capa Bitmap para importar bitmaps. - + Importing image sequence... Importando secuencia de imágenes... - - + + Undo Menu item text Deshacer - + Redo Menu item text Rehacer - + Stop Parar @@ -1929,32 +1939,32 @@ Quiere gravarla ahora? Imágenes (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - + Everything ok. Todo correcto. - + Ooops, Something went wrong. ¡Ups! Algo ha salido mal. - + File doesn't exist. El archivo no existe. - + Cannot open file. No se puede abrir el archivo - + The file is not a valid xml document. El archivo no es un documento xml válido - + The file is not valid pencil document. El archivo no es un documento válido de Pencil @@ -3578,12 +3588,12 @@ Quiere gravarla ahora? TimeLineCells - + Layer Properties Propiedades de la capa - + Layer name: Nombre de la capa: diff --git a/translations/pencil_fr.ts b/translations/pencil_fr.ts index 4a2578084..1a0722f92 100644 --- a/translations/pencil_fr.ts +++ b/translations/pencil_fr.ts @@ -28,118 +28,118 @@ ActionCommands - + No sound layer exists as a destination for your import. Create a new sound layer? Votre piste son ne peut pas être importée car aucune piste de son n'existe. Créer une nouvelle piste de son ? - + Create sound layer Créer un calque de son - + Don't create layer Ne pas créer le calque - + Layer Properties Dialog title on creating a sound layer Propriétés du calque - + Sound Layer Default name on creating a sound layer Calque son - + Exporting movie Exporter un film - + Finished. Open movie now? When movie export done. Fini. Ouvrir un film maintenant? - - - - - Layer Properties - Propriétés du calque - - - + Layer Properties + Propriétés du calque + + + + + + + Layer name: Nom du calque: - + A sound clip already exists on this frame! Please select another frame or layer. Un clip sonore existe déjà sur ce cadre! Veuillez sélectionner un autre cadre ou calque. - + Exporting image sequence... Exportation de la séquence d'images... - + Abort Abandonner - + Warning Attention - + Unable to export image. Incapable d'exporter l'image. - + Bitmap Layer couche bitmap - + Vector Layer couche vecteur - + Camera Layer couche caméra - + Sound Layer couche son - + Delete Layer Windows title of Delete current layer pop-up. Supprimer le calque - + Are you sure you want to delete layer: Êtes-vous sûr de vouloir supprimer le calque: - + Please keep at least one camera layer in project text when failed to delete camera layer Veuillez conserver au moins un calque de caméra dans le projet @@ -447,19 +447,19 @@ Editor - - + + Paste Coller - + Remove frame Supprimer le cadre - - + + Import Image Importer une image @@ -1077,7 +1077,7 @@ - + Tools Outils @@ -1088,401 +1088,411 @@ - + Help Aide - + Windows Fenêtres - + New Nouveau - + Open Ouvrir - + Save Enregistrer - + Save As .. Enregistrer sous... - + Exit Sortie - - + + Image Sequence... Séquence d'images... - - + + Image... Image... - - + + Movie... Film... - - + + Palette... Palette... - + Sound... Son... - + Undo Annuler - + Redo Rétablir - + Cut Couper - + Copy Copier - + Paste Coller - + Crop Découper - + Crop To Selection Découper vers sélection - + Select All Tout sélectionner - + Deselect All Tout désélectionner - - + + Clear Frame Effacer l'image - + Preferences Préférences - + Reset Windows Réinitialiser la fenêtre - + Zoom In Agrandir - + Zoom Out Diminuer - + Rotate Clockwise Rotation sens horaire - + Rotate AntiClosewise Rotation sens anti horaire - + Reset Zoom/Rotate Réinitialiser Zoom/Rotation - + Horizontal Flip Symétrie horizontale - + Vertical Flip Symétrie verticale - + Preview Aperçu - + Grid Grille - + Previous Précédent - + Show previous onion skin Afficher précédente image transparente - + Next Suivant - + Show next onion skin Afficher prochaine image transparente - - + + Play Play - + Loop Boucle - + Next Frame image suivante - + Previous Frame image précédente - + Extend Frame image étendue - + Add Frame Ajouter une image - + Duplicate Frame Dupliquer une image - + Remove Frame Enlever une image - + Move Déplacer - + Select Sélectionner - + Brush Brosse - + Polyline Polyligne - + Smudge Etaler - + Pen Stylo - + Hand Main - + Pencil Crayon - + Bucket Seau - + Eyedropper Pipette - + Eraser Gomme - + New Bitmap Layer Nouveau calque Image - + New Vector Layer Nouveau calque Vecteur - + New Sound Layer Nouveau calque Son - + New Camera Layer Nouveau calque Caméra - + Delete Current Layer Supprimer le calque courant - + About A propos - - + + Reset to default Réinitialiser par défaut - + MultiLayer Onion Skin Peau d'oignon Multicouche - + Range Gamme - + Pencil2D Website Site Web Pencil2D - + Report a Bug Signaler un bug - - + + Quick Reference Guide + Aide-mémoire + + + + F1 + + + + + Next KeyFrame Image suivante - - + + Previous KeyFrame Image précedente - + Timeline Chronologie - + Options Options - + Color Wheel Roue Couleurs - + Color Palette Palette Couleurs - + Display Options Option d'Affichage - + Flip X Retourner axe X - + Flip Y Retourner axe Y - + Move Frame Forward Avancer l'image - + Move Frame Backward Reculer l'image @@ -1497,12 +1507,12 @@ Verrouiller les fenêtres - + Open Recent Ouvrir fichier récent - + You have successfully cleared the list @@ -1511,86 +1521,86 @@ Vous avez effacé la liste avec succès - - - - + + + + Warning Attention - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil ne peut pas lire ce fichier. Si vous voulez import des images, utilisez la commande import. - + Opening document... Document de démarrage... - - - + + + Abort Abandonner - + Saving document... Enregistrement d'un document... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>Une erreur est survenue et votre fichier n'a peut-être pas été sauvegardé correctement. Si vous pensez que cette erreur est un problème avec Pencil2D, veuillez créer un nouveau problème sur:<br><a href='https://github.com/pencil2d/pencil/issues'> https: //github.com/pencil2d/pencil/issues</a><br>Veuillez vous assurer d'inclure les détails suivants dans votre problème: - + This animation has been modified. Do you want to save your changes? Cette animation a été modifiée. Voulez vous sauvegarder vos modifications ? - + The animation is not saved yet. Do you want to save now? L'animation n'est pas encore enregistrée. Voulez-vous enregistrer maintenant? - + Never ask again AutoSave reminder button Ne plus me demander - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Impossible d'importer l'image.<br><b>ASTUCE:</b> Utilisez un calque "Bitmap" pour importer des bitmaps. - + Importing image sequence... Importation de la séquence d'image... - - + + Undo Menu item text Annuler - + Redo Menu item text Rétablir - + Stop Arrêter @@ -1828,7 +1838,7 @@ Voulez-vous enregistrer maintenant? Error: the input file at '%1' does not exist Command line error - + Erreur: le fichier source à '%1' n'existe pas @@ -1851,7 +1861,7 @@ Voulez-vous enregistrer maintenant? Warning: Transparency is not currently supported in movie files Command line warning - + Attention: la transparence n'est actuellement pas supportée dans les fichiers vidéo @@ -1932,32 +1942,32 @@ Voulez-vous enregistrer maintenant? Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - + Everything ok. Tout est OK. - + Ooops, Something went wrong. Oups, quelque chose ne s'est pas passé comme prévu. - + File doesn't exist. Le fichier n’existe pas. - + Cannot open file. Impossible d'ouvrir le fichier - + The file is not a valid xml document. Le fichier n'est pas un document xml valide. - + The file is not valid pencil document. Le fichier n'est pas un fichier Pencil valide. @@ -3581,12 +3591,12 @@ Voulez-vous enregistrer maintenant? TimeLineCells - + Layer Properties Propriétés du calque - + Layer name: Nom du calque: @@ -3848,13 +3858,13 @@ Voulez-vous enregistrer maintenant? Pressure Brush - + Pression Anti-Aliasing Brush AA - + Anticrénelage diff --git a/translations/pencil_he.ts b/translations/pencil_he.ts index b7e56029d..bdd528208 100644 --- a/translations/pencil_he.ts +++ b/translations/pencil_he.ts @@ -28,118 +28,118 @@ ActionCommands - + No sound layer exists as a destination for your import. Create a new sound layer? אין שכבת צליל לצורך יבוא. האם ליצור שכבת צליל חדשה? - + Create sound layer צור שכבת צליל - + Don't create layer אל תיצור שכבה - + Layer Properties Dialog title on creating a sound layer מאפייני שכבה - + Sound Layer Default name on creating a sound layer שכבת צליל - + Exporting movie - + Finished. Open movie now? When movie export done. סיימתי. האם לפתוח את הסרט כעת? - - - - - Layer Properties - מאפייני שכבה - - - + Layer Properties + מאפייני שכבה + + + + + + + Layer name: שם שכבה: - + A sound clip already exists on this frame! Please select another frame or layer. קטע קול קיים למסגרת זו! אנא בחר מסגרת או שכבה אחרת - + Exporting image sequence... מייצא רצף תמונות... - + Abort בטל - + Warning אזהרה - + Unable to export image. לא אפשרי לייצא תמונה - + Bitmap Layer שכבת מפת ביטים - + Vector Layer שכבת וקטורים - + Camera Layer שכבת מצלמה - + Sound Layer שכבת צליל - + Delete Layer Windows title of Delete current layer pop-up. מחק שכבה - + Are you sure you want to delete layer: האם אתה בטוח שברצונך למחוק שכבה: - + Please keep at least one camera layer in project text when failed to delete camera layer אנא שמור לפחות שכבת מצלמה אחת בפרוייקט @@ -446,19 +446,19 @@ Editor - - + + Paste הדבק - + Remove frame הסר מסגרת - - + + Import Image ייבא תמונה @@ -1076,7 +1076,7 @@ - + Tools כלים @@ -1087,401 +1087,411 @@ - + Help עזרה - + Windows חלונות - + New חדש - + Open פתח - + Save שמור - + Save As .. שמור בשם... - + Exit יציאה - - + + Image Sequence... רצף תמונות... - - + + Image... תמונה... - - + + Movie... סרט... - - + + Palette... טבלת צבעים... - + Sound... צליל... - + Undo בטל פעולה - + Redo חזור על פעולה - + Cut חתוך - + Copy העתק - + Paste הדבק - + Crop לחתוך לגודל - + Crop To Selection חתוך לאזור הבחירה - + Select All בחר הכל - + Deselect All בטל כל בחירה - - + + Clear Frame אפס מסגרת - + Preferences העדפות - + Reset Windows אפס חלונות - + Zoom In הגדלה - + Zoom Out הקטנה - + Rotate Clockwise סובב בכיוון השעון - + Rotate AntiClosewise סובב נגד כיוון השעון - + Reset Zoom/Rotate אפס הגדלה וסיבוב - + Horizontal Flip הפוך אופקית - + Vertical Flip הפוך אנכית - + Preview תצוגה מקדימה - + Grid רשת - + Previous הקודם - + Show previous onion skin הצג שכבת בצל קודמת - + Next הבא - + Show next onion skin הצג שכבת בצל הבאה - - + + Play נגן - + Loop לולאה - + Next Frame המסגרת הבאה - + Previous Frame המסגרת הקודמת - + Extend Frame הארכת מסגרת - + Add Frame הוסף מסגרת - + Duplicate Frame שכפל מסגרת - + Remove Frame הסר מסגרת - + Move הזז - + Select בחר - + Brush מברשת - + Polyline רב-קו - + Smudge טשטוש - + Pen עט - + Hand יד - + Pencil עפרון - + Bucket דלי - + Eyedropper טפטפת - + Eraser מחק - + New Bitmap Layer שכבת מפת ביטים חדשה - + New Vector Layer שכבת וקטורים חדשה - + New Sound Layer שכבת צליל חדשה - + New Camera Layer שכבת מצלמה חדשה - + Delete Current Layer מחק שכבה נוכחית - + About אודות - - + + Reset to default החזר לברירת המחדל - + MultiLayer Onion Skin עור בצל רב שכבתי - + Range תחום - + Pencil2D Website אתר Pencil2D - + Report a Bug דווח על באג - - + + Quick Reference Guide + + + + + F1 + + + + + Next KeyFrame מסגרת מפתח הבאה - - + + Previous KeyFrame מסגרת מפתח הקודמת - + Timeline ציר זמן - + Options אפשרויות - + Color Wheel גלגל צבעים - + Color Palette טבלת צבעים - + Display Options אפשרויות תצוגה - + Flip X הפוך X - + Flip Y הפוך Y - + Move Frame Forward הזז מסגרת קדימה - + Move Frame Backward הזז מסגרת אחורה @@ -1496,12 +1506,12 @@ נעל חלונות - + Open Recent פתח מהאחרונים - + You have successfully cleared the list @@ -1510,86 +1520,86 @@ מחקת בהצלחה את הרשימה - - - - + + + + Warning אזהרה - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil2D לא הצליחה לקרוא את הקובץ. אם ברצונך לייבא תמונות, השתמש בפעולת הייבוא - + Opening document... פותח מסמך... - - - + + + Abort בטל - + Saving document... שומר מסמך: - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>שגיאה ארעה ויתכן כי הקובץ שלך לא נשמר בהצלחה. אם אתה מאמין שזו תקלה ב-Pencil2D, אנא צור דו״ח תקלה בכתובת: <br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>אנא כלול את הפרטים הבאים בדיווח שלך: - + This animation has been modified. Do you want to save your changes? הנפשה זו נערכה ושונתה. האם ברצונך לשמור השינויים? - + The animation is not saved yet. Do you want to save now? ההנפשה לא נשמרה עדיין. האם ברצונך לשמור כעת? - + Never ask again AutoSave reminder button אל תשאל שוב - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. לא ניתן לייבא תמונה.<br><b>טיפ:</b> השתמש בשכבת מפת ביטים לייבוא תמונות - + Importing image sequence... - - + + Undo Menu item text - + Redo Menu item text - + Stop עצור @@ -1931,32 +1941,32 @@ תמונות (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - + Everything ok. הכל בסדר. - + Ooops, Something went wrong. אופס, משהו השתבש. - + File doesn't exist. קובץ לא קיים. - + Cannot open file. לא יכול לפתוח קובץ. - + The file is not a valid xml document. הקובץ אינו מסמך xml תקין. - + The file is not valid pencil document. הקובץ אינו מסמך pencil תקין. @@ -3580,12 +3590,12 @@ TimeLineCells - + Layer Properties מאפייני שכבה - + Layer name: שם שכבה: diff --git a/translations/pencil_hu_HU.ts b/translations/pencil_hu_HU.ts index e08e4289d..c97430f55 100644 --- a/translations/pencil_hu_HU.ts +++ b/translations/pencil_hu_HU.ts @@ -28,118 +28,118 @@ ActionCommands - + No sound layer exists as a destination for your import. Create a new sound layer? Nincs hang réteg a betöltendő állomány számára. Létrehoz egy új hang réteget? - + Create sound layer Hang réteg létrehozása - + Don't create layer Ne legyen réteg létrehozva - + Layer Properties Dialog title on creating a sound layer - + Sound Layer Default name on creating a sound layer - + Exporting movie - + Finished. Open movie now? When movie export done. - - - - - Layer Properties - Réteg tulajdonságai - - - + Layer Properties + Réteg tulajdonságai + + + + + + + Layer name: Réteg neve: - + A sound clip already exists on this frame! Please select another frame or layer. Egy hang már el lett helyezve ezen a képkockán. Válasszon másik pozíciót vagy réteget! - + Exporting image sequence... - + Abort - + Warning - + Unable to export image. - + Bitmap Layer Bitkép réteg - + Vector Layer Vektor réteg - + Camera Layer Kamera réteg - + Sound Layer Hang réteg - + Delete Layer Windows title of Delete current layer pop-up. - + Are you sure you want to delete layer: - + Please keep at least one camera layer in project text when failed to delete camera layer @@ -446,19 +446,19 @@ Editor - - + + Paste Beillesztés - + Remove frame - - + + Import Image Kép importálása @@ -1076,7 +1076,7 @@ - + Tools Eszközök @@ -1087,401 +1087,411 @@ - + Help Súgó - + Windows Ablakok - + New Új - + Open Megnyitás - + Save Mentés - + Save As .. Mentés másként .. - + Exit Kilépés - - + + Image Sequence... Képsorozat... - - + + Image... Kép... - - + + Movie... Videó... - - + + Palette... Paletta... - + Sound... Hang... - + Undo Visszavonás - + Redo Újra - + Cut Kivágás - + Copy Másolás - + Paste Beillesztés - + Crop Csonkítás - + Crop To Selection Csonkítás kijelölésre - + Select All Minden kijelölése - + Deselect All Kijelölés megszüntetése - - + + Clear Frame Képkocka kiürítése - + Preferences Beállítások - + Reset Windows Ablakok visszaállítása - + Zoom In Nagyítás - + Zoom Out Kicsinyítés - + Rotate Clockwise Forgatás jobbra - + Rotate AntiClosewise Forgatás balra - + Reset Zoom/Rotate Nagyítás/Elforgatás visszaállítása - + Horizontal Flip Vízszintes tükrözés - + Vertical Flip Függőleges tükrözés - + Preview Előnézet - + Grid Rács - + Previous Előző - + Show previous onion skin Előző képfólia megjelenítése - + Next Következő - + Show next onion skin Következő képfólia megjelenítése - - + + Play Lejátszás - + Loop Ismétlés - + Next Frame Következő képkocka - + Previous Frame Előző képkocka - + Extend Frame Képkocka kiterjesztése - + Add Frame Képkocka hozzáadása - + Duplicate Frame Képkocka kétszerezése - + Remove Frame Képkocka eltávolítása - + Move Mozgatás - + Select Kijelölés - + Brush Ecset - + Polyline Vonallánc - + Smudge Maszatolás - + Pen Toll - + Hand Kéz - + Pencil Ceruza - + Bucket Vödör - + Eyedropper Szemcseppentő - + Eraser Radír - + New Bitmap Layer Új bitkép réteg - + New Vector Layer Új vektor réteg - + New Sound Layer Új hang réteg - + New Camera Layer Új kamera réteg - + Delete Current Layer Aktuális réteg törlése - + About Névjegy - - + + Reset to default Alapértékek visszaállítása - + MultiLayer Onion Skin Többrétegű képfóliák - + Range Tartomány - + Pencil2D Website - + Report a Bug - - + + Quick Reference Guide + + + + + F1 + + + + + Next KeyFrame Következő kulcsképkocka - - + + Previous KeyFrame Előző kulcsképkocka - + Timeline Idővonal - + Options Beállítások - + Color Wheel Színkerék - + Color Palette Színpaletta - + Display Options Megjelenítés beállításai - + Flip X X tükrözés - + Flip Y Y tükrözés - + Move Frame Forward Képkocka mozgatása előre - + Move Frame Backward Képkocka mozgatása hátra @@ -1496,97 +1506,97 @@ - + Open Recent Legutóbbi megnyitása - + You have successfully cleared the list - - - - + + + + Warning Figyelmeztetés - - + + Pencil cannot read this file. If you want to import images, use the command import. A Pencil nem tudja olvasni ezt a fájlt. Képek beemeléséhez az "Importálás" művelet használható. - + Opening document... Dokumentum megnyitása... - - - + + + Abort Névjegy - + Saving document... Dokumentum mentése... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: - + This animation has been modified. Do you want to save your changes? Ez az animáció meg lett változtatva. Szeretné menteni a változásokat? - + The animation is not saved yet. Do you want to save now? - + Never ask again AutoSave reminder button - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. A kép nem importálható.<br><b>TIPP:</b> Képek importálásához bitkép réteget kell használni. - + Importing image sequence... - - + + Undo Menu item text - + Redo Menu item text - + Stop Megállítás @@ -1928,32 +1938,32 @@ Képek (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - + Everything ok. Minden rendben. - + Ooops, Something went wrong. Hoppá, valami rosszul sikerült. - + File doesn't exist. A fájl nem létezik. - + Cannot open file. A fájl nem nyitható meg. - + The file is not a valid xml document. Ez a fájl nem egy érvényes XML dokumentum. - + The file is not valid pencil document. Ez a fájl nem egy érvényes Pencil dokumentum. @@ -3577,12 +3587,12 @@ TimeLineCells - + Layer Properties - + Layer name: diff --git a/translations/pencil_id.ts b/translations/pencil_id.ts index 1112d2c47..2f6f2f304 100644 --- a/translations/pencil_id.ts +++ b/translations/pencil_id.ts @@ -28,118 +28,118 @@ ActionCommands - + No sound layer exists as a destination for your import. Create a new sound layer? - + Create sound layer Buat layer suara - + Don't create layer Jangan buat layer - + Layer Properties Dialog title on creating a sound layer - + Sound Layer Default name on creating a sound layer - + Exporting movie - + Finished. Open movie now? When movie export done. - - - - - Layer Properties - - - - + Layer Properties + + + + + + + + Layer name: Nama layer - + A sound clip already exists on this frame! Please select another frame or layer. Klip suara telah tersedia dalam frame ini! Mohon pilih frame yang lain atau layer - + Exporting image sequence... Mengekspor gambar berurutan - + Abort Gagalkan - + Warning Peringatan - + Unable to export image. Tidak mampu mengekspor gambar. - + Bitmap Layer - + Vector Layer - + Camera Layer - + Sound Layer - + Delete Layer Windows title of Delete current layer pop-up. - + Are you sure you want to delete layer: - + Please keep at least one camera layer in project text when failed to delete camera layer @@ -446,19 +446,19 @@ Editor - - + + Paste Tempel - + Remove frame - - + + Import Image Impor Gambar @@ -1076,7 +1076,7 @@ - + Tools Peralatan @@ -1087,401 +1087,411 @@ - + Help Bantuan - + Windows - + New - + Open - + Save - + Save As .. - + Exit - - + + Image Sequence... - - + + Image... - - + + Movie... - - + + Palette... Palet... - + Sound... Suara... - + Undo - + Redo - + Cut - + Copy - + Paste - + Crop - + Crop To Selection - + Select All - + Deselect All - - + + Clear Frame - + Preferences - + Reset Windows - + Zoom In - + Zoom Out - + Rotate Clockwise - + Rotate AntiClosewise - + Reset Zoom/Rotate - + Horizontal Flip - + Vertical Flip - + Preview - + Grid - + Previous - + Show previous onion skin - + Next - + Show next onion skin - - + + Play - + Loop - + Next Frame - + Previous Frame - + Extend Frame - + Add Frame - + Duplicate Frame - + Remove Frame - + Move - + Select - + Brush - + Polyline - + Smudge - + Pen - + Hand - + Pencil - + Bucket - + Eyedropper - + Eraser - + New Bitmap Layer - + New Vector Layer - + New Sound Layer - + New Camera Layer - + Delete Current Layer - + About - - + + Reset to default - + MultiLayer Onion Skin - + Range - + Pencil2D Website - + Report a Bug - - + + Quick Reference Guide + + + + + F1 + + + + + Next KeyFrame - - + + Previous KeyFrame - + Timeline - + Options - + Color Wheel - + Color Palette - + Display Options - + Flip X - + Flip Y - + Move Frame Forward - + Move Frame Backward @@ -1496,96 +1506,96 @@ - + Open Recent - + You have successfully cleared the list - - - - + + + + Warning - - + + Pencil cannot read this file. If you want to import images, use the command import. - + Opening document... - - - + + + Abort - + Saving document... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: - + This animation has been modified. Do you want to save your changes? - + The animation is not saved yet. Do you want to save now? - + Never ask again AutoSave reminder button - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. - + Importing image sequence... - - + + Undo Menu item text - + Redo Menu item text - + Stop @@ -1927,32 +1937,32 @@ - + Everything ok. - + Ooops, Something went wrong. - + File doesn't exist. - + Cannot open file. - + The file is not a valid xml document. - + The file is not valid pencil document. @@ -3576,12 +3586,12 @@ TimeLineCells - + Layer Properties - + Layer name: diff --git a/translations/pencil_it.ts b/translations/pencil_it.ts index 29020ef54..6ebb8ed05 100644 --- a/translations/pencil_it.ts +++ b/translations/pencil_it.ts @@ -28,118 +28,118 @@ ActionCommands - + No sound layer exists as a destination for your import. Create a new sound layer? Non esiste nessun livello suono come destinazione per l'importazione. Creare un nuovo livello suono? - + Create sound layer Crea livello di suono - + Don't create layer Non creare il livello - + Layer Properties Dialog title on creating a sound layer - + Sound Layer Default name on creating a sound layer - + Exporting movie - + Finished. Open movie now? When movie export done. - - - - - Layer Properties - Proprietà del livello - - - + Layer Properties + Proprietà del livello + + + + + + + Layer name: Nome del livello: - + A sound clip already exists on this frame! Please select another frame or layer. Un clip audio esiste già in questo fotogramma! Perfavore selezionare un altro fotogramma o livello. - + Exporting image sequence... - + Abort - + Warning Avviso - + Unable to export image. - + Bitmap Layer Livello Bitmap - + Vector Layer Livello Vettoriale - + Camera Layer Livello Videocamera - + Sound Layer Livello Suono - + Delete Layer Windows title of Delete current layer pop-up. - + Are you sure you want to delete layer: - + Please keep at least one camera layer in project text when failed to delete camera layer @@ -446,19 +446,19 @@ Editor - - + + Paste Incolla - + Remove frame - - + + Import Image Importa immagine @@ -1076,7 +1076,7 @@ - + Tools Strumenti @@ -1087,401 +1087,411 @@ - + Help Aiuto - + Windows Finestre - + New Nuovo - + Open Apri - + Save Salva - + Save As .. Salva come... - + Exit Esci - - + + Image Sequence... Sequenza immagini... - - + + Image... Immagine... - - + + Movie... Animazione... - - + + Palette... Tavolozza... - + Sound... Audio... - + Undo Annulla - + Redo Ripeti - + Cut Taglia - + Copy Copia - + Paste Incolla - + Crop Ritaglia - + Crop To Selection Ritaglia alla selezione - + Select All Seleziona tutto - + Deselect All Deseleziona tutto - - + + Clear Frame Pulisci fotogramma - + Preferences Preferenze - + Reset Windows Ripristina finestra - + Zoom In Ingrandisci - + Zoom Out Rimpicciolisci - + Rotate Clockwise Ruota in senso orario - + Rotate AntiClosewise Ruota in senso antiorario - + Reset Zoom/Rotate Ripristina ingrandimento/rotazione - + Horizontal Flip Rifletti orizzontalmente - + Vertical Flip Rifletti verticalmente - + Preview Anteprima - + Grid Griglia - + Previous Precedente - + Show previous onion skin Mostra velina precedente - + Next Successivo - + Show next onion skin Mostra velina seguente - - + + Play Riproduci - + Loop Ciclo - + Next Frame Fotogramma successivo - + Previous Frame Fotogramma precedente - + Extend Frame Estendi fotogramma - + Add Frame Aggiungi fotogramma - + Duplicate Frame Duplica fotogramma - + Remove Frame Cancella fotogramma - + Move Sposta - + Select Seleziona - + Brush Pennello - + Polyline Polilinea - + Smudge Sfuma - + Pen Penna - + Hand Mano - + Pencil Matita - + Bucket Secchiello - + Eyedropper Preleva colore - + Eraser Gomma - + New Bitmap Layer Nuovo livello bitmap - + New Vector Layer Nuovo livello vettoriale - + New Sound Layer Nuovo livello audio - + New Camera Layer Nuovo livello videocamera - + Delete Current Layer Elimina livello - + About Informazioni - - + + Reset to default Ripristina predefiniti - + MultiLayer Onion Skin Velina multilivello - + Range Intervallo - + Pencil2D Website - + Report a Bug - - + + Quick Reference Guide + + + + + F1 + + + + + Next KeyFrame KeyFrame seguente - - + + Previous KeyFrame KeyFrame precedente - + Timeline Linea del tempo - + Options Opzioni - + Color Wheel Ruota dei colori - + Color Palette Tavolozza dei colori - + Display Options Opzioni di visualizzazione - + Flip X Rifletti X - + Flip Y Rifletti Y - + Move Frame Forward Sposta fotogramma in avanti - + Move Frame Backward Sposta fotogramma indietro @@ -1496,97 +1506,97 @@ - + Open Recent Apri recenti - + You have successfully cleared the list - - - - + + + + Warning Attenzione - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil non può leggere questo file. Per importare immagini usare il comando importa. - + Opening document... Apertura del documento... - - - + + + Abort Annulla - + Saving document... Salvataggio del documento... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: - + This animation has been modified. Do you want to save your changes? Questa animazione è stata modificata. Vuoi salavare i cambiamenti? - + The animation is not saved yet. Do you want to save now? L'animazione non è ancora salvata. Vuoi salvarla ora? - + Never ask again AutoSave reminder button Non chiederlo più - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Impossibile caricare l'immagine.<br><b>Suggerimento:</b> usare un livello bitmap per importarla. - + Importing image sequence... - - + + Undo Menu item text - + Redo Menu item text - + Stop Stop @@ -1928,32 +1938,32 @@ Vuoi salavare i cambiamenti? Immagini (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - + Everything ok. Tutto ok. - + Ooops, Something went wrong. Oops, qualcosa è andato storto. - + File doesn't exist. Il file non esiste. - + Cannot open file. Impossible aprire il file. - + The file is not a valid xml document. Il file non è un documento xml valido. - + The file is not valid pencil document. Il file non è un documento di Pencil valido. @@ -3577,12 +3587,12 @@ Vuoi salavare i cambiamenti? TimeLineCells - + Layer Properties - + Layer name: diff --git a/translations/pencil_ja.ts b/translations/pencil_ja.ts index c29a472bb..4216dc1d2 100644 --- a/translations/pencil_ja.ts +++ b/translations/pencil_ja.ts @@ -28,118 +28,118 @@ ActionCommands - + No sound layer exists as a destination for your import. Create a new sound layer? 音声の読み込みができる音声レイヤーがありません。音声レイヤーを作成しますか? - + Create sound layer 音声レイヤーを作成 - + Don't create layer 作成しない - + Layer Properties Dialog title on creating a sound layer - + Sound Layer Default name on creating a sound layer - + Exporting movie - + Finished. Open movie now? When movie export done. - - - - - Layer Properties - レイヤーのプロパティ - - - + Layer Properties + レイヤーのプロパティ + + + + + + + Layer name: レイヤー名: - + A sound clip already exists on this frame! Please select another frame or layer. このフレームにには既に音声クリップが存在します。他のフレーム、またはレイヤーを選択して下さい。 - + Exporting image sequence... - + Abort - + Warning - + Unable to export image. - + Bitmap Layer ビットマップレイヤー - + Vector Layer ベクターレイヤー - + Camera Layer カメラレイヤー - + Sound Layer 音声レイヤー - + Delete Layer Windows title of Delete current layer pop-up. - + Are you sure you want to delete layer: - + Please keep at least one camera layer in project text when failed to delete camera layer @@ -446,19 +446,19 @@ Editor - - + + Paste 貼り付け - + Remove frame - - + + Import Image イメージを読み込む @@ -1076,7 +1076,7 @@ - + Tools ツール @@ -1087,401 +1087,411 @@ - + Help ヘルプ - + Windows ウィンドウ - + New 新規 - + Open 開く - + Save 保存 - + Save As .. 名前を付けて保存... - + Exit 終了 - - + + Image Sequence... 連番画像... - - + + Image... 画像... - - + + Movie... 動画... - - + + Palette... パレット... - + Sound... 音声... - + Undo 元に戻す - + Redo やり直す - + Cut 切り取り - + Copy コピー - + Paste 貼り付け - + Crop 切り抜き - + Crop To Selection 選択範囲でクロップ - + Select All すべて選択 - + Deselect All すべての選択を解除 - - + + Clear Frame フレームをクリア - + Preferences 詳細設定 - + Reset Windows ウィンドウをリセット - + Zoom In ズームイン - + Zoom Out ズームアウト - + Rotate Clockwise 時計回りに回転 - + Rotate AntiClosewise 反時計回りに回転 - + Reset Zoom/Rotate ズームと回転をリセット - + Horizontal Flip 水平反転 - + Vertical Flip 垂直反転 - + Preview プレビュー - + Grid グリッド - + Previous - + Show previous onion skin 前のフレームのオニオンスキンを表示 - + Next - + Show next onion skin 次のフレームのオニオンスキンを表示 - - + + Play 再生 - + Loop ループ - + Next Frame 次のフレーム - + Previous Frame 前のフレーム - + Extend Frame フレーム - + Add Frame フレームを追加 - + Duplicate Frame フレームを複製 - + Remove Frame フレームを削除 - + Move 移動 - + Select 選択 - + Brush ブラシ - + Polyline 折れ線 - + Smudge 指先 - + Pen ペン - + Hand 手のひら - + Pencil 鉛筆 - + Bucket バケツ - + Eyedropper スポイト - + Eraser 消しゴム - + New Bitmap Layer 新しいビットマップレイヤー - + New Vector Layer 新しいベクターレイヤー - + New Sound Layer 新しい音声レイヤー - + New Camera Layer 新しいカメラレイヤー - + Delete Current Layer 現在のレイヤーを削除 - + About About - - + + Reset to default 初期状態に戻す - + MultiLayer Onion Skin 複数レイヤーのオニオンスキンを表示 - + Range 範囲 - + Pencil2D Website - + Report a Bug - - + + Quick Reference Guide + + + + + F1 + + + + + Next KeyFrame 次のキーフレーム - - + + Previous KeyFrame 前のキーフレーム - + Timeline タイムライン - + Options オプション - + Color Wheel カラーホイール - + Color Palette カラーパレット - + Display Options 表示オプション - + Flip X 水平反転 - + Flip Y 垂直反転 - + Move Frame Forward 次のフレームに移動 - + Move Frame Backward 前のフレームに移動 @@ -1496,97 +1506,97 @@ - + Open Recent 最近使ったファイル - + You have successfully cleared the list リストは正常に削除されました - - - - + + + + Warning 警告 - - + + Pencil cannot read this file. If you want to import images, use the command import. 読み込みエラーです。画像を読み込む場合は「読み込む」コマンドを使用して下さい。 - + Opening document... ドキュメントを開いています... - - - + + + Abort 中断 - + Saving document... ドキュメントを保存しています... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>エラーによってファイルが正常に保存されなかった可能性があります。もしこのエラーがPencil2Dによって起こったと推測される場合は, <br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>にアクセスして新しい"issue"として報告してください。ご報告の際は、以下の詳細を追記してください: - + This animation has been modified. Do you want to save your changes? ファイルの変更があります。 これらの変更を保存しますか? - + The animation is not saved yet. Do you want to save now? - + Never ask again AutoSave reminder button - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. 画像が読み込めません。<br><b>ヒント:</b> ビットマップファイルはビットマップレイヤーに読み込んでください。 - + Importing image sequence... - - + + Undo Menu item text - + Redo Menu item text - + Stop 停止 @@ -1928,32 +1938,32 @@ 画像 (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - + Everything ok. 正常終了 - + Ooops, Something went wrong. エラーが発生しました。 - + File doesn't exist. ファイルは存在しません。 - + Cannot open file. ファイルの読み込みに失敗しました。 - + The file is not a valid xml document. 正常なXMLファイルではありません。 - + The file is not valid pencil document. 正常なPencil2Dのドキュメントではありません。 @@ -3577,12 +3587,12 @@ TimeLineCells - + Layer Properties - + Layer name: diff --git a/translations/pencil_pt.ts b/translations/pencil_pt.ts index 3f47fd825..d24df45d6 100644 --- a/translations/pencil_pt.ts +++ b/translations/pencil_pt.ts @@ -28,118 +28,118 @@ ActionCommands - + No sound layer exists as a destination for your import. Create a new sound layer? Não existe uma camada de som para importar o ficheiro. Criar uma nova? - + Create sound layer Criar Camada de Som - + Don't create layer Não Criar Camada - + Layer Properties Dialog title on creating a sound layer Propriedades da Camada - + Sound Layer Default name on creating a sound layer Camada de Som - + Exporting movie Exportar filme - + Finished. Open movie now? When movie export done. Concluído. Abrir o filme agora? - - - - - Layer Properties - Propriedades da Camada - - - + Layer Properties + Propriedades da Camada + + + + + + + Layer name: Nome da Camada: - + A sound clip already exists on this frame! Please select another frame or layer. Já existe um clipe de som neste quadro! Por favor seleccione outro quadro ou camada - + Exporting image sequence... Exportando sequência de imagens - + Abort Abortar - + Warning Aviso - + Unable to export image. Não é possível exportar imagem - + Bitmap Layer Camada Bitmap - + Vector Layer Camada Vectorial - + Camera Layer Camada da Câmara - + Sound Layer Camada de Som - + Delete Layer Windows title of Delete current layer pop-up. Excluir Camada - + Are you sure you want to delete layer: Tem certeza de que quer excluir a camada: - + Please keep at least one camera layer in project text when failed to delete camera layer Por favor, mantenha pelo menos uma câmara no projecto @@ -446,19 +446,19 @@ Editor - - + + Paste Colar - + Remove frame Remover quadro - - + + Import Image Importar imagem @@ -1076,7 +1076,7 @@ - + Tools Ferramentas @@ -1087,401 +1087,411 @@ - + Help Ajuda - + Windows Janelas - + New Novo - + Open Abrir - + Save Gravar - + Save As .. Gravar como... - + Exit Sair - - + + Image Sequence... Sequência de imagens... - - + + Image... Imagem... - - + + Movie... Filme... - - + + Palette... Paleta... - + Sound... Som... - + Undo Desfazer - + Redo Refazer - + Cut Cortar - + Copy Copiar - + Paste Colar - + Crop Recortar - + Crop To Selection Ajustar à selecção - + Select All Seleccionar Tudo - + Deselect All Desmarcar Tudo - - + + Clear Frame Limpar Quadro - + Preferences Preferências - + Reset Windows Reiniciar Janelas - + Zoom In Aproximar - + Zoom Out Afastar - + Rotate Clockwise Girar no sentido horário - + Rotate AntiClosewise Girar no sentido anti-horário - + Reset Zoom/Rotate Restaurar zoom/rotação - + Horizontal Flip Virar horizontalmente - + Vertical Flip Virar verticalmente - + Preview Pré-visualização - + Grid Grelha - + Previous Anterior - + Show previous onion skin Mostrar transparência anterior - + Next Seguinte - + Show next onion skin Mostra transparência seguinte - - + + Play Reproduzir - + Loop Repetir - + Next Frame Quadro seguinte - + Previous Frame Quadro anterior - + Extend Frame Estender quadro - + Add Frame Adicionar quadro - + Duplicate Frame Duplicar quadro - + Remove Frame Remover quadro - + Move Mover - + Select Seleccionar - + Brush Pincel - + Polyline Polilinha - + Smudge Espalhar - + Pen Caneta - + Hand Mão - + Pencil Lápis - + Bucket Balde - + Eyedropper Conta-gotas - + Eraser Borracha - + New Bitmap Layer Nova Camada Bitmap - + New Vector Layer Nova Camada Vectorial - + New Sound Layer Nova Camada de Som - + New Camera Layer Nova camada da câmara - + Delete Current Layer Excluir Camada Actual - + About Sobre - - + + Reset to default Restaurar definições padrão - + MultiLayer Onion Skin Transparência Multicamadas - + Range Intervalo - + Pencil2D Website Site Pencil2D - + Report a Bug Reportar falha - - + + Quick Reference Guide + Manual de Consulta Rápida + + + + F1 + F1 + + + + Next KeyFrame Quadro-chave seguinte - - + + Previous KeyFrame Quadro-chave anterior - + Timeline Linha do tempo - + Options Opções - + Color Wheel Roda de Cores - + Color Palette Paleta de Cores - + Display Options Opções de visualização - + Flip X Virar X - + Flip Y Virar Y - + Move Frame Forward Mover Quadro para Frente - + Move Frame Backward Mover Quadro para Trás @@ -1496,12 +1506,12 @@ Bloquear Janelas - + Open Recent Abrir Recente - + You have successfully cleared the list @@ -1509,85 +1519,85 @@ Acabou de limpar a lista com sucesso - - - - + + + + Warning Aviso - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil não consegue ler este arquivo. Se você quiser importar imagens, use o comando Importar. - + Opening document... Abrindo documento... - - - + + + Abort Abortar - + Saving document... Gravando documento... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>Ocorreu um erro e seu ficheiro pode não ter sido gravado com sucesso. Se você achar que é um problema com Pencil2D, por favor crie um tópico em: <br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Por favor, certifique-se de incluir os seguintes detalhes: - + This animation has been modified. Do you want to save your changes? Esta animação foi modificada. Deseja gravar as alterações? - + The animation is not saved yet. Do you want to save now? A animação não foi gravada. Quer gravá-la agora? - + Never ask again AutoSave reminder button Não voltar a perguntar - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Não é possível importar imagem. <br><b>DICA:</b> Use uma Camada Bitmap para importar bitmaps. - + Importing image sequence... Importando sequência de imagens... - - + + Undo Menu item text Desfazer - + Redo Menu item text Refazer - + Stop Parar @@ -1861,7 +1871,7 @@ Deseja gravar as alterações? Done. Command line task done - Concluído + Concluído. @@ -1929,32 +1939,32 @@ Deseja gravar as alterações? Imagens (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - + Everything ok. Tudo certo. - + Ooops, Something went wrong. Opa! Alguma coisa deu errado. - + File doesn't exist. O ficheiro não existe. - + Cannot open file. Não é possível abrir o ficheiro. - + The file is not a valid xml document. O ficheiro não é um documento XML válido. - + The file is not valid pencil document. O ficheiro não é um documento Pencil2D válido. @@ -3578,12 +3588,12 @@ Deseja gravar as alterações? TimeLineCells - + Layer Properties Propriedades da Camada - + Layer name: Nome da Camada: diff --git a/translations/pencil_pt_BR.ts b/translations/pencil_pt_BR.ts index bbb03d8f7..9569787bb 100644 --- a/translations/pencil_pt_BR.ts +++ b/translations/pencil_pt_BR.ts @@ -28,118 +28,118 @@ ActionCommands - + No sound layer exists as a destination for your import. Create a new sound layer? Não há uma camada de som para importar. Criar uma nova? - + Create sound layer Criar camada de som - + Don't create layer Não criar camada - + Layer Properties Dialog title on creating a sound layer Propriedades da Camada - + Sound Layer Default name on creating a sound layer Camada de Som - + Exporting movie Exportando vídeo - + Finished. Open movie now? When movie export done. Finalizado. Abrir vídeo agora? - - - - - Layer Properties - Propriedades da camada - - - + Layer Properties + Propriedades da camada + + + + + + + Layer name: Nome da camada: - + A sound clip already exists on this frame! Please select another frame or layer. Já existe um clipe de som neste quadro! Por favor selecione outro quadro ou camada - + Exporting image sequence... Exportando sequência de imagens... - + Abort Abortar - + Warning Aviso - + Unable to export image. Impossível exportar imagem. - + Bitmap Layer Camada Bitmap - + Vector Layer Camada Vetorial - + Camera Layer Camada de Câmera - + Sound Layer Camada de Som - + Delete Layer Windows title of Delete current layer pop-up. Apagar Camada - + Are you sure you want to delete layer: Você tem certeza de que deseja apagar a camada: - + Please keep at least one camera layer in project text when failed to delete camera layer Por favor, mantenha ao menos uma camada de câmera no projeto @@ -446,19 +446,19 @@ Editor - - + + Paste Colar - + Remove frame Remover quadro - - + + Import Image Importar imagem @@ -1076,7 +1076,7 @@ - + Tools Ferramentas @@ -1087,401 +1087,411 @@ - + Help Ajuda - + Windows Janelas - + New Novo - + Open Abrir - + Save Salvar - + Save As .. Salvar como... - + Exit Sair - - + + Image Sequence... Sequência de imagens... - - + + Image... Imagem... - - + + Movie... Vídeo... - - + + Palette... Paleta... - + Sound... Som... - + Undo Desfazer - + Redo Refazer - + Cut Cortar - + Copy Copiar - + Paste Colar - + Crop Recortar - + Crop To Selection Recortar para a seleção - + Select All Selecionar Tudo - + Deselect All Desmarcar Tudo - - + + Clear Frame Limpar Quadro - + Preferences Preferências - + Reset Windows Reiniciar Janelas - + Zoom In Aproximar - + Zoom Out Afastar - + Rotate Clockwise Girar em sentido horário - + Rotate AntiClosewise Girar em sentido anti-horário - + Reset Zoom/Rotate Restaurar zoom/rotação - + Horizontal Flip Inverter horizontalmente - + Vertical Flip Virar verticalmente - + Preview Prévia - + Grid Grade - + Previous Anterior - + Show previous onion skin Mostrar transparência anterior - + Next Próxima - + Show next onion skin Mostrar próxima transparência - - + + Play Reproduzir - + Loop Repetir - + Next Frame Próximo Quadro - + Previous Frame Quadro Anterior - + Extend Frame Estender Quadro - + Add Frame Adicionar Quadro - + Duplicate Frame Duplicar Quadro - + Remove Frame Remover Quadro - + Move Mover - + Select Selecionar - + Brush Pincel - + Polyline Polilinha - + Smudge Borrar - + Pen Caneta - + Hand Mão - + Pencil Lápis - + Bucket Balde - + Eyedropper Conta-gotas - + Eraser Borracha - + New Bitmap Layer Nova camada Bitmap - + New Vector Layer Nova camada Vetorial - + New Sound Layer Nova camada de Som - + New Camera Layer Nova camada de Câmera - + Delete Current Layer Apagar camada atual - + About Sobre - - + + Reset to default Restaurar para o padrão - + MultiLayer Onion Skin Transparência Multicamadas - + Range Intervalo - + Pencil2D Website Website do Pencil2D - + Report a Bug Reportar um Bug - - + + Quick Reference Guide + Guia Rápido de Referência + + + + F1 + F1 + + + + Next KeyFrame Próximo quadro-chave - - + + Previous KeyFrame Quadro-chave anterior - + Timeline Linha do tempo - + Options Opções - + Color Wheel Roda de Cores - + Color Palette Paleta de Cores - + Display Options Opções da tela - + Flip X Inverter X - + Flip Y Inverter Y - + Move Frame Forward Mover Quadro para Frente - + Move Frame Backward Mover Quadro para Trás @@ -1496,12 +1506,12 @@ Bloquear Janelas - + Open Recent Abrir Recente - + You have successfully cleared the list @@ -1509,86 +1519,86 @@ Você limpou a lista com sucesso - - - - + + + + Warning Aviso - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil não consegue ler este arquivo. Se você quiser importar imagens, use o comando Importar. - + Opening document... Abrindo documento... - - - + + + Abort Abortar - + Saving document... Salvando documento... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>Um erro ocorreu e seu arquivo pode não ter sido salvo com sucesso. Se você acredita que é um problema com Pencil2D, por favor crie um tópico em: <br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Por favor, certifique-se de incluir os seguintes detalhes: - + This animation has been modified. Do you want to save your changes? Esta animação foi modificada. Você deseja salvar suas alterações? - + The animation is not saved yet. Do you want to save now? A animação não foi salva. Gostaria de salvar agora? - + Never ask again AutoSave reminder button Não pergunte novamente - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Impossível importar imagem. <br><b>DICA:</b> Use uma camada Bitmap para importar bitmaps. - + Importing image sequence... Importando sequência de imagens... - - + + Undo Menu item text Desfazer - + Redo Menu item text Refazer - + Stop Parar @@ -1930,32 +1940,32 @@ Gostaria de salvar agora? Imagens (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - + Everything ok. Tudo certo. - + Ooops, Something went wrong. Opa! Alguma coisa deu errado. - + File doesn't exist. O arquivo não existe. - + Cannot open file. Impossível abrir o arquivo. - + The file is not a valid xml document. O arquivo não é um documento XML válido. - + The file is not valid pencil document. O arquivo não é um documento Pencil válido. @@ -3579,12 +3589,12 @@ Gostaria de salvar agora? TimeLineCells - + Layer Properties Propriedades da camada - + Layer name: Nome da camada: diff --git a/translations/pencil_ru.ts b/translations/pencil_ru.ts index 53186854e..9eae6aa96 100644 --- a/translations/pencil_ru.ts +++ b/translations/pencil_ru.ts @@ -28,118 +28,118 @@ ActionCommands - + No sound layer exists as a destination for your import. Create a new sound layer? Звуковой слой отсутствует в качестве места назначения для вашего импорта. Создать новый звуковой слой? - + Create sound layer Создать звуковой слой - + Don't create layer Не создавать слой - + Layer Properties Dialog title on creating a sound layer Свойства слоя - + Sound Layer Default name on creating a sound layer Звуковой слой - + Exporting movie Экспорт фильма - + Finished. Open movie now? When movie export done. Завершено. Открыть фильм сейчас? - - - - - Layer Properties - Свойства слоя - - - + Layer Properties + Свойства слоя + + + + + + + Layer name: Имя слоя: - + A sound clip already exists on this frame! Please select another frame or layer. Звуковой клип уже существует на этом кадре! Выберите другой кадр или слой. - + Exporting image sequence... Экспорт последовательности изображений... - + Abort Отменить - + Warning Предупреждение - + Unable to export image. Не удалось экспортировать изображение. - + Bitmap Layer Слой битовой карты - + Vector Layer Векторный слой - + Camera Layer Слой камеры - + Sound Layer Звуковой слой - + Delete Layer Windows title of Delete current layer pop-up. Удалить слой - + Are you sure you want to delete layer: Вы уверены, что хотите удалить слой: - + Please keep at least one camera layer in project text when failed to delete camera layer Пожалуйста, сохраните хотя бы один слой камеры в проекте. @@ -446,19 +446,19 @@ Editor - - + + Paste Вставить - + Remove frame Удалить кадр - - + + Import Image Импорт изображения @@ -1076,7 +1076,7 @@ - + Tools Инструменты @@ -1087,401 +1087,411 @@ - + Help Помощь - + Windows Окна - + New Создать - + Open Открыть - + Save Сохранить - + Save As .. Сохранить как... - + Exit Выход - - + + Image Sequence... Последовательность изображений... - - + + Image... Изображение... - - + + Movie... Ролик... - - + + Palette... Палитра... - + Sound... Звук... - + Undo Отменить - + Redo Повторить - + Cut Вырезать - + Copy Копировать - + Paste Вставить - + Crop Обрезать - + Crop To Selection Кадрировать - + Select All Выделить всё - + Deselect All Снять выделение - - + + Clear Frame Очистить кадр - + Preferences Настройки - + Reset Windows Окна по умолчанию - + Zoom In Приблизить - + Zoom Out Отдалить - + Rotate Clockwise Вращать по часовой стрелке - + Rotate AntiClosewise Вращать против часовой стрелки - + Reset Zoom/Rotate Сбросить масштабирование/поворот - + Horizontal Flip Отразить по горизонтали - + Vertical Flip Отразить по вертикали - + Preview Предпросмотр - + Grid Сетка - + Previous Предыдущий кадр - + Show previous onion skin - + Next Следующий кадр - + Show next onion skin - - + + Play Воспроизведение - + Loop Повтор - + Next Frame Следующий кадр - + Previous Frame Предыдущий кадр - + Extend Frame Продлить кадр - + Add Frame Добавить кадр - + Duplicate Frame Дублировать кадр - + Remove Frame Удалить кадр - + Move Перемещение - + Select Выделение - + Brush Кисть - + Polyline Ломаная - + Smudge Коррекция - + Pen Перо - + Hand Рука - + Pencil Карандаш - + Bucket Заливка - + Eyedropper Пипетка - + Eraser Ластик - + New Bitmap Layer Новый растровый слой - + New Vector Layer Новый векторный слой - + New Sound Layer Новый звуковой слой - + New Camera Layer Новый слой камеры - + Delete Current Layer Удалить текущий слой - + About О программе - - + + Reset to default Вернуть настройки по умолчанию - + MultiLayer Onion Skin - + Range Диапазон - + Pencil2D Website Сайт Pencil2D - + Report a Bug Сообщить о проблеме - - + + Quick Reference Guide + + + + + F1 + + + + + Next KeyFrame Следующий ключевой кадр - - + + Previous KeyFrame Предыдущий ключевой кадр - + Timeline Временная шкала - + Options Параметры - + Color Wheel Цветовой круг - + Color Palette Палитра - + Display Options Настройки отображения - + Flip X Отразить по оси X - + Flip Y Отразить по оси Y - + Move Frame Forward Переместить кадр вперед - + Move Frame Backward Переместить кадр назад @@ -1496,12 +1506,12 @@ Закрепить окна - + Open Recent Последние документы - + You have successfully cleared the list @@ -1510,87 +1520,87 @@ Вы успешно очистили список - - - - + + + + Warning Предупреждение - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil не удалось открыть данный файл. >br<Подсказка: для изображений воспользуйтесь командой Файл -> Импорт - + Opening document... Открытие документа... - - - + + + Abort Отмена - + Saving document... Сохранение документа... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: - + This animation has been modified. Do you want to save your changes? Эта анимация была изменена. Вы хотите сохранить свои изменения? - + The animation is not saved yet. Do you want to save now? Анимация еще не сохранена. Вы хотите сохранить ее сейчас? - + Never ask again AutoSave reminder button Больше не спрашивать - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. - + Importing image sequence... - - + + Undo Menu item text - + Redo Menu item text - + Stop Стоп @@ -1932,32 +1942,32 @@ Изображения (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - + Everything ok. Все в порядке. - + Ooops, Something went wrong. Ой, что-то пошло не так. - + File doesn't exist. Файл не существует. - + Cannot open file. Невозможно открыть файл. - + The file is not a valid xml document. Файл не является допустимым XML-документом. - + The file is not valid pencil document. Файл не является допустимым документом Pencil. @@ -3581,12 +3591,12 @@ TimeLineCells - + Layer Properties Свойства слоя - + Layer name: Имя слоя: diff --git a/translations/pencil_sl.ts b/translations/pencil_sl.ts index 9a017ab62..90a1abeef 100644 --- a/translations/pencil_sl.ts +++ b/translations/pencil_sl.ts @@ -28,118 +28,118 @@ ActionCommands - + No sound layer exists as a destination for your import. Create a new sound layer? Ni sloja z zvokom, kamor želite uvoziti vaš izbor. Želite ustvariti nov zvočni sloj? - + Create sound layer Ustvari Zvočni sloj - + Don't create layer Ne ustvari sloja - + Layer Properties Dialog title on creating a sound layer Lastnosti sloja - + Sound Layer Default name on creating a sound layer Zvočni sloj - + Exporting movie Izvažanje posnetka - + Finished. Open movie now? When movie export done. Dokončano. Predvajaj posnetek? - - - - - Layer Properties - Lastnosti sloja - - - + Layer Properties + Lastnosti sloja + + + + + + + Layer name: Ime sloja: - + A sound clip already exists on this frame! Please select another frame or layer. V temu razdelku že obstaja zvočni posnetek! Prosim izberite drug razdelek ali sloj. - + Exporting image sequence... Izvažanje animacije sličic... - + Abort Prekini - + Warning Opozorilo - + Unable to export image. Slike ni mogoče izvoziti. - + Bitmap Layer Bitni sloj - + Vector Layer Vektorski sloj - + Camera Layer Sloj kamere - + Sound Layer Zvočni sloj - + Delete Layer Windows title of Delete current layer pop-up. Izbriši sloj - + Are you sure you want to delete layer: Res želite izbrisati sloj: - + Please keep at least one camera layer in project text when failed to delete camera layer Prosim ohranite vsaj en sloj s kamero v projektu @@ -446,19 +446,19 @@ Editor - - + + Paste Prilepi - + Remove frame Odstrani razdelek - - + + Import Image Uvozi sliko @@ -1076,7 +1076,7 @@ - + Tools Orodja @@ -1087,401 +1087,411 @@ - + Help Pomoč - + Windows Okna - + New Nov - + Open Odpri - + Save Shrani - + Save As .. Shrani kot... - + Exit Izhod - - + + Image Sequence... Zaporedje sličic... - - + + Image... Slika... - - + + Movie... Posnetek... - - + + Palette... Paleta... - + Sound... Zvok... - + Undo Korak nazaj - + Redo Korak naprej - + Cut Izreži - + Copy Kopiraj - + Paste Prilepi - + Crop Obreži - + Crop To Selection Obreži do izbora - + Select All Izberi vse - + Deselect All Razveljavi izbor - - + + Clear Frame Počisti razdelek - + Preferences Nastavitve - + Reset Windows Ponastavi okna - + Zoom In Približaj - + Zoom Out Oddalji - + Rotate Clockwise Zavrti desno - + Rotate AntiClosewise Zavrti levo - + Reset Zoom/Rotate Ponastavi Povečavo/Vrtenje - + Horizontal Flip Prezrcali horizontalno - + Vertical Flip Prezrcali vertikalno - + Preview Predogled - + Grid Mreža - + Previous Prejšnji - + Show previous onion skin Pokaži prejšnjo prosojnico - + Next Naslednji - + Show next onion skin Pokaži naslednjo prosojnico - - + + Play Predvajaj - + Loop Ponavljanje - + Next Frame Naslednji razdelek - + Previous Frame Prejšnji razdelek - + Extend Frame Razširi razdelek - + Add Frame Dodaj razdelek - + Duplicate Frame Podvoji razdelek - + Remove Frame Odstrani razdelek - + Move Premakni - + Select Izbor - + Brush Čopič - + Polyline Večsegmentna črta - + Smudge Zamaži - + Pen Penkalo - + Hand Roka - + Pencil Svinčnik - + Bucket Vedro - + Eyedropper Kapalka - + Eraser Radirka - + New Bitmap Layer Novi bitni sloj - + New Vector Layer Novi vektorski sloj - + New Sound Layer Novi zvočni sloj - + New Camera Layer Novi sloj kamere - + Delete Current Layer Ibriši trenutni sloj - + About O programu - - + + Reset to default Ponastavi na osnovne nastavitve - + MultiLayer Onion Skin Večslojna prosojnica - + Range Razpon - + Pencil2D Website Internetna stran Svinčnik2D - + Report a Bug Sporoči napako - - + + Quick Reference Guide + + + + + F1 + + + + + Next KeyFrame Naslednji ključni razdelek - - + + Previous KeyFrame Prejšnji ključni razdelek - + Timeline Časovnica - + Options Možnosti - + Color Wheel Barvno kolo - + Color Palette Paleta barv - + Display Options Možnosti prikaza - + Flip X Zrcali X - + Flip Y Zrcali Y - + Move Frame Forward Premakni razdelek naprej - + Move Frame Backward Premakni razdelek nazaj @@ -1496,12 +1506,12 @@ Zakleni okna - + Open Recent Odpri nedavne - + You have successfully cleared the list @@ -1510,86 +1520,86 @@ Uspešno ste izbpraznili seznam - - - - + + + + Warning Opozorilo - - + + Pencil cannot read this file. If you want to import images, use the command import. Svinčnik ne more prebrati te datoteke. Če želite uvoziti slike uporabite ukaz za uvoz. - + Opening document... Odpiranje dokumenta... - - - + + + Abort Prekini - + Saving document... Shranjevanje dokumenta... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>Pojavila se je napaka in vaša datoteka morda ni pravilno shranjena. Če sumite, da napaka kaže na problem s Svinčnikom2D kreirajtenovo poročilo na:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Prosimo, da v svoje poročilo vključite naslednje podatke: - + This animation has been modified. Do you want to save your changes? Ta animacija je bila spremenjena. Želite shraniti spremembe? - + The animation is not saved yet. Do you want to save now? Animacija še ni shranjena. Želite shraniti sedaj? - + Never ask again AutoSave reminder button Ne sprašuj več - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Ni mogoče uvoziti slike.<br><b>Namig:</b>Uporabite bitni sloj za uvoz bitnih slik. - + Importing image sequence... Uvažanje zaporedja sličic... - - + + Undo Menu item text Korak nazaj - + Redo Menu item text Korak naprej - + Stop Stop @@ -1931,32 +1941,32 @@ Uspešno ste izbpraznili seznam Slike (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - + Everything ok. Vse v redu. - + Ooops, Something went wrong. Jejhata na, nekaj se je zalomilo. - + File doesn't exist. Datoteka ne obstaja. - + Cannot open file. Ne morem odpreti datoteke - + The file is not a valid xml document. Datoteka ni veljaven xml dokument. - + The file is not valid pencil document. Datoteka ni veljaven svinčnikov dokument. @@ -3580,12 +3590,12 @@ Uspešno ste izbpraznili seznam TimeLineCells - + Layer Properties Lastnosti sloja - + Layer name: Ime sloja: diff --git a/translations/pencil_vi.ts b/translations/pencil_vi.ts index 45f4b9ebb..454696b6a 100644 --- a/translations/pencil_vi.ts +++ b/translations/pencil_vi.ts @@ -28,118 +28,118 @@ ActionCommands - + No sound layer exists as a destination for your import. Create a new sound layer? Không tìm thấy Layer âm thanh khi bạn Đưa vào. Bạn có muốn tạo một Layer âm thanh mới không? - + Create sound layer Tạo một Layer âm thanh mới - + Don't create layer Không tạo Layer - + Layer Properties Dialog title on creating a sound layer - + Sound Layer Default name on creating a sound layer - + Exporting movie - + Finished. Open movie now? When movie export done. - - - - - Layer Properties - Thuộc tính của Layer - - - + Layer Properties + Thuộc tính của Layer + + + + + + + Layer name: Tên Layer - + A sound clip already exists on this frame! Please select another frame or layer. Clip âm thanh này Đã có sẵn trên frame! Hãy chọn một frame khác hay một Layer khác - + Exporting image sequence... Đang xuất hình ảnh trong clip... - + Abort Từ chối yêu cầu - + Warning Cảnh báo - + Unable to export image. Không thể xuất Được hình ảnh - + Bitmap Layer Bitmap Layer - + Vector Layer Vector Layer - + Camera Layer Layer của máy quay - + Sound Layer Layer âm thanh - + Delete Layer Windows title of Delete current layer pop-up. - + Are you sure you want to delete layer: - + Please keep at least one camera layer in project text when failed to delete camera layer @@ -446,19 +446,19 @@ Editor - - + + Paste Dán - + Remove frame - - + + Import Image Nhập vào hình ảnh @@ -1076,7 +1076,7 @@ - + Tools Công cụ @@ -1087,401 +1087,411 @@ - + Help Trợ giúp - + Windows Cửa sổ - + New Tạo Mới - + Open Mở ra - + Save Lưu lại - + Save As .. Lưu ở nơi khác - + Exit Thoát - - + + Image Sequence... Hàng chờ hình ảnh - - + + Image... Hình ảnh... - - + + Movie... Video... - - + + Palette... Bảng màu... - + Sound... Âm thanh... - + Undo Quay lại bước trước Đó - + Redo Thực hiện tiếp - + Cut Cắt - + Copy Sao chép - + Paste Dán - + Crop Gọt hình ảnh - + Crop To Selection Gọt hình ảnh theo vùng chọn - + Select All Chọn tất cả - + Deselect All Bỏ chọn tất cả - - + + Clear Frame Làm sạch Frame - + Preferences Cài Đặt chung - + Reset Windows Khởi Động lại - + Zoom In Phóng to - + Zoom Out Thu nhỏ - + Rotate Clockwise Xoay theo chiều kim Đồng hồ - + Rotate AntiClosewise Xoay ngược chiều kim Đồng hồ - + Reset Zoom/Rotate Đưa về mặc Định Phóng to/Xoay góc - + Horizontal Flip Lật theo chiều ngang - + Vertical Flip Lật theo chiều dọc - + Preview Xem trước - + Grid Lưới - + Previous Trước Đó - + Show previous onion skin HIển thị Onion Skin trước Đó - + Next Kế tiếp - + Show next onion skin Hiển thị Onion skin kế tiếp - - + + Play Chạy - + Loop Lập lại - + Next Frame Frame kế tiếp - + Previous Frame Frame trước Đó - + Extend Frame Frame mở rộng - + Add Frame Thêm Frame vào - + Duplicate Frame Sao chép frame - + Remove Frame Gỡ bỏ frame - + Move Di chuyển - + Select Chọn - + Brush Cọ vẽ - + Polyline Polyline - + Smudge Làm mờ - + Pen Viết mực - + Hand Bàn tay - + Pencil Bút chì - + Bucket Xô màu - + Eyedropper Chọn màu - + Eraser Tẩy xóa - + New Bitmap Layer Layer Bitmap mới - + New Vector Layer Layer Vector mới - + New Sound Layer Layer âm thanh mới - + New Camera Layer Layer máy quay mới - + Delete Current Layer Xóa layer hiện hành - + About Giới thiệu - - + + Reset to default Đưa về mặc Định - + MultiLayer Onion Skin Onion skin Đa layer - + Range Khoảng vùng - + Pencil2D Website - + Report a Bug - - + + Quick Reference Guide + + + + + F1 + + + + + Next KeyFrame Key Frame tiếp theo - - + + Previous KeyFrame Key frame trước Đó - + Timeline Dòng thời gian - + Options Các lựa chọn - + Color Wheel Bánh xe màu - + Color Palette Bảng màu - + Display Options Lựa chọn hiển thị - + Flip X Lật theo trục X - + Flip Y Lật theo trục Y - + Move Frame Forward Di chuyển Frame tới trước - + Move Frame Backward Di chuyển Frame về sau @@ -1496,12 +1506,12 @@ Khóa cửa sổ hiển thị - + Open Recent Mở file gần Đây - + You have successfully cleared the list @@ -1510,86 +1520,86 @@ Bạn Đã xóa thành công danh sách - - - - + + + + Warning Cảnh báo - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil không thể mở file này. Nếu như bạn muốn nhập vào hình ảnh, hãy sử dụng chức nhăn "Nhập vào" - + Opening document... Đang mở file... - - - + + + Abort Từ chối - + Saving document... Đang lưu file... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>Có lỗi phát sinh và file của bạn không thể lưu lại. Nếu bạn cho rằng Đây là lỗi thuộc về Pencil2D, hãy thông báo cho chúng tôi biết tại<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Hãy chắc rằng bạn Đã gửi những chi tiết lỗi sau Đây cho chúng tôi: - + This animation has been modified. Do you want to save your changes? File hoạt hình Đã Được thay Đổi Bạn có chắc rằng muốn lưu lại những thay Đổi này? - + The animation is not saved yet. Do you want to save now? File này chưa Được lưu. Bạn có muốn lưu ngay không? - + Never ask again AutoSave reminder button Đừng hỏi lại - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Không thể nhập vào hình ảnh.<br><b>Cách giải quyết:</b>Hãy sử dụng Layer Bitmap Để nhập vào ảnh Bitmaps. - + Importing image sequence... - - + + Undo Menu item text - + Redo Menu item text - + Stop Ngừng ngay @@ -1931,32 +1941,32 @@ Bạn có muốn lưu ngay không? Images - Hình ảnh (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - + Everything ok. Mọi thứ Đã sẵn sàng - + Ooops, Something went wrong. Ooops, Đã có lỗi phát sinh - + File doesn't exist. File không tồn tại - + Cannot open file. Không thể mở file này - + The file is not a valid xml document. File này không có Định dạng chuẩn của tài liệu XML - + The file is not valid pencil document. File này không phải là file Định dạng chuẩn của Pencil2D @@ -3580,12 +3590,12 @@ Bạn có muốn lưu ngay không? TimeLineCells - + Layer Properties - + Layer name: diff --git a/translations/pencil_zh_TW.ts b/translations/pencil_zh_TW.ts index d4585c1f8..13a367984 100644 --- a/translations/pencil_zh_TW.ts +++ b/translations/pencil_zh_TW.ts @@ -28,118 +28,118 @@ ActionCommands - + No sound layer exists as a destination for your import. Create a new sound layer? 目前沒有音效層可供匯入音效,要創建新的音效層嗎? - + Create sound layer 建立音效層 - + Don't create layer 不建立圖層 - + Layer Properties Dialog title on creating a sound layer 圖層屬性 - + Sound Layer Default name on creating a sound layer 音效層 - + Exporting movie 正在輸出影片 - + Finished. Open movie now? When movie export done. 輸出完成。要打開影片嗎? - - - - - Layer Properties - 圖層屬性 - - - + Layer Properties + 圖層屬性 + + + + + + + Layer name: 圖層名稱: - + A sound clip already exists on this frame! Please select another frame or layer. 目前畫格已經有一個音效了! 請選擇另一個畫格或圖層 - + Exporting image sequence... 輸出連續圖片中... - + Abort 關於 - + Warning 警告 - + Unable to export image. 無法匯出圖片 - + Bitmap Layer 點陣圖層 - + Vector Layer 向量圖層 - + Camera Layer 相機層 - + Sound Layer 音效層 - + Delete Layer Windows title of Delete current layer pop-up. 刪除圖層 - + Are you sure you want to delete layer: 確定要刪除圖層嗎 - + Please keep at least one camera layer in project text when failed to delete camera layer 請至少保留一個相機層 @@ -446,19 +446,19 @@ Editor - - + + Paste 貼上 - + Remove frame 刪除關鍵格 - - + + Import Image 匯入圖像 @@ -1076,7 +1076,7 @@ - + Tools 工具 @@ -1087,401 +1087,411 @@ - + Help 幫助 - + Windows 視窗 - + New 新增 - + Open 開啟 - + Save 儲存 - + Save As .. 另存為.. - + Exit 離開 - - + + Image Sequence... 連續圖像... - - + + Image... 圖像... - - + + Movie... 影片... - - + + Palette... 調色盤... - + Sound... 音效... - + Undo 復原 - + Redo 重做 - + Cut 剪下 - + Copy 複製 - + Paste 貼上 - + Crop 裁剪 - + Crop To Selection 裁剪至選擇區域 - + Select All 全選 - + Deselect All 取消全選 - - + + Clear Frame 清除畫格 - + Preferences 偏好設定 - + Reset Windows 重設視窗 - + Zoom In 放大 - + Zoom Out 縮小 - + Rotate Clockwise 順時針旋轉 - + Rotate AntiClosewise 逆時針旋轉 - + Reset Zoom/Rotate 重設縮放/旋轉 - + Horizontal Flip 水平翻轉 - + Vertical Flip 垂直翻轉 - + Preview 預覽 - + Grid 格線 - + Previous 前一個 - + Show previous onion skin 顯示先前描圖紙 - + Next 下一個 - + Show next onion skin 顯示後續描圖紙 - - + + Play 播放 - + Loop 循環 - + Next Frame 下一個畫格 - + Previous Frame 前一個畫格 - + Extend Frame 延伸畫格 - + Add Frame 加入畫格 - + Duplicate Frame 重製畫格 - + Remove Frame 移除畫格 - + Move 移動 - + Select 選擇 - + Brush 筆刷 - + Polyline 折線 - + Smudge 塗抹 - + Pen 鋼筆 - + Hand - + Pencil 鉛筆 - + Bucket 顏料桶 - + Eyedropper 取色器 - + Eraser 橡皮擦 - + New Bitmap Layer 新增點陣圖層 - + New Vector Layer 新增向量圖層 - + New Sound Layer 新增音效層 - + New Camera Layer 新增攝影機層 - + Delete Current Layer 刪除目前圖層 - + About 關於 - - + + Reset to default 重設為預設值 - + MultiLayer Onion Skin 多重圖層描圖紙 - + Range 範圍 - + Pencil2D Website Pencil2D 網站 - + Report a Bug 回報 BUG - - + + Quick Reference Guide + + + + + F1 + + + + + Next KeyFrame 下一個關鍵影格 - - + + Previous KeyFrame 前一個關鍵影格 - + Timeline 時間軸 - + Options 選項 - + Color Wheel 色輪 - + Color Palette 顏色調色盤 - + Display Options 顯示選項 - + Flip X X翻轉 - + Flip Y Y翻轉 - + Move Frame Forward 影格前移 - + Move Frame Backward 影格後移 @@ -1496,96 +1506,96 @@ 鎖定視窗 - + Open Recent 最近開啟的 - + You have successfully cleared the list 成功清除清單 - - - - + + + + Warning 警告 - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil 無法讀取這個檔案。如果您想要匯入影像,請使用指令匯入。 - + Opening document... 開啟文件... - - - + + + Abort 中止 - + Saving document... 儲存文件... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>發現錯誤,你的檔案可能並未成功保存。如果你看見這個訊息,請到<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a>協助回報錯誤<br>並附上以下錯誤細節訊息: - + This animation has been modified. Do you want to save your changes? 動畫已經修改。你想要儲存檔案嗎? - + The animation is not saved yet. Do you want to save now? 您的動畫還沒儲存。要現在儲存嗎? - + Never ask again AutoSave reminder button 不要再問我 - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. 無法匯入圖片。<br><b>提示</b> 使用點陣圖層來匯入點陣圖 - + Importing image sequence... - - + + Undo Menu item text - + Redo Menu item text - + Stop 停止 @@ -1927,32 +1937,32 @@ - + Everything ok. 正常 - + Ooops, Something went wrong. 歐,好像出錯了! - + File doesn't exist. 檔案不存在 - + Cannot open file. 無法開啟檔案 - + The file is not a valid xml document. 無效的 XML 檔案 - + The file is not valid pencil document. 無效的 Pencil 檔案格式 @@ -3576,12 +3586,12 @@ TimeLineCells - + Layer Properties 圖層屬性 - + Layer name: 圖層名稱: From 5ba80c0b489990ff61c324a7408dc37ba87127a9 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Fri, 27 Apr 2018 13:09:56 +1000 Subject: [PATCH 025/184] lupdate --- translations/pencil.ts | 746 ++++++++++++++++++++++------------------- 1 file changed, 396 insertions(+), 350 deletions(-) diff --git a/translations/pencil.ts b/translations/pencil.ts index d685b3dbe..e4fb7d5dc 100644 --- a/translations/pencil.ts +++ b/translations/pencil.ts @@ -150,57 +150,57 @@ BaseTool - + Pencil - + Eraser - + Select - + Move - + Hand - + Smudge - + Pen - + Polyline - + Bucket - + Eyedropper - + Brush @@ -362,8 +362,8 @@ ColorPaletteWidget - - + + Colour name @@ -1280,7 +1280,7 @@ - + Play @@ -1498,106 +1498,112 @@ - + color palette:<br>use <b>(C)</b><br>toggle at cursor - + Lock Windows - + Open Recent - + You have successfully cleared the list - - - - + + + + + Warning - - + + Pencil cannot read this file. If you want to import images, use the command import. - + Opening document... - - - + + + Abort - + Saving document... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: - + This animation has been modified. Do you want to save your changes? - + The animation is not saved yet. Do you want to save now? - + Never ask again AutoSave reminder button - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. - + Importing image sequence... - - + + was unable to import + + + + + Undo Menu item text - + Redo Menu item text - + Stop @@ -1605,122 +1611,122 @@ Object - + Black - + Red - + Dark Red - + Orange - + Dark Orange - + Yellow - + Dark Yellow - + Green - + Dark Green - + Cyan - + Dark Cyan - + Blue - + Dark Blue - + White - + Very Light Grey - + Light Grey - + Grey - + Dark Grey - + Light Skin - + Light Skin - shade - + Skin - + Skin - shade - + Dark Skin - + Dark Skin - shade @@ -1855,26 +1861,26 @@ - + Warning: Transparency is not currently supported in movie files Command line warning - + Exporting movie... Command line task progress - - + + Done. Command line task done - + Exporting image sequence... Command line task progress @@ -1935,7 +1941,7 @@ - Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) + Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) @@ -1979,1337 +1985,1337 @@ - + Vivid Pink - + Strong Pink - + Deep Pink - + Light Pink - + Moderate Pink - + Dark Pink - + Pale Pink - + Grayish Pink - + Pinkish White - + Pinkish Gray - + Vivid Red - + Strong Red - + Deep Red - + Very Deep Red - + Moderate Red - + Dark Red - + Very Dark Red - + Light Grayish Red - + Grayish Red - + Dark Grayish Red - + Blackish Red - + Reddish Gray - + Dark Reddish Gray - + Reddish Black - + Vivid Yellowish Pink - + Strong Yellowish Pink - + Deep Yellowish Pink - + Light Yellowish Pink - + Moderate Yellowish Pink - + Dark Yellowish Pink - + Pale Yellowish Pink - + Grayish Yellowish Pink - + Brownish Pink - + Vivid Reddish Orange - + Strong Reddish Orange - + Deep Reddish Orange - + Moderate Reddish Orange - + Dark Reddish Orange - + Grayish Reddish Orange - + Strong Reddish Brown - + Deep Reddish Brown - + Light Reddish Brown - + Moderate Reddish Brown - + Dark Reddish Brown - + Light Grayish Reddish Brown - + Grayish Reddish Brown - + Dark Grayish Reddish Brown - + Vivid Orange - + Brilliant Orange - + Strong Orange - + Deep Orange - + Light Orange - + Moderate Orange - + Brownish Orange - + Strong Brown - + Deep Brown - + Light Brown - + Moderate Brown - + Dark Brown - + Light Grayish Brown - + Grayish Brown - + Dark Grayish Brown - + Light Brownish Gray - + Brownish Gray - + Brownish Black - + Vivid Orange Yellow - + Brilliant Orange Yellow - + Strong Orange Yellow - + Deep Orange Yellow - + Light Orange Yellow - + Moderate Orange Yellow - + Dark Orange Yellow - + Pale Orange Yellow - + Strong Yellowish Brown - + Deep Yellowish Brown - + Light Yellowish Brown - + Moderate Yellowish Brown - + Dark Yellowish Brown - + Light Grayish Yellowish Brown - + Grayish Yellowish Brown - + Dark Grayish Yellowish Brown - + Vivid Yellow - + Brilliant Yellow - + Strong Yellow - + Deep Yellow - + Light Yellow - + Moderate Yellow - + Dark Yellow - + Pale Yellow - + Grayish Yellow - + Dark Grayish Yellow - + Yellowish White - + Yellowish Gray - + Light Olive Brown - + Moderate Olive Brown - + Dark Olive Brown - + Vivid Greenish Yellow - + Brilliant Greenish Yellow - + Strong Greenish Yellow - + Deep Greenish Yellow - + Light Greenish Yellow - + Moderate Greenish Yellow - + Dark Greenish Yellow - + Pale Greenish Yellow - + Grayish Greenish Yellow - + Light Olive - + Moderate Olive - + Dark Olive - + Light Grayish Olive - + Grayish Olive - + Dark Grayish Olive - + Light Olive Gray - + Olive Gray - + Olive Black - + Vivid Yellow Green - + Brilliant Yellow Green - + Strong Yellow Green - + Deep Yellow Green - + Light Yellow Green - + Moderate Yellow Green - + Pale Yellow Green - + Grayish Yellow Green - + Strong Olive Green - + Deep Olive Green - + Moderate Olive Green - + Dark Olive Green - + Grayish Olive Green - + Dark Grayish Olive Green - + Vivid Yellowish Green - + Brilliant Yellowish Green - + Strong Yellowish Green - + Deep Yellowish Green - + Very Deep Yellowish Green - + Very Light Yellowish Green - + Light Yellowish Green - + Moderate Yellowish Green - + Dark Yellowish Green - + Very Dark Yellowish Green - + Vivid Green - + Brilliant Green - + Strong Green - + Deep Green - + Very Light Green - + Light Green - + Moderate Green - + Dark Green - + Very Dark Green - + Very Pale Green - + Pale Green - + Grayish Green - + Dark Grayish Green - + Blackish Green - + Greenish White - + Light Greenish Gray - + Greenish Gray - + Dark Greenish Gray - + Greenish Black - + Vivid Bluish Green - + Brilliant Bluish Green - + Strong Bluish Green - + Deep Bluish Green - + Very Light Bluish Green - + Light Bluish Green - + Moderate Bluish Green - + Dark Bluish Green - + Very Dark Bluish Green - + Vivid Greenish Blue - + Brilliant Greenish Blue - + Strong Greenish Blue - + Deep Greenish Blue - + Very Light Greenish Blue - + Light Greenish Blue - + Moderate Greenish Blue - + Dark Greenish Blue - + Very Dark Greenish Blue - + Vivid Blue - + Brilliant Blue - + Strong Blue - + Deep Blue - + Very Light Blue - + Light Blue - + Moderate Blue - + Dark Blue - + Very Pale Blue - + Pale Blue - + Grayish Blue - + Dark Grayish Blue - + Blackish Blue - + Bluish White - + Light Bluish Gray - + Bluish Gray - + Dark Bluish Gray - + Bluish Black - + Vivid Purplish Blue - + Brilliant Purplish Blue - + Strong Purplish Blue - + Deep Purplish Blue - + Very Light Purplish Blue - + Light Purplish Blue - + Moderate Purplish Blue - + Dark Purplish Blue - + Very Pale Purplish Blue - + Pale Purplish Blue - + Grayish Purplish Blue - + Vivid Violet - + Brilliant Violet - + Strong Violet - + Deep Violet - + Very Light Violet - + Light Violet - + Moderate Violet - + Dark Violet - + Very Pale Violet - + Pale Violet - + Grayish Violet - + Vivid Purple - + Brilliant Purple - + Strong Purple - + Deep Purple - + Very Deep Purple - + Very Light Purple - + Light Purple - + Moderate Purple - + Dark Purple - + Very Dark Purple - + Very Pale Purple - + Pale Purple - + Grayish Purple - + Dark Grayish Purple - + Blackish Purple - + Purplish White - + Light Purplish Gray - + Purplish Gray - + Dark Purplish Gray - + Purplish Black - + Vivid Reddish Purple - + Strong Reddish Purple - + Deep Reddish Purple - + Very Deep Reddish Purple - + Light Reddish Purple - + Moderate Reddish Purple - + Dark Reddish Purple - + Very Dark Reddish Purple - + Pale Reddish Purple - + Grayish Reddish Purple - + Brilliant Purplish Pink - + Strong Purplish Pink - + Deep Purplish Pink - + Light Purplish Pink - + Moderate Purplish Pink - + Dark Purplish Pink - + Pale Purplish Pink - + Grayish Purplish Pink - + Vivid Purplish Red - + Strong Purplish Red - + Deep Purplish Red - + Very Deep Purplish Red - + Moderate Purplish Red - + Dark Purplish Red - + Very Dark Purplish Red - + Light Grayish Purplish Red - + Grayish Purplish Red - + White - + Light Gray - + Medium Gray - + Dark Gray - + Black @@ -3330,60 +3336,60 @@ ScribbleArea - + Warning - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). - + Delete Selection Undo Step: clear the selection area. - - + + Clear Image Undo step text - + There is a gap in your drawing (or maybe you have zoomed too much). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). - + Out of bound. - + Could not find a closed path. - + Could not find the root index. - + %1<br><br>Error: %2 - + Flood fill error @@ -3588,12 +3594,12 @@ TimeLineCells - + Layer Properties - + Layer name: @@ -3630,6 +3636,46 @@ Preferences + + + Drawing + + + + + When drawing on an empty frame: + + + + + Create a new (blank) key-frame and start drawing on it. + + + + + Create a new (blank) key-frame + + + + + Duplicate the previous key-frame and start drawing on the duplicate. + + + + + Duplicate the previous key-frame + + + + + Keep drawing on the previous key-frame + + + + + <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + Frame size From 340d2e816beca3ae9d436ea47bd1f87e6f586288 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Fri, 27 Apr 2018 13:10:17 +1000 Subject: [PATCH 026/184] lrelease --- translations/pencil_es.qm | Bin 76087 -> 76240 bytes translations/pencil_fr.qm | Bin 74631 -> 75314 bytes translations/pencil_pt.qm | Bin 76143 -> 76302 bytes translations/pencil_pt_BR.qm | Bin 75711 -> 75868 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/translations/pencil_es.qm b/translations/pencil_es.qm index 52f316da3398db94f6aeeced5041d210cac9a63f..ec585e3a1d6314d9c22048223843e9701b27e7d2 100644 GIT binary patch delta 5706 zcmX|FcU%Qi`Y;U6|qIcU}Iy!5+WAF-b)lg zv4B`&N5QTjc2QJfhbUr~e9yYS&+iXC%-c8b-Fx1>=iWD2dBW9vVX;G##(=N{2yP2B zQ2=LW87wPc}F&5aQL zn!;CBLP!}x%!QC12aL*raG(<~r`?h>)h)vz+*k;_i2jZ$-D3#PxVGI~8+IQ}JO@Pe zAie`yy|H2UrVw7y-tNmGHs|6V|JX3(g$-ZVgV^~D*Gacw&v1y{_)MroImd=wJAOx%*b@N_W&uUR5oqM^Evq4L zI8SZtS_G+21G9P~IDvds-ekk5I_PnY&rcd5r{DnT)wy4EmSrj{Vt&57%SRmmNTT_wT5Z3J~6>kA)$-#`*{FZ#E)bNZ^t!7;W|R zm4LDHeYnw27$=S6_%}>G>If|DgJ~-TsMJ?6yGc1PZv*1B&wwf_#Mf#|gLY#_BQK!! zWu*0|r}z6{uRqs)HX2!fO=OxR;;$K;)EYJNRe>;S_ZIV z6mBStfGl?ut=r0wDN1q`oGc4ecB`sEg$z~Y^n-xsOjRdME1;r|Dqu@6@U*FF=(G}G z|8J^@ck6+Xo~o#ai9n01swtyB0DnAE&D`072hdlQlt=UOD^#m$Z{~sf+OR{iYVD|| z%!o)Ez8#|4@^UxOt3YDE_dRGp!A=vM$V_@s9KmI6#3t8R366_DYz4mL_hVUVjtjCD|Jlk3&80y>bNRoIVo2?t6>ZfbWpwMTx-TxNA)`A2#yaE zf3V!MSEmcbz+gqa&l+^4P1RX$*MT2*sg~oK_#TzWie) z^~qD^z#vx}mi?_h>p^a+Tvz86k%K0=>cWA8>C_8#;W;(%POmP!xeb`_t$t|b=I<}+ zBED~dTcNrry8uX2)J6Xt0gm=kKa%+3p?}rIF0}s84t3dz0YL6Lb$RqlAa$O){Qg>~ zOr`42M?HYU|7a>ra0jZL*Hjrn@!X%QsZ~}V_%BN1ek&fB@L5xPDL2g9s`1FJ3Vf@l zsT<8KPK?(y{4bh8{o1Qgg@AsY4aX;HIxKf%dd|>vYsZD$ z#%qQ)CnNWhH4$TJ;Pjt0W31ypmT96xx#9bcnpi7C4bn8zz9s_KLNznyDqJ^C6K7?% zVMomz2Qs%VTQm2g{v|Mk~B$2NaTS}bbjbqt-Pi1j?Mc0PqS^I@OgcZ-WR;!)#=XRQmoC_7CYJGr5Z3XSFOzPqxL04-T&njMUET`p%LIkJz z_kch*usaI1F02Q34ir3+{s5YL3k|w3KnLCz+Imz1jDA9gom?;Up3w1C zN9IqK;4cSo{EQ9D`wK1le2dC zw)Pelnop6Lm?RHfXG@~9aAG;_+vX$WB#a|Y7jhRchV5$DFvv}~98f_2stH#n)1RPO z!j+p1fD4a>e04uo>E%R*Oz=O#jifn@0B7OWiDQ(b0m7|p3U{jn;cg1$%h*`BmlVh6 zxvYp}l#bqF~*)$3aoM z=`RYhi&)K$8?2uyx-IJjmA;!;>sC3RFN*H62t?i%>nyDdl`2E5_caM9&l7)i?88jn zE;hLL1S;82^n8^Fc)N?utCur&S6mmHH{gpK_K2NFk%?xr#h?j~dDKV60pU@=!;a!8 zYlRr&D~{><6|fg<*e_n3G4Uxkb{6NpaG(T<;@pZSz~%t)&sNMs=66Kghl(negjpPo(g6*u~OFgrVlTMu(%`%N|+ z`j5D+bqPz%T`{#DsqXnkOkM8Jc}K;xXuiKOMNEt3!mC`x-I1L4piJDo*9kb&T-=xL zPs0|8`;IWyM?bRRnl9pgOCTveQb){azMeQ$JTagapxYtl9a+Vs_(RNlxQ*CCy#KK` z@Jl5d7OfVGyE6t--NoW3Jpk?RHY_a?Ka`TWuWQ85A(WwuC&e!pI}szrugyl%@F+Mv2 z%xp=4{8MsjOvCCdmz**)87f976^Lg)QsYVzbdA~xc_jned*x9f{cd6cM zAL?6c$y2Tm{9K+CVXSW1Ao(@msC^R~_8%v;>rAuLKT2IL(yBghq^@f&GcuP-0d-CR zj&-HLgPF{Q5=G$92}waB0Y|by>a-&P4|vtT(y>FG|8c2lt`9QG-uN?X|5;3V9!x0Nk16CGHG==C2n?QX=}~dz!ZCF zpEX{Szew4Wce8bLkj@v=oZLRrMMsj>Mv<<}CH4xGuC2Mvc>g3_E7by)g`=cAYy)m= zmkP78sU%~ihn1!QIl0m!-}VfbN;YhNTq-_B0~R_qEb@O16cGCWN zg)Kw>m)d2&)Fv}6w9B>Z%|29Ux1S;dmv!1ysXwcjuXgX=Mr3BXc7F&Ny*x~N;94_E z#Dr+=k*RT{^1k+BnLj0?l{SB1FW~od?agC+-e9jS`p@d|SsT7Nt$ozZK(Sw?Ej}@h z@o1-gvERznARBg2Y0K?K@`PIIq!$og&*NeGMWIbI$oeLx~Sy%8fj{Ei2753+Ntu?yhgWf=go4Oa?Pg!Lwy8kXE zk`S*5z3%WnYTXpQL#QJgg)n{4NWM@#Mn7SO}WodX|#T2Jm+PN)UWy3j#XuuKD{?j;$?>Z{01*7(oX%; z19Zsuw*K|?1?YtZ_WIHZOn#-mzM|B+aeadrLOglJ;BaRPROV_17q9ie@)d?^l{vor zxxwA4op(!-6Mj5gKmbi?TZE3pCt)8qeH5Xn1?c$c(reY4~`F8+u+fstyp{ z>KKLAd?DMC?U(=UvMx?gx{C^s4=o}*TEGAeUx0gnrfZZ|o;w!6_&pdojg89n1p z@ZQPE%#*V{1oH%UJK~G|2I?`m1I;3U8c)3xB1(dGbLfLP#0t}rfcf2tkke%c}??mz^$-#|pu^s9s zM_dSHEm6xOCqAO|FPBFi>;x=WCjXj1PfsSx(I*qXqv9+PjY$7iX;(M8MQRyA-`C3 zH@TiKfyyq-8%>xVNRmgqs2^)<2RRP2Jo{&DJtgP}{+5 zH1kct2xJF(%G7fusa_sx>UWhJ=ER$ZjAx9boHdQ{qqgm|GfmFUW=zPY*scA5A3RLI z$H&uwaMOYwPQ1a+v*CzCHhk95wDrR$c0cV**}1;_M6t+Z$!T>An5Z{hjb)T4O)@=t zM?5B(UajSZ+Xd5`x-_hszv=zWV4nFMMKiI2hOSlwtM-g|ujmJp(teqW@k$WuXLrSM z7}vY?NvS%3^Byl$T)-nL%u!tC(-A{W#cKf9J>;M?3Oxhd{%BDe?O4NmVvN!(pFiY_ zO0%cQr0kl~Zu}vBQW&8GZcL=7hm{eB4gsIGDPygbKi5tf@56bYM=LQU!-2LgO6)Q+ z;IvVRwch3Lr73YwXvnelO2RjP-Wg6R$t!u(x@2X=3WZtlTv>6N1}?V5DeKZ|GyhYS zjSFLdb`O-41X7ycM@c#Ez{>Bgq`UI=_Q6-l>@|!X*hS@XV;?fnL&+b@0^Q78$=^>y zRo#^9`7|hHgmUjGWo!N=rSu`!yB(pt8StDJ<@QSXC#p~PY~_O$o#!iGvIaB%Z|_pR zZKtLGoi(d!>jBrMX5HE+?4g3q2CJY1zA)Fj(w;5e4>o*T$?Rpnl^5uAvsXz0FsaruFvr=EVq>^Nh#+{)(>eKIfl9Kyo9$GpOe zj(Y7gug`a5{{K3|ykR&QSa{I9@o+hN{EOz)a2j-QhB>3F$k;ew&K$)UXzXjwx>ZaA zo|}(1nnFcvY(7)Q=Zm$?InBsW%X#LjHG|2>F!Qw zB~(P_v7%>)LS;;T-+kw=@1A}3S$mD&TKg6ha_M)tjrChMBl=S!YTQ`CYHK1ltTjs} z^2j3c3?v%hN>p}oQ(r5l`KBPN*6oRWQ;F*PDLA!+*gAygAH+qc5!IWm;3V@+$IZ3f zi96kwX!)5<`Bp|e++R=h_T7KTX#9zL1KDP)6ddRZyiPPF2Utba<&%N~MdIGKBN`Y? ze8J>+sEJ_VO$D_D6&!Rq-6ewh~SrE)Y1 zOUT_WmT2M!1y_}k`>yRoa*l%TuKyv!T_+FwWkf|!$WxE^otu#7_;8}>^~g(gg=lFm zc}K!u_4X<_C5{H&#`DWVy$e%hQl!*J$KN z$engt!J-B<^5+qv);9kkBMhLi!-g4=vazNg(C{ysYyk&uYD`m1mX?Ll^ay7hbc$vO zGq66F=ACZ<%%iaF95E_4TK;D>(dve@QvHUgAww&zyAzGKr6X+}iMrmTWB#!8X&xoJ zLGJ5fNQl>B4h3Hot=#{4@ZoTzO8^Wg&$veOji zv%?IcSdOVS*&927`865Oi|4B(O(;>L#j5(g_lWGjt89KH5QV%_wSBUK=tQKdbJBPs zV;8N;Eh7zTMXEfSLGZ4hDz9#qz;xBzQfH#eCsiR`bBQuvs=^y~CyMT&TGl3n$m@)1 z!}YERXof1TaS)NUn`&<_C~oym!Pb7N1a~*0ClRV7u9RrxO4TV-YL+Lc(k<^2{c%*4 ze)tvHQ_@w{nOrFF~Z zzN&go8PU;NRrRx7#26;1ew?=@IyaK78*D?=w$1N3;5KizT`w(B^B-)-JqX00Yiy@Q&xy2g3eM!& zK3gqOvQ_K=lfNuyvST{J{AVH?G#v_too1(**8iwv=lJ2k>I^p2s?Dh zWsBM9j1xo$OW3%_;LNkX*!|Ich+6Gs6Z)qkfrqlkLkANT2e8L~!jp|(vgsAsL^Gzc zPv%TSDf@h8D|*-=Ft6C!{bOMnuVBSDj+lVK2$#;K2|fh*5)8tWK@s)lP& z4aLt~pYK|Dnb+@fcr0>b~ISM&`r#aX6 zUaqJdN6t<3z>91Jt8R1tzu@x3d@j(lFVRjLZoElA&~$EU2A=m$;AWiPf-d69Ef1>& zC**SLi%>6Jz-`fQ|XF7P$W?sGb z5XgBm-^2_D#C_r|WBL-Kxx!mNtR{-@!`p~F(d0pV%gyzOVeI)WAnswp>#!e-Ak-<+g zb&IJf{51C(qB@*{zJdJW*{`9&fn^I*_&sj6#E9qk1LtsXoxKW< z8Oa~)T8@4=m``j4R}aqR6SumddY$-VbMXD1X8f^G2;LsUpO}n&FQ)J(lFf0@asE`2 z8=8Q?pUOavPw`W5=S4on=m{5}i{n!}#sfd`mjbMbG)MS589Pu641cHSAW`xO{@J&o z7*yUXSX_rM9f%w_x|1(`HHb*PM8OJQ{%Zw1S5ue&;RE`~>&*Ym>x*0|;%hogM4v1X z7!KzRUnsCZrjEB@)D*`Mx%dm(WVq_W6hT+Bg~;NnAo@Y$%+-S7sU^|P%R;@?-b9aU zgoaByqYthV%-cb+mRkk$RIHB<5iBAd!RrHrCiC!|JWFU62t&R|LaUd{h$J%w`wSFX zeQ<_h$%2E}ny5#0bco){*ih(ckJUPVD(K%|=+zHuC(RW4=RvDsxq^G_O=RX~!J}m+ zQ3E@{^Gq7ijvK;&$`&xQOz^r4t@~e6u>8K@l^22xW`)7m#u8OD5e8QsBl_!?@b^^6 zja)4Fajs|MGd#qELDP3ar~CybiuYG}K$ck7dGJk9eY<$JClo zGzsUCYVBAxI5|SCfA30kw^l9R#{2n4)%EA2D`mT@t<2G-F5ObwEVvGeSgBUGbpWX+ z_EvZ92+cRQQ1=>BiyJ|W+Vdqoyj-UC%DssKGE+}WKsP#Ut)4zKi0DwZdhP&Q?2l5f zyM^(=KU*F1cMEu?lX|NfbK2Js_2Eo-Am6A?6#Ow}q^OgV+rl%I>J%S%H2<;s^z9Cy zh?(!y84JU4Zy2i1t8^pUdQx3DVhHB8mg)x=@EjkZF8*z@c#ndgx~fYC=s@y2)TNhZ zASA2R?@~;j8mV9(MqO<-5#vOXMhrCV>#C{y5*ahxLepRX_8UDkO~*Q;9%PNBwb7l( z(L&>tbOBu?P}AA(AEeSDjf+bJF|50$TS++*{D!8_c4)jdQ`4_0_H|pL@$OcOkOgVH zPgP_8Uz%ZM!$1XfG?U!7;F;H~*oS>H*J&c=@F=8r3WlgP>qpcFiEdVK`&-TK=p4zx zI7O578SEPBn-UoQOpRWGn{lrMoIt#~mq=uwxQV;7}N9$}% z-1(%F&c6LkqJkc}Hl{96{7dKZRfWmllh zuXH)V7H9=sbvZA9yR&pRb`B&Oo2h&9dL?SRt?qNa9u;w`NcSxt2Ran!nbSbamU^x$ zKDd&u=Sv~*${4-Q?kA>(X?or4>)@)sdTEt42Do8*%LiDGy{dQMpvdE+dWY~!m^za5 zj`Jp?QYxam)v+>4dLKua_voU2bQS8QO3+W;#SJJZDgCS~=KJnogjGNc>Cr_$zQ@pEB_Uevw z3Do~{rx6(BkUrCt#>PGK_1AiV1Ako5=RaJ5mN`XVq{CFz{=L5ZEc`fRoc?na)Ia`B zUs*RE_o8O{$`=oauKyM_{a9Swx{3x{DA4Gd*l0Hd|IQbiC#9hUOjgiC5Uu}$zrQaQ zTRh@%Z?F+6h{xFZ|HiD&wP-1XwDNLYGV6z5z*T<#@_p-#?3-(1B-3r7(x*d#6w&c>a% zmAJlhIj*9s#f_#xI`xRS(F@0^rA=$GFj@RJuo_emC6*P>#S~L0 ze%ucaES)QU;Zt!1NET~aVBbD3gAf}83duHT6GAZGMHr+`?TLDa8XBE@4obUfXnLa@ zIdtFPV)9Jk6GP9QaQ&#QhMuM?$H1=!51a0wm`4T=qv=P?I>P`PxaPnVgID)a5bR;_ zCQo#SE{4I|;p!~~2Hyf4c(ukbdM0utp_^e^PjFkpYQwy&EOe9QhR_4PME|ojELph{ z2Dlj33^K>x7poPV&`!bE`wa)aekb~Q#*lT*1$|dA7<0N@AeyzrP!NhN-&|%WsREu~ zYJ`y{-7K+x9I1~3wm@a8Y!KJ<%B>gQf^v{7(gK?1e zFj#67fPF7H$$}7~=iMcX2pFPkE;$B3?wLrbtzR~(Zl+OcdnA@9NWE$M&xIb=bk9caeqn^&YndUH<6~BI)Bb;X{IyweJ_?m%EuFRw~#_(-~sbJ zQmE+?|I|hbe+5O(pOqqixnY*?EN$72P-{eK+cpVRFk0Gn1qyC3R!ecmT7Vs_r9JCI zh1fa$oTS1OC`wnP zyM<8b$TR8bYtUANt5i`0c@LjTp90?EufpC^^>?t(zT+@S!W^?&v$aGTfNb^KP&iYjqF(G04!@MJC@%gnmbKy_xE-D z5%WRrkQq*NtFi2K(GnOgI~!p6MV;LH1FE1=J-N@{hcT!wl!w>A1A)GBV4^GPKQBfe z-3uW|Z6%Ms6baX@l1JZk#AU)x9y1OWJf1C&`3IpnK3yJ@(+G{A9O#Eh_Ng2cX$zuB zljry2AlO+BZ4^(mXpA31R>6iTm>Q{8#|Mc^Q(O+pT|bCJ^@mO`=7^2N3bpwMAC zyAsd2v2soac&PJgxuCf>(VWNf?Pd)?waN0Q_}7pZC4Uo~aV=BJ-*(kv)cG;hLo#wbf^ChPxawU diff --git a/translations/pencil_fr.qm b/translations/pencil_fr.qm index c7cd19b51a5faf7748347dd6085528ce132ce918..ea1eb76c415b3cfeab7524591fc496ed86b82503 100644 GIT binary patch delta 5878 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 delta 5455 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 delta 5544 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 diff --git a/translations/pencil_pt_BR.qm b/translations/pencil_pt_BR.qm index 66fb7784c2d9a8ad5efd9006699d0867a64176eb..e7b81338a984f00af6863a9c884a6e5840f7d517 100644 GIT binary patch delta 5642 zcmX9?30zI-8-CBZ=bXEpdrl!uLy07$qGT`_YiYIbSxQls_-i7X>Dp@0ST90}>}y$~ zlr>SwURl#98fGF}VJ!JS*YW%LJ@-53JKy)d&-cF1`+l9f!Ij_S)->tVk%(JM|^ND;si2VB#y;!-nXA9=W+VL%nH;G1P5;cCQV8jzrSrSo` z^~9M@;5nz@6b*5E<`WH^P2B!T!0p6k#1Tz#Bktq?qD8xj%jK|33UN1pek^e}9f^Js z6!dRG+?|y~|9<$6jCwP1&tZwt!d>~{{~TCE6rK;PBkI~hLH``$UckM8M#Oi)#;q?a zIB1%JFXs^Nb&1GgjDmxn67P@ihYcfsBn+!@`i_j&o%ktdiH3&~KW917sLbzZq?fyi zPs|`1YeW1dEEH5vd|Ct1G)v+SV#A4r3cd;^J|FWYcPIWv0a2)mBvbT5i*^(~3`n`AeCH^y4BKfDX`il{?_n&`2X+{FtO8PxST4%3^V9?n=ec$B0>8od-eIjR&K zQ>9?-&op-5dZOBV8hhp#QQT`9HwEz-{6xV;+;?PD|4`796NtzV8vh#WPP?RFr7w;D zypPD~+;?R7KPY6x2r`oIpzlBEO=pT|2L4vt(loQDFUHc$WuDmR6h#V=c)p0{p0NV{ zMX{SWVwhvJq*Fc7(hn4`eokbyn&MmaA_}pieQvIZ$oF(;EIfTwNk_f0?(=fW+A{}9 z6+$@{7^fA}8JEZo_z^~DhBqO)-7I(e2s`CioM55ni!%VUa?I^ zml3sJ!a982PZaf%b$hs(=l=ZcbBT8Pu2K2N8_GN#q_9V(1 z#zuE9Cc3zcjcW>)*Un%UcZh~?gtDuPx+A{Q*{wf@5t%0QHpVnIgR3SQH-kN9j=5KB z*ettJqIP}Rti8yTj3I1xG4^^yY|aNzG{J{GWB#`75%xk}JyJVS!Md*OWk*ocbOL+3 z5)^c7&sGFYAo?wptteuN>V9V{?(QavU&cN*Q*%0vtu%jcw6kC<^UH`1{L5B;%f*YY zY?XiyPmN@&o5A=~I`&=CIHJM~wmzx`^G31tk5Y&cquEbq9EozmRgGpl5H)+RYC2^M zNNK8S^{yRJLz&9qUOZ9c9#!jg*zk6q%CXRf=*vBoQxuXou}Ib7TNGltW{j$1A1zVK z=Bh5+aSDNvs-J$VAkro&IMZL%Z=)SiwWZ3x4;HdbQw4VcBNfe5VKZUi0zcIZ^YeD` zs;Dv8@O`=}#>`Or9;(WA+s`_IG zM9MT%^~Zg@Ff~@K$n8&zFiW+ve>FsFlFF0|N_XX|wmyJ5o@!9-H1$Jv4p8kMn1$$d zP#umL3b{#89sUd^f9$5pdUc6t#zxh{sHsGQQdF;gal%oRs2X;L5NZBX@bw#xn`Nve zDl&3H^AT8}f>R$p0aZ-qG_BU-tZs2u^{_nqFlW82oT$+{1qV8F&0;-?#>8^1ic^X9 z+jEYl6-1rKa?S%0pJV;FUXG23^nJO02e96#30(gd{fSEc;k-p(JTFkNzK|Q++P^q8&@Qm2w`K>1lG*c=;xVaOXF| zzMWxQL1HBEBv-f`F)ZgP=zEpB?pp@``g1qt!XH0Z?#5kbqT+8{2|F6)+6#z~@n2{< zp=n{P;>t~N$gY>%qmEXfdp7sv(r{#BbMBwtVC2e8T+JrX-!*`%`C5l+xsv;2gi*Jn zc+R|fU{_w9wg;jc#W%M&OO&#Lw_87e7!Av}x>t{JIqx9yL{q)_HtQM_LwESLUrdOX z?tFWz5y*s#w|M9Br^M(U@GdV_5xIx)U0UG74afK{&iHWa72Ycx?sj^~2h4tgl(pr@ zg-l1)tK-AXRUjghpW*Wb<@$(%Bfjy!&v}N8+wckhHi67o@(B${>Fo*ppWTp>+P?f6 zi%Ud*+~-ZJBasQW4Sdp~`9ziT_$`k!i7r|3DbBlyESo4ezJT9)9G=Y&;ZouSK1k$RBLGlxXn(_=6k0k*WjuLs3{KHH$wKgLOB);nO29?{PAp ze$*QKjOLGJcq0?G7xTw*5z*mzV8+eE`Qv_|I47OY?2<~9EAr>ZwL%1^^0#w06CEw& zZ$I7*oW(!-I2;YgIt8nG@zsNH(EH!;)lUZ#se=@J9l(Eh1?IlYjU1mxZQ_x43cZ~%vUsH6s24&XFW8%2Ck(s_bB4tWKFQY+ zk~xBJn>^I<3xZ$v3FOfb!T()rqHBK&0T*DdSGIz$E(ifvqlp}9grS8YM6cDt(7Ho# z&q)|H9qTTiAdKPQ&bA<7Tru#+q%}fN%T#ZP)(F3MDj@Q-5RBn4XIq|-;DYndxF(pi6VL(g5Vq7qz!v^4 z>}t7$Xx=E{m^n~QMMD1EbhL%*g)7xCr!Y*oY6Z4_?j_tv01hq@ZYAHxDa{vdy;4Is zS7ZveX*bbby-<;rkBlf19yf|5DtI7N_2`Q@5ftoQEL5L`0V}2m&t~67eg352n<~>+ z(b`z1)|=(2?5K4|hJQu>%4)dYUi|f>GF2Dn6>aJa2=9-@B zKEZH%V5!>g3BJo)r4A^*PBh+8J!3yA%pM!{%;8}~yR+55`a5F&VfCLkl5iJ@P_G}= z8Z@}6H>%NPP5anGy*Cg3UUyd?6vm=U$X6dd>INR(tB(%>f7dstPu@cN7U`zWT@Z&0 z!2tEucis>NSzQt|3|&_r_1&`=Z*@>teuH~M0~LJhp|0}RLAQTWSD%k0I^t^jYOprG z)`%1F)Ury`=m~;hSh2>+A8&u3udxmBM2yeX*tPOOvy`UkoN*RapqHlWnA1evZfbh; zSVjz+qUl*xizaBUrr#!5x9p(C%NFx~PS*tXY`|fR)C3-@$Nb5f5j7)-^0PJJJ{vH0 z(JbA8d97yN(kzSOksP-bjB?kk3~B;lT&`eJpy`CwI)oV)cd*b>uTEUg$HKo;9XUaNFS({?8 z7NIGtiNm}rnu@V_-ZD#5o!uF!SEKp2^D|V3-I{OLR*{}M)Mzz1#~@#fX{Ky#Jg*Ij zJ`2(E(T1%6Uc0WHz8Y>;p3}yh{)gy8y>`(m#Msy7+Vy8jh~e97H^pP#$xGVgUo21- z-fJ_4gZ3A8+AG^!k#qO7&rZVppS9YTrOSyDCTm~KMh;6FZNn>=Wj9R64*_1N)HQjq z6V1P2qpq22D$)7~UGv6xvHqOS!7P5|zB*_3>qIx7>N-Hi=}Bu{j}I&wAWj!H7w@g^ z>B0vWVxxJw}yfmh3p9^E-7Z55Z?^58c*Fb{Kcl z?U<-0Bg4PY?T>}!SvI=#DS^NRy32j5A?sS*WfO42E8XSiNY9P^bOp1U0h4tFe*se` z>aJ`VL^LT&_wZRf;=QZx?KM3NPSkz8h7CK6)-xx8w!`&Ycg)WZ(eu? z+Ua$3iqQPq9M($-t#D78p|`t>7h6W?T{sx>@QmIi?mXItBYM}l5y+2nlZ&NY`*p+g zLtNqDgRA;Ub#T01rJtU{6C;J|XEX&G{?RX5jDvsqqbb_5g)v3Hvs{E!Gy1*5a30w% z`h)j^ammfsA335%ThK^n97b^?e>*r;Cnl;QiJ`qFX;0TKGxqy+eZGwPOD}vxvmT zqF?7#h=UzsV8?qfJV6XA9z&E=Cr+JHh1;uzI5m3!0`6b&e~I}1!fr9@d>qREofI*q zvnSDijQHDv2}Cjd#U-;Z!7^uYW!G9%7YA{Tx$(_hBCZL*hnaW8wZ(q8ox6xzgNtBb ziMY=t77MDyqe2BS@(wXOeKE?zF)?QgJiIbeJlD>ZXhfKp7kd^(_O5u_s|;0Vk67~1 z8RdTkFP7$D;et`(oyM3b$l{|sP&B%Yf(tu~kGrQsn3KgSdr(0GP>ei-c7HT6>H>rG zlhK{1_dbFU-k?5cgQ2(iiV(2P;Oo!}l5$(Fm^2G9vTvbbMsG;jzMF=*`T3|6 zzZqhTyG9dPZ#688kB7&lhUJ5;(aCx!82Yn<&kq=OefSRzjEf<^um?Q*YAEP-mT1-) z!_63k@>-ptst$POyx~O(HryR)c;f`annfAj-wi}%?kK6|G$5t&CC)59p)(}y1TZ?% zO)~0l1Q7L#kgO(S!Ta+hn{k-gKi!gBI z3u)`2*3f`X()N|n_@mexX@4RpEs2%(pKAg`rb-#M4s}c8?MInuttDzcLDr-^MKk0j>&$xMb6ReDqc4i`J_X;dkX~Ps5FAlxrHM#RSJIJG(>}i1K=hn)7Um^>Bh?o0~+Kcy|^2je> zVElA>;=%qXL~in=J~)Eo-{eW>6Tw`PJn6bCt^;l5;K^{{VZ0oC8b@=eR1Pk%f!@Ca zjzJSSLJmuGgw70+=Xr6+|Lbq%7@Ji58KRLKvlK_sG)-P`u?iQMMY8c;2@0<)ul_Uy zg*Ze`a)qZZUF6gf7&^;C-WGZmH)>Yio>Px5Jybpz0)w*3@!oEKXGi|rFX=*hjI%4v4`=Mb|!sdiUP7bs8j*bWoGcjQ{$CGBa&H6tT Crrogs delta 5478 zcmXX~cR)@38-LC{^&0EHL4fc7a2*Ckx?Q_6f#1H z29Z$_UXfL{{65$H{q?!$d%oxSKF{Zw-}~qecRrWfXjZ!kQEQ3Fa)k-2BQ`l&Ftn+6 zVb^DMlp(~{CL*&f#2HRuoikxz2yq7%5%rx-T*6pjEOAMpM1gU{ zo$gJvy#A(JR(h{W;_j^@dOh_IGD?xSSG|a8wK1W07VtXJu0W2z3HxOd?~U&VIubtwr@!9$2lb3K{ z^f8Xw=wNx|Dsqn060L1Y?G(?69zUfHuizechFl#Wcw8M5E^{7OzOUX-%_w9y}*93TNs)2kImx%N( zN=ZnvX1)S#q;w{Z#E6|1kWeaY2dX&V)V*OG-M6zZuG*0 zgF|Ro7;h=i zd&r&I!Gt9lH0sA8BKz}ykm0^lz~I58C(nL=e$e}aG^GLfTfdQ}8ZE83MKe~p;Gh;X zQ<#bMDhkRlC)zN8Lbh|nFm|-Ebv04gR0>zVA~N4V;Wk~N&?Y+6(g_jynT`&JrH=PM*u<`Q`XP zQ|az_U<$+bLqut&G0L`h3q82>Uo9#&S%aZZj=S%d` zmKhgPNpzwu6Ic~PG{KCSRxUw=URR=xPZcX#EFc7-V#D=LL?5gTfqY{RGer_t zPBi?f;)F5U-m!{Qs{*2bdMHv4LZ`&binJV@@@SqS{YwndsB?;pzXFMx9amh;szy@R znDEmP!!6!IUt96yx`OD_d&QIc`{C&yiV`CO=gbtP#@$x66s4C7i4Koal>R=8_1TIt zVKhB_eFJrBj|CflmJn#j5# z+b$N=`u1hpFL^?wjxyo&^K8#;R!G7y*1J38G}_CKYX|cmuV({iK*2?s>~!P$KjG{= ze;oMPnhiG6(cF~{`MDmsapx7gGy=Z!DPlv7JT|}0hMB?gU0v9SuMdfO%xC|NLoM1| z!v6aJ>zgCkHD`Mf!1wuk-X!EkzaaKqH+wj=4_mV@fJpVtgzqPC+^kAa`;ikG z4kjw|08X=m}gXD2r^V=K{!o!rWh8f5twZk?P3Mvfa?RDC?x6ml1~L9e(XE<182(Y}AU zYpW5ca+V1_Z*sRi3t?9(mm35-yqvh)`wm1obGdxQFtoKMK!l3-aKjZ)9T&LwKwuAN#K3v7GDm24&+;=^cy8D9XjM9DU@XEah zh~B>78`jE%TYvFZTY3|tT)^8DRTD+`<84KrXkt45_vX69kO$xFr-7*Y7~kA{Faq>a zFW%wNb7C|;yyKhoL~R23c8&4jRy)3(13ui{h3_*N=C*#z`^v z7Wpam{B)0>=*GuQIQRj-bnZ(ivV)I!Z3cG3_=p50!w@u&^r(j=+#3v?O;G7)(M3TF) zcz5MboJAy0!h#XEXY(h$KykV?pVBS{sOK+?utDI)@OfuC;x`n7yn4nGuRhfeX&Cjh!t*?UU?~VexSI|AOBD!56)cx0&sCb1? zZ+Qozdi4a0R#40?Ot477`lwGrgGeV7=w?F0AUq%6FEkkgLq5+Gnmt=Vq`M$AlZ-#Q zj}n@_b%AAH3^TO$dQNb2z*DWqCLDTI=-vnVCQcIi-h?^>#|R#~ZX+bq1<${;(55d6 zUTLR@qAm;GpPItH--6FYsM{yagzwr4J~tN-*;WVxt_7f?FBS$=9ff)J!q91uyXvms z&%vCSTwz2G@UJLV7-_v8W6=y@O#cFOJ0D@}9DCT^&EP0D){8=jz!Jj+3Lz0-?R-CB zN!w5a6e}!kosFhdOVCe-I(uA%2uJuo$xSe*M`MbO6LwakaOvL*@zyJef^G;WjDc!! z6)p!QV(L>0H_D+-c9C$?9Bg&&D&$50`yUhT?s|YgeIcHh*?H)`1t$D3*r3x{==&Y8m1YakVXll=xlpXMU4**4Vv@3@Bk-`9vO_zlx#767`#6~0w?OIj4Burj zN}rtD7-F|8rzfDX>|d*#F(?q|pq%e*hc4Shxi&Wn^L$U`mZ42SLrdj0C5EV}Uy_su zvtaM7{mLW4aCD;f%H-sh;9-jLq#yXZtx}%8i|K4eobv4AP@-jN%A23uiMFgz=8qgm zv@}I|KNHW<+mxlhVcvjdCj4+fS>~-ly>728zc3U0?=|Qo3;lSNI0mb=%T#rqAs7bk zSDAa`?UFaDMgcBF8ULxQY&{Yc*%0#11R(0?{N7V6-%GGrhF$!7LrL2-j3R3ml z4((Q1srod+zRrm%-!3(9#&wnNiE8X0uNqu27}@Qhn(VO^&yK3FIP9~T(Mz>z9*^Y6 zGvVC*s&ymHP#AxjaN9-070F5e@rCO0N62gQL3JacnizFs)y?+yL|rDSZm}mpW02~u z7tr^ssvyo-pN$B;Cx)sD9=Ko#&oSZJJF0?m$eGBi3jfXlYmZcg6`?3HT~tqoW8FGc zRi4%ssaK(T-S#DlL4DQlTkACU_mBs5a-l^Yk;@9tEX*% znWb&i!RP)X`Z8I)d_7|9=LYqbjC>@;ZuRzX>^t2-y{lU-jM`JwNrOOp#U}NQJx<8E zBK6DDP`|TU{kC8=n(RIGyV=NLNu{oN2eqsQYIr~3#X%aghx;(w>(rVCPBF-mN1BFp z@nTCGjjgfx6=!H1+T13(GgQ+8Wt_^QG_GG1m{=ET0)z10yht;-|1})6P_w!Q(V}@~ z!m7ub&9mU2NeeYQH^&maX|CCs7K(7Mr-?2GpG}=LyRTRwtB-2p#wbb8@MAOyA<+Ev zT210aU*KEK)gI;OOG`9Y4Zy7dnyasno?B0AvS&9ynU^%#Pl3DhG&gqkBO2RWQ~WX< z>3c-;@s^e-w?^~z77lDNOv{`GHX5YmI${5%LM>kod6$-JHTFNy^`o_#xz}6Zu6#@@ zMc5EMd#bg%j~6?xX&pHzQrt@G7LR+m<&=g#H`x&~_wralVs@Bg520rYj9a{y% ztAe!CqIqI;#oFohj5t!ed<7i;W}P9tc4NJ)-S048L-vA zT>G&KN**oHeyS6Li^w7Er>FNJ$5vGJVTn9BQD+A&^_HDP%RLbMyRm4UbP9gsP3T@C z+H?l3-&TrEAMhCBtwp=PVSRL!*s>=Sy*5L1i<5{(j}v>{n?)qn6}{T72TSInZ>u6G z9w7$i_@gOI5+}_qLk(XkPD<-d6fsJi6N&FH))(hp2u1t9CyT*tU5LKU7ndv^O|&po zTsiv+?rbsQx(=1-F1F%EvEuG=*TFy^@sMK(0%)SCiHi;uHF(J(Th{-9XWDG}65Vp$VVdEH%n-Vq0gX<~V!8azjeFUC}3|97#XbUx9v z5#sxOU?B9h_?b_^zXct|pG~nZHe4s{3dAMUMW;?!fC;UWPHK<4JGm{>S*Ab1-v&;) zMmH*nk%sGBK@Al&(z&^T`jIM~oAGMkvq9Ys%fiE9 zL85MTe+x{q&L$lH|L0eYbn#!lVStI%UB2dupqZ`9?wCn5tCj9fFhY6bQe9aUFvD5* zCK?CEm+C&)L$L<)bf540!sq)Wc5V$6Z7*@g;xqoKq#g}Mho~jJHrI!!>lDd+JOmcK zmMlkLp9lt~R%!4i$7kNk6Ldh$3JuI!3CZ0KiAa<2z7+ZL@L7L@)ecy7W1(g$sT%Gk&@D?KjR#LF> z`uymm6#5*BWGs~;f4O5CpD%6Q4qprBq^KwfSuk3Px&#H+jgfXAZHgq1mtxl~AnNu( zN{9rdd6iPac{3>TP)cfq%heY~IyG=Sy53^xb}JV!VJYR$K=W-KE#;qtV!!p@q=I~C zba1uw=q0LC_-5%{2?RbEB7GR~ADZTvcB(8Snk&hzhF(W~XR>AI ztWcCiH@WS3D`1@LqJ!nm5 zmB(I)#C=pFkG<`LKl66U7ORSFt`ePQoCI?2^q0acp3;S@$ z|J#9buw@L<;&3@Q46dlRS6+On4CzrN>x=Tycx8FRcRylOg>sY=EOl%r$K*rNnFr)O z6Eca`ERbW d^fC+@Vr>{Qr?%ntc(ap-##`%7wwlu-^?$Abz%u{< From 827cddb1d1bf59378d65629dfeae0487f79cddcd Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Fri, 27 Apr 2018 13:17:37 +1000 Subject: [PATCH 027/184] Add Polish & Estonian to preferences --- app/src/preferencesdialog.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/preferencesdialog.cpp b/app/src/preferencesdialog.cpp index e0e013d93..9795d26dd 100644 --- a/app/src/preferencesdialog.cpp +++ b/app/src/preferencesdialog.cpp @@ -96,19 +96,21 @@ GeneralPage::GeneralPage(QWidget* parent) : ui->languageCombo->addItem(tr("Danish") + " (Danish)", "da"); ui->languageCombo->addItem(tr("German") + " (German)", "de"); ui->languageCombo->addItem(tr("English") + " (English)", "en"); + ui->languageCombo->addItem(tr("Estonian") + " (Estonian)", "et"); ui->languageCombo->addItem(tr("Spanish") + " (Spanish)", "es"); ui->languageCombo->addItem(tr("French") + " (French)", "fr"); ui->languageCombo->addItem(tr("Hebrew") + " (Hebrew)", "he"); - ui->languageCombo->addItem(tr("Hungarian") + " (Hungarian)", "hu-HU"); + ui->languageCombo->addItem(tr("Hungarian") + " (Hungarian)", "hu_HU"); ui->languageCombo->addItem(tr("Indonesian") + " (Indonesian)", "id"); ui->languageCombo->addItem(tr("Italian") + " (Italian)", "it"); ui->languageCombo->addItem(tr("Japanese") + " (Japanese)", "ja"); + ui->languageCombo->addItem(tr("Polish") + " (Polish)", "pl"); ui->languageCombo->addItem(tr("Portuguese - Portugal") + "(Portuguese - Portugal)", "pt"); - ui->languageCombo->addItem(tr("Portuguese - Brazil") + "(Portuguese - Brazil)", "pt-BR"); + ui->languageCombo->addItem(tr("Portuguese - Brazil") + "(Portuguese - Brazil)", "pt_BR"); ui->languageCombo->addItem(tr("Russian") + " (Russian)", "ru"); ui->languageCombo->addItem(tr("Slovenian") + " (Slovenian)", "sl"); ui->languageCombo->addItem(tr("Vietnamese") + " (Vietnamese)", "vi"); - ui->languageCombo->addItem(tr("Chinese - Taiwan") + " (Chinese - Taiwan)", "zh-TW"); + ui->languageCombo->addItem(tr("Chinese - Taiwan") + " (Chinese - Taiwan)", "zh_TW"); int value = settings.value("windowOpacity").toInt(); ui->windowOpacityLevel->setValue(100 - value); From 81d05c15aacb0b306728b16e058dc4699ea00781 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Mon, 7 May 2018 10:30:03 +1000 Subject: [PATCH 028/184] Update polish translations --- translations/pencil_pl.qm | Bin 76190 -> 77698 bytes translations/pencil_pl.ts | 750 ++++++++++++++++++++------------------ 2 files changed, 398 insertions(+), 352 deletions(-) diff --git a/translations/pencil_pl.qm b/translations/pencil_pl.qm index 9919a286b84576be878181e2c822c29a9db3044a..a6858c8a2df1b30c508942e363c6baa4f10e8835 100644 GIT binary patch delta 6143 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 SnE0erLrd`#^|EDVe)K=fy-ged delta 4947 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 Z{=yp`Nlj*qTT)pY=0TRDIWy*~{{qcB9C`o% diff --git a/translations/pencil_pl.ts b/translations/pencil_pl.ts index 9a13b269d..ec59b6f54 100644 --- a/translations/pencil_pl.ts +++ b/translations/pencil_pl.ts @@ -1,6 +1,6 @@ - + AboutDialog @@ -151,57 +151,57 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">re BaseTool - + Pencil Ołówek - + Eraser Gumka - + Select Zaznaczenie - + Move Przesunięcie - + Hand Ręka - + Smudge Rozmazanie - + Pen Pióro - + Polyline Linia - + Bucket Wypełniacz - + Eyedropper Selektor kolorów - + Brush Pędzel @@ -363,8 +363,8 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">re ColorPaletteWidget - - + + Colour name Nazwa koloru @@ -1281,7 +1281,7 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">re - + Play Graj @@ -1499,22 +1499,22 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">re Przesuń klatkę do tyłu - + color palette:<br>use <b>(C)</b><br>toggle at cursor Paleta kolorów: <br>użyj <b>(C)</b><br>by przełączyć kursor - + Lock Windows Zablokuj okna - + Open Recent Otwórz ostatnie pliki - + You have successfully cleared the list @@ -1523,86 +1523,92 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">re Pomyślnie wyczyszczono listę - - - - + + + + + Warning Uwaga - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil nie może odczytać tego pliku. Jeżeli chcesz wczytać obraz, użyj polecenia <b>importu</b>. - + Opening document... Otwórz dokument... - - - + + + Abort Anuluj - + Saving document... Zapisuje dokument... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>Wystąpił błąd i plik nie został pomyślnie zapisany. Jeśli uważasz, że ten błąd dotyczy programu Pencil2D, utwórz nowy problem na stronie:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Pamiętaj, by w swoim zgłoszeniu uwzględnić następujące szczegóły: - + This animation has been modified. Do you want to save your changes? Animacja została zmieniona. Czy zapisać zmiany? - + The animation is not saved yet. Do you want to save now? Animacja jeszcze nie została zapisana. Czy zapisać ją teraz? - + Never ask again AutoSave reminder button Nigdy więcej nie pytaj - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Nie można importować obrazu.<br><b>Podpowiedź:</b> Użyj warstwy bitmapowej dla importu bitmapy. - + Importing image sequence... Importowanie sekwencji obrazów... - - + + was unable to import + nie można importować + + + + Undo Menu item text Cofnij - + Redo Menu item text Ponów - + Stop Stop @@ -1610,122 +1616,122 @@ Czy zapisać ją teraz? Object - + Black czarny - + Red Czerwony - + Dark Red Ciemny czerwony - + Orange Pomarańczowy - + Dark Orange Ciemny pomarańczowy - + Yellow Żółty - + Dark Yellow Ciemny żółty - + Green Zielony - + Dark Green Ciemny zielony - + Cyan Cyan - + Dark Cyan Ciemny cyan - + Blue Niebieski - + Dark Blue Ciemny niebieski - + White Biały - + Very Light Grey Bardzo jasny szary - + Light Grey Jasny szary - + Grey Szary - + Dark Grey Ciemny szary - + Light Skin Jasna skóra - + Light Skin - shade Jasna skóra - odcień - + Skin Skóra - + Skin - shade Skóra - odcień - + Dark Skin Ciemna skóra - + Dark Skin - shade Ciemna skóra - odcień @@ -1860,26 +1866,26 @@ Czy zapisać ją teraz? Uwaga: format wyjściowy jest nie określony lub nie obsługiwany. Przejście do użycia PNG. - + Warning: Transparency is not currently supported in movie files Command line warning Uwaga: przezroczystość aktualnie nie jest obsługiwana dla plików filmowych - + Exporting movie... Command line task progress Eksportuje film... - - + + Done. Command line task done Gotowe. - + Exporting image sequence... Command line task progress Eksportowanie sekwencji obrazów... @@ -1940,8 +1946,8 @@ Czy zapisać ją teraz? - Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) + Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + Obrazy (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) @@ -1984,1337 +1990,1337 @@ Czy zapisać ją teraz? Pliki Pencil Animation PCLX(*.pclx);;Stare pliki Pencil Animation PCL(*.pcl) - + Vivid Pink Żywy różowy - + Strong Pink Mocny różowy - + Deep Pink Głęboki róż - + Light Pink Jasny róż - + Moderate Pink Umiarkowany róż - + Dark Pink Ciemny róż - + Pale Pink Blady róż - + Grayish Pink Szary róż - + Pinkish White Różowaty biały - + Pinkish Gray Różowaty szary - + Vivid Red Żywy czerwony - + Strong Red Mocny czerwony - + Deep Red Głęboki czerwony - + Very Deep Red Bardzo głęboki czerwony - + Moderate Red Umiarkowany czerwień - + Dark Red Ciemny czerwony - + Very Dark Red Bardzo ciemny czerwień - + Light Grayish Red Jasny szary czerwień - + Grayish Red Szary czerwień - + Dark Grayish Red Ciemny szary czerwień - + Blackish Red Czarny czerwień - + Reddish Gray Czerwony szary - + Dark Reddish Gray Ciemny czerwony szary - + Reddish Black Czerwień czarny - + Vivid Yellowish Pink Żywy żółty róż - + Strong Yellowish Pink Mocny żółty róż - + Deep Yellowish Pink Głęboki żółty róż - + Light Yellowish Pink Jasny żółty róż - + Moderate Yellowish Pink Umiarkowany żółty róż - + Dark Yellowish Pink Ciemny żółty róż - + Pale Yellowish Pink Blady żółty róż - + Grayish Yellowish Pink Szary żółty róż - + Brownish Pink Brązowaty róż - + Vivid Reddish Orange Żywy czerwień pomarańcz - + Strong Reddish Orange Mocny czerwień pomarańcz - + Deep Reddish Orange Głęboki czerwień pomarańcz - + Moderate Reddish Orange Umiarkowany czerwień pomarańcz - + Dark Reddish Orange Ciemny czerwień pomarańcz - + Grayish Reddish Orange Szary czerwień pomarańcz - + Strong Reddish Brown Mocny czerwień brąz - + Deep Reddish Brown Głęboki czerwień brąz - + Light Reddish Brown Jasny czerwień brąz - + Moderate Reddish Brown Umiarkowany czerwień brąz - + Dark Reddish Brown Ciemny czerwień brąz - + Light Grayish Reddish Brown Jasny szarawy czerwień brąz - + Grayish Reddish Brown Szarawy czerwień brąz - + Dark Grayish Reddish Brown Ciemny szarawy czerwień brąz - + Vivid Orange Żywy pomarańcz - + Brilliant Orange Błyszczący pomarańcz - + Strong Orange Mocny pomarańcz - + Deep Orange Głęboki pomarańcz - + Light Orange Jasny pomarańcz - + Moderate Orange Umiarkowany pomarańcz - + Brownish Orange Brązowy pomarańcz - + Strong Brown Mocny brąz - + Deep Brown Głęboki brąz - + Light Brown Jasny brąz - + Moderate Brown Umiarkowany brąz - + Dark Brown Ciemny brąz - + Light Grayish Brown Jasny szarawy brąz - + Grayish Brown Szarawy brąz - + Dark Grayish Brown Ciemny szarawy brąz - + Light Brownish Gray Jasny brązowaty szary - + Brownish Gray Brązowaty szary - + Brownish Black Brązowata czerń - + Vivid Orange Yellow Żywy pomarańczowo żółty - + Brilliant Orange Yellow Błyszczący pomarańczowo żółty - + Strong Orange Yellow Mocny pomarańczowo żółty - + Deep Orange Yellow Głęboki pomarańczowo żółty - + Light Orange Yellow Jasny pomarańczowo żółty - + Moderate Orange Yellow Umiarkowany pomarańczowo żółty - + Dark Orange Yellow Ciemny pomarańczowo żółty - + Pale Orange Yellow Blady pomarańczowo żółty - + Strong Yellowish Brown Mocny żółty brąz - + Deep Yellowish Brown Głęboki żółty brąz - + Light Yellowish Brown Jasny żółty brąz - + Moderate Yellowish Brown Umiarkowany żółty brąz - + Dark Yellowish Brown Ciemny żółty brąz - + Light Grayish Yellowish Brown Jasny szarowaty żółty brąz - + Grayish Yellowish Brown Szarowaty żółty brąz - + Dark Grayish Yellowish Brown Ciemny szarawy żółty brąz - + Vivid Yellow Żywy żółty - + Brilliant Yellow Błyszczący żółty - + Strong Yellow Mocny żółty - + Deep Yellow Głęboki żółty - + Light Yellow Jasny żółty - + Moderate Yellow Umiarkowany żółty - + Dark Yellow Ciemny żółty - + Pale Yellow Blady żółty - + Grayish Yellow Szarawy żółty - + Dark Grayish Yellow Ciemny szarawy żółty - + Yellowish White Żółtawa biel - + Yellowish Gray Żółtawy szary - + Light Olive Brown Jasny oliwkowo brązowy - + Moderate Olive Brown Umiarkowany oliwkowo brązowy - + Dark Olive Brown Ciemny oliwkowo brązowy - + Vivid Greenish Yellow Żywy zielono żółty - + Brilliant Greenish Yellow Błyszczący zielono żółty - + Strong Greenish Yellow Mocny zielono żółty - + Deep Greenish Yellow Głęboki zielono żółty - + Light Greenish Yellow Jasny zielono żółty - + Moderate Greenish Yellow Umiarkowany zielono żółty - + Dark Greenish Yellow Ciemny zielono żółty - + Pale Greenish Yellow Blady zielono żółty - + Grayish Greenish Yellow Szarawy zielono żółty - + Light Olive Jasny oliwkowy - + Moderate Olive Umiarkowany oliwkowy - + Dark Olive Ciemny oliwkowy - + Light Grayish Olive Jasny szarawy oliwkowy - + Grayish Olive Szarawy oliwkowy - + Dark Grayish Olive Ciemny szarawy oliwkowy - + Light Olive Gray Jasny oliwkowo szary - + Olive Gray Oliwkowo szary - + Olive Black Oliwkowo czarny - + Vivid Yellow Green Żywy żółto zielony - + Brilliant Yellow Green Błyszczący żółto zielony - + Strong Yellow Green Mocny żółto zielony - + Deep Yellow Green Głęboki żółto zielony - + Light Yellow Green Jasny żółto zielony - + Moderate Yellow Green Umiarkowany żółto zielony - + Pale Yellow Green Blady żółto zielony - + Grayish Yellow Green Szarawy żółto zielony - + Strong Olive Green Mocny oliwkowo zielony - + Deep Olive Green Głęboki oliwkowo zielony - + Moderate Olive Green Umiarkowany oliwkowo zielony - + Dark Olive Green Ciemny oliwkowo zielony - + Grayish Olive Green Szarawy oliwkowo zielony - + Dark Grayish Olive Green Ciemny szarawy oliwkowo zielony - + Vivid Yellowish Green Żywy żółtawo zielony - + Brilliant Yellowish Green Błyszczący żółtawo zielony - + Strong Yellowish Green Mocny żółtawo zielony - + Deep Yellowish Green Głęboki żółtawo zielony - + Very Deep Yellowish Green Bardzo błęboki żółtawo zielony - + Very Light Yellowish Green Bardzo jasny żółtawo zielony - + Light Yellowish Green Jasny żółtawo zielony - + Moderate Yellowish Green Umiarkowany żółtawo zielony - + Dark Yellowish Green Ciemny żółtawo zielony - + Very Dark Yellowish Green Bardzo ciemny żółtawo zielony - + Vivid Green Żywy zielony - + Brilliant Green Błyszczący zielony - + Strong Green Mocny zielony - + Deep Green Głęboki zielony - + Very Light Green Bardzo jasny zielony - + Light Green Jasny zielony - + Moderate Green Umiarkowany zielony - + Dark Green Ciemny zielony - + Very Dark Green Bardzo ciemny zielony - + Very Pale Green Bardzo blady zielony - + Pale Green Blady zielony - + Grayish Green Szarawy zielony - + Dark Grayish Green Ciemny szarawy zielony - + Blackish Green Czarnowata zieleń - + Greenish White Zielonkowaty biały - + Light Greenish Gray Jasny zielony szary - + Greenish Gray Zielony szary - + Dark Greenish Gray Ciemny zielony szary - + Greenish Black Zielonkowata czerń - + Vivid Bluish Green Żywy niebieskawo zielony - + Brilliant Bluish Green Błyszczący niebieskawo zielony - + Strong Bluish Green Mocny niebieskawo zielony - + Deep Bluish Green Głęboki niebieskawo zielony - + Very Light Bluish Green Bardzo jasny niebieskawo zielony - + Light Bluish Green Jasny niebieskawo zielony - + Moderate Bluish Green Umiarkowany niebieskawo zielony - + Dark Bluish Green Ciemny niebieskawo zielony - + Very Dark Bluish Green Bardzo ciemny niebieskawo zielony - + Vivid Greenish Blue Żywy zielonkowaty niebieski - + Brilliant Greenish Blue Błyszczący zielonkowaty niebieski - + Strong Greenish Blue Mocny zielonkowaty niebieski - + Deep Greenish Blue Głęboki zielonkowaty niebieski - + Very Light Greenish Blue Bardzo jasny zielonkowaty niebieski - + Light Greenish Blue Jasny zielonkowaty niebieski - + Moderate Greenish Blue Umiarkowany zielonkowaty niebieski - + Dark Greenish Blue Ciemny zielonkowaty niebieski - + Very Dark Greenish Blue Bardzo ciemny zielonkowaty niebieski - + Vivid Blue Żywy niebieski - + Brilliant Blue Błyszczący niebieski - + Strong Blue Mocny niebieski - + Deep Blue Głęboki niebieski - + Very Light Blue Bardzo jasny niebieski - + Light Blue Jasny niebieski - + Moderate Blue Umiarkowany niebieski - + Dark Blue Ciemny niebieski - + Very Pale Blue Bardzo blady niebieski - + Pale Blue Blady niebieski - + Grayish Blue Szarawy niebieski - + Dark Grayish Blue Ciemny szarawy niebieski - + Blackish Blue Czarny niebieski - + Bluish White Niebieskowata biel - + Light Bluish Gray Jasny niebiesko szary - + Bluish Gray Niebiesko szary - + Dark Bluish Gray Ciemny niebiesko szary - + Bluish Black Niebiesko czarny - + Vivid Purplish Blue Żywy fioletowato niebieski - + Brilliant Purplish Blue Błyszczący fioletowato niebieski - + Strong Purplish Blue Mocny fioletowato niebieski - + Deep Purplish Blue Głęboki fioletowato niebieski - + Very Light Purplish Blue Bardzo jasny fioletowato niebieski - + Light Purplish Blue Jasny fioletowato niebieski - + Moderate Purplish Blue Umiarkowany fioletowato niebieski - + Dark Purplish Blue Ciemny fioletowato niebieski - + Very Pale Purplish Blue Bardzo blady fioletowato niebieski - + Pale Purplish Blue Blady fioletowato niebieski - + Grayish Purplish Blue Szarawy fioletowato niebieski - + Vivid Violet Żywy fioletowy - + Brilliant Violet Błyszczący fioletowy - + Strong Violet Mocny fioletowy - + Deep Violet Głęboki fioletowy - + Very Light Violet Bardzo jasny fioletowy - + Light Violet Jasny fioletowy - + Moderate Violet Umiarkowany fioletowy - + Dark Violet Ciemny fioletowy - + Very Pale Violet Bardzo blady fioletowy - + Pale Violet Blady fioletowy - + Grayish Violet Szarawy fioletowy - + Vivid Purple Żywy purpurowy - + Brilliant Purple Błyszczący purpurowy - + Strong Purple Mocny purpurowy - + Deep Purple Głęboki purpurowy - + Very Deep Purple Bardzo głęboki purpurowy - + Very Light Purple Bardzo jasny purpurowy - + Light Purple Jasny purpurowy - + Moderate Purple Umiarkowany purpurowy - + Dark Purple Ciemny purpurowy - + Very Dark Purple Bardzo ciemny purpurowy - + Very Pale Purple Bardzo blady purpurowy - + Pale Purple Blady purpurowy - + Grayish Purple Szarawy purpurowy - + Dark Grayish Purple Ciemny szarawy purpurowy - + Blackish Purple Czarny purpurowy - + Purplish White Purpurowa biel - + Light Purplish Gray Jasny purpurowy szary - + Purplish Gray Purpurowo szary - + Dark Purplish Gray Ciemny purpurowo szary - + Purplish Black Purpurowo czarny - + Vivid Reddish Purple Żywy fuksja - + Strong Reddish Purple Mocny fuksja - + Deep Reddish Purple Głęboki fuksja - + Very Deep Reddish Purple Bardzo głęboki fuksja - + Light Reddish Purple Jasny fuksja - + Moderate Reddish Purple Umiarkowany fuksja - + Dark Reddish Purple Ciemny fuksja - + Very Dark Reddish Purple Bardzo ciemny fuksja - + Pale Reddish Purple Blady fuksja - + Grayish Reddish Purple Szarawy fuksja - + Brilliant Purplish Pink Błyszczący malinowy - + Strong Purplish Pink Mocny malinowy - + Deep Purplish Pink Głęboki malinowy - + Light Purplish Pink Jasny malinowy - + Moderate Purplish Pink Umiarkowany malinowy - + Dark Purplish Pink Ciemny malinowy - + Pale Purplish Pink Blady malinowy - + Grayish Purplish Pink Szarawy malinowy - + Vivid Purplish Red Żywy magenta - + Strong Purplish Red Mocny magenta - + Deep Purplish Red Głęboki magenta - + Very Deep Purplish Red Bardzo głęboki magenta - + Moderate Purplish Red Umiarkowany magenta - + Dark Purplish Red Ciemny magenta - + Very Dark Purplish Red Bardzo ciemny magenta - + Light Grayish Purplish Red Jasny szarawy magenta - + Grayish Purplish Red Szarawy magenta - + White Biały - + Light Gray Jasny szary - + Medium Gray Średni szary - + Dark Gray Ciemny szary - + Black Czarny @@ -3335,61 +3341,61 @@ Czy zapisać ją teraz? ScribbleArea - + Warning Uwaga - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Aktualnie rysujesz na ukrytej warstwie! Użyj innej warstwy (albo zmień obecną warstwę na widoczną). - + Delete Selection Undo Step: clear the selection area. Usuń zaznaczenie - - + + Clear Image Undo step text Czyść obraz - + There is a gap in your drawing (or maybe you have zoomed too much). Znaleziono lukę w rysunku (bądź obraz został za bardzo powiększony). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). Przepraszam! Ta opcja nie zawsze działa poprawnie. Spróbuj ponownie (powiększ nieco, kliknij w inne miejsce...)<br> jeżeli to nie pomoże, to spróbuj powiększyć i sprawdź, czy ścieżki są połączone (naciskając klawisz F1). - + Out of bound. Brak powiązania. - + Could not find a closed path. Nie można znaleźć zamkniętej ścieżki. - + Could not find the root index. Nie można znaleźć głównego indeksu. - + %1<br><br>Error: %2 %1<br><br>Błąd: %2 - + Flood fill error Błąd napełnianiu wypełnienia @@ -3594,12 +3600,12 @@ jeżeli to nie pomoże, to spróbuj powiększyć i sprawdź, czy ścieżki są p TimeLineCells - + Layer Properties Właściwości warstwy - + Layer name: Nazwa warstwy: @@ -3636,6 +3642,46 @@ jeżeli to nie pomoże, to spróbuj powiększyć i sprawdź, czy ścieżki są p Preferences Długość osi czasu: + + + Drawing + Rysowanie + + + + When drawing on an empty frame: + Podczas rysowania na pustej ramce: + + + + Create a new (blank) key-frame and start drawing on it. + Utwórz nową (pustą) klatkę kluczową i zacznij rysować na niej. + + + + Create a new (blank) key-frame + Utwórz nową (pustą) klatkę kluczową + + + + Duplicate the previous key-frame and start drawing on the duplicate. + Powiel poprzednią klatkę kluczową i zacznij rysować na utworzonym duplikacie. + + + + Duplicate the previous key-frame + Powiel poprzednią klatkę kluczową + + + + Keep drawing on the previous key-frame + Rysuj na poprzedniej klatce kluczowej + + + + <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + <html><head/><body><p>(Ustawienie dotyczy narzędzi: ołówek, gumka, pióro, linia, wypełniacz i pędzel)</p></body></html> + Frame size From 7d63ba096e9fbbd2023f0439179f08de1842c05e Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Mon, 7 May 2018 15:30:32 +1000 Subject: [PATCH 029/184] Headers clean up --- app/src/main.cpp | 4 ++++ app/src/preferencesdialog.cpp | 6 ++++-- app/src/preferencesdialog.h | 18 ------------------ core_lib/src/canvaspainter.h | 3 +-- core_lib/src/external/win32/win32.cpp | 2 ++ core_lib/src/managers/playbackmanager.cpp | 5 +++-- core_lib/src/managers/soundmanager.cpp | 1 + core_lib/src/movieexporter.cpp | 2 ++ core_lib/src/structure/filemanager.cpp | 1 + core_lib/src/structure/layer.cpp | 2 +- core_lib/src/structure/layer.h | 3 ++- core_lib/src/structure/layerbitmap.cpp | 2 ++ core_lib/src/structure/layersound.cpp | 4 +++- core_lib/src/structure/object.cpp | 1 - core_lib/src/tool/handtool.cpp | 1 + core_lib/src/tool/movetool.h | 1 + 16 files changed, 28 insertions(+), 28 deletions(-) diff --git a/app/src/main.cpp b/app/src/main.cpp index 2448d2224..1c5b12da1 100644 --- a/app/src/main.cpp +++ b/app/src/main.cpp @@ -19,6 +19,10 @@ GNU General Public License for more details. #include #include #include +#include +#include +#include + #include "editor.h" #include "mainwindow2.h" #include "pencilapplication.h" diff --git a/app/src/preferencesdialog.cpp b/app/src/preferencesdialog.cpp index 9795d26dd..2588be7ad 100644 --- a/app/src/preferencesdialog.cpp +++ b/app/src/preferencesdialog.cpp @@ -15,15 +15,17 @@ GNU General Public License for more details. */ #include "preferencesdialog.h" + +#include +#include #include "ui_preferencesdialog.h" #include "ui_generalpage.h" #include "ui_timelinepage.h" #include "ui_filespage.h" #include "ui_toolspage.h" -#include -#include #include "util.h" + PreferencesDialog::PreferencesDialog( QWidget* parent ) : QDialog(parent), ui(new Ui::PreferencesDialog) diff --git a/app/src/preferencesdialog.h b/app/src/preferencesdialog.h index 718394ab6..a2435f361 100644 --- a/app/src/preferencesdialog.h +++ b/app/src/preferencesdialog.h @@ -18,31 +18,13 @@ GNU General Public License for more details. #define _PREFERENCES_H_ #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include "pencildef.h" #include "scribblearea.h" -#include "shortcutspage.h" #include "preferencemanager.h" -class QListWidget; class QListWidgetItem; -class QStackedWidget; -class QComboBox; class PreferenceManager; -class FilesPage; namespace Ui { class PreferencesDialog; diff --git a/core_lib/src/canvaspainter.h b/core_lib/src/canvaspainter.h index b212cce30..e6eeae371 100644 --- a/core_lib/src/canvaspainter.h +++ b/core_lib/src/canvaspainter.h @@ -17,11 +17,10 @@ GNU General Public License for more details. #ifndef CANVASPAINTER_H #define CANVASPAINTER_H - +#include #include #include #include -#include #include "log.h" diff --git a/core_lib/src/external/win32/win32.cpp b/core_lib/src/external/win32/win32.cpp index 45550ecb8..7fca053f4 100644 --- a/core_lib/src/external/win32/win32.cpp +++ b/core_lib/src/external/win32/win32.cpp @@ -24,6 +24,8 @@ GNU General Public License for more details. #include #include #include +#include +#include #include "object.h" #include "editor.h" diff --git a/core_lib/src/managers/playbackmanager.cpp b/core_lib/src/managers/playbackmanager.cpp index 9ebca3cd9..a8234460d 100644 --- a/core_lib/src/managers/playbackmanager.cpp +++ b/core_lib/src/managers/playbackmanager.cpp @@ -18,13 +18,14 @@ GNU General Public License for more details. #include "playbackmanager.h" #include +#include +#include #include "object.h" #include "editor.h" #include "layersound.h" #include "layermanager.h" -#include "soundmanager.h" #include "soundclip.h" -#include "soundplayer.h" + PlaybackManager::PlaybackManager(Editor* editor) : BaseManager(editor) { diff --git a/core_lib/src/managers/soundmanager.cpp b/core_lib/src/managers/soundmanager.cpp index abb75057a..2ee060457 100644 --- a/core_lib/src/managers/soundmanager.cpp +++ b/core_lib/src/managers/soundmanager.cpp @@ -18,6 +18,7 @@ GNU General Public License for more details. #include "soundmanager.h" #include +#include #include "editor.h" #include "object.h" #include "layersound.h" diff --git a/core_lib/src/movieexporter.cpp b/core_lib/src/movieexporter.cpp index e19d705c4..43e51df25 100644 --- a/core_lib/src/movieexporter.cpp +++ b/core_lib/src/movieexporter.cpp @@ -24,6 +24,8 @@ GNU General Public License for more details. #include #include #include +#include + #include "object.h" #include "layercamera.h" #include "layersound.h" diff --git a/core_lib/src/structure/filemanager.cpp b/core_lib/src/structure/filemanager.cpp index 1cac220b2..9639ebfc0 100644 --- a/core_lib/src/structure/filemanager.cpp +++ b/core_lib/src/structure/filemanager.cpp @@ -17,6 +17,7 @@ GNU General Public License for more details. #include "filemanager.h" +#include #include "pencildef.h" #include "qminiz.h" #include "fileformat.h" diff --git a/core_lib/src/structure/layer.cpp b/core_lib/src/structure/layer.cpp index ab8465ae6..6b8aa90b8 100644 --- a/core_lib/src/structure/layer.cpp +++ b/core_lib/src/structure/layer.cpp @@ -17,9 +17,9 @@ GNU General Public License for more details. #include "layer.h" #include +#include #include "keyframe.h" #include "object.h" -#include "timeline.h" #include "timelinecells.h" diff --git a/core_lib/src/structure/layer.h b/core_lib/src/structure/layer.h index 4d0cba022..f9506ef14 100644 --- a/core_lib/src/structure/layer.h +++ b/core_lib/src/structure/layer.h @@ -19,9 +19,10 @@ GNU General Public License for more details. #include #include +#include #include #include -#include +#include class QMouseEvent; class KeyFrame; diff --git a/core_lib/src/structure/layerbitmap.cpp b/core_lib/src/structure/layerbitmap.cpp index f2adf1421..96e0d1db4 100644 --- a/core_lib/src/structure/layerbitmap.cpp +++ b/core_lib/src/structure/layerbitmap.cpp @@ -17,6 +17,8 @@ GNU General Public License for more details. #include "layerbitmap.h" #include +#include +#include #include "keyframe.h" #include "bitmapimage.h" diff --git a/core_lib/src/structure/layersound.cpp b/core_lib/src/structure/layersound.cpp index afaf5d402..b727c8a56 100644 --- a/core_lib/src/structure/layersound.cpp +++ b/core_lib/src/structure/layersound.cpp @@ -16,8 +16,10 @@ GNU General Public License for more details. */ #include "layersound.h" -#include +#include #include +#include +#include #include "object.h" #include "soundclip.h" diff --git a/core_lib/src/structure/object.cpp b/core_lib/src/structure/object.cpp index 3db3e79fb..a38fd8111 100644 --- a/core_lib/src/structure/object.cpp +++ b/core_lib/src/structure/object.cpp @@ -18,7 +18,6 @@ GNU General Public License for more details. #include #include -#include #include #include diff --git a/core_lib/src/tool/handtool.cpp b/core_lib/src/tool/handtool.cpp index e41939c84..ff745b8ca 100644 --- a/core_lib/src/tool/handtool.cpp +++ b/core_lib/src/tool/handtool.cpp @@ -18,6 +18,7 @@ GNU General Public License for more details. #include "handtool.h" #include +#include #include #include #include diff --git a/core_lib/src/tool/movetool.h b/core_lib/src/tool/movetool.h index af5a3cbdc..c656285a3 100644 --- a/core_lib/src/tool/movetool.h +++ b/core_lib/src/tool/movetool.h @@ -22,6 +22,7 @@ GNU General Public License for more details. class Layer; + class MoveTool : public BaseTool { Q_OBJECT From 688f5d734403cad72aae80cd14afbcdbdfa46ef0 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Mon, 7 May 2018 16:07:36 +1000 Subject: [PATCH 030/184] Fix compiler errors --- core_lib/src/external/linux/linux.cpp | 1 + core_lib/src/tool/basetool.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/core_lib/src/external/linux/linux.cpp b/core_lib/src/external/linux/linux.cpp index 979152ebc..13ed24d4e 100644 --- a/core_lib/src/external/linux/linux.cpp +++ b/core_lib/src/external/linux/linux.cpp @@ -22,6 +22,7 @@ GNU General Public License for more details. #include #include #include +#include #include "object.h" #include "editor.h" #include "layersound.h" diff --git a/core_lib/src/tool/basetool.cpp b/core_lib/src/tool/basetool.cpp index 2e00ab6f0..9c7829f41 100644 --- a/core_lib/src/tool/basetool.cpp +++ b/core_lib/src/tool/basetool.cpp @@ -244,7 +244,7 @@ void BaseTool::stopAdjusting() void BaseTool::adjustCursor(qreal argOffsetX, ToolPropertyType propertyType) //offsetx x-lastx ... { - qreal inc = pow(OriginalSettingValue * 100, 0.5); + qreal inc = qPow(OriginalSettingValue * 100, 0.5); qreal newValue = inc + argOffsetX; int max = (propertyType == FEATHER) ? 64 : 200; int min = (propertyType == FEATHER) ? 2 : 1; @@ -254,7 +254,7 @@ void BaseTool::adjustCursor(qreal argOffsetX, ToolPropertyType propertyType) //o newValue = 0; } - newValue = pow(newValue, 2) / 100; + newValue = qPow(newValue, 2) / 100; if (mAdjustmentStep > 0) { int tempValue = (int)(newValue / mAdjustmentStep); // + 0.5 ? From bc84700e51b0517569a4a98df42f32231c0a0cb9 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Mon, 7 May 2018 16:17:55 +1000 Subject: [PATCH 031/184] Fix more compiler errors --- app/src/colorpalettewidget.cpp | 9 +++++++-- app/src/colorpalettewidget.h | 2 +- core_lib/src/external/linux/linux.cpp | 1 + core_lib/src/external/macosx/macosx.cpp | 13 +++++++++++-- core_lib/src/tool/basetool.cpp | 1 + core_lib/src/util/pencildef.h | 4 ++++ 6 files changed, 25 insertions(+), 5 deletions(-) diff --git a/app/src/colorpalettewidget.cpp b/app/src/colorpalettewidget.cpp index 301d2e2a9..6bd1eb22a 100644 --- a/app/src/colorpalettewidget.cpp +++ b/app/src/colorpalettewidget.cpp @@ -15,13 +15,16 @@ GNU General Public License for more details. */ #include "colorpalettewidget.h" +#include "ui_colorpalette.h" + +#include #include #include #include #include #include -#include "ui_colorpalette.h" +#include #include "colordictionary.h" #include "colourref.h" @@ -324,6 +327,8 @@ void ColorPaletteWidget::updateGridUI() QString ColorPaletteWidget::getDefaultColorName(QColor c) { + using std::pow; + // Separate rgb values for convenience const int r = c.red(); const int g = c.green(); @@ -338,7 +343,7 @@ QString ColorPaletteWidget::getDefaultColorName(QColor c) // Convert XYZ to CEI L*u*v // (algorithm source: https://www.cs.rit.edu/~ncs/color/t_convert.html#XYZ%20to%20CIE%20L*a*b*%20(CIELAB)%20&%20CIELAB%20to%20XYZ) // Helper function for the conversion - auto f = [](const double a) { return a > 0.008856 ? cbrt(a) : 7.787 * a + 16 / 116; }; + auto f = [](const double a) { return a > 0.008856 ? std::cbrt(a) : 7.787 * a + 16 / 116; }; // XYZ tristimulus values for D65 (taken from: https://en.wikipedia.org/wiki/Illuminant_D65#Definition) const qreal xn = 95.047, yn = 100, diff --git a/app/src/colorpalettewidget.h b/app/src/colorpalettewidget.h index 7386c5b29..9f9a2cde6 100644 --- a/app/src/colorpalettewidget.h +++ b/app/src/colorpalettewidget.h @@ -88,7 +88,7 @@ private slots: QAction* mSmallSwatchAction = nullptr; QAction* mMediumSwatchAction = nullptr; QAction* mLargeSwatchAction = nullptr; - QAction* mSeparator; + QAction* mSeparator = nullptr; QSize mIconSize{ 34, 34 }; QMenu* mToolMenu = nullptr; diff --git a/core_lib/src/external/linux/linux.cpp b/core_lib/src/external/linux/linux.cpp index 13ed24d4e..2ae39883f 100644 --- a/core_lib/src/external/linux/linux.cpp +++ b/core_lib/src/external/linux/linux.cpp @@ -23,6 +23,7 @@ GNU General Public License for more details. #include #include #include +#include #include "object.h" #include "editor.h" #include "layersound.h" diff --git a/core_lib/src/external/macosx/macosx.cpp b/core_lib/src/external/macosx/macosx.cpp index 6b1d28604..f8803c21c 100644 --- a/core_lib/src/external/macosx/macosx.cpp +++ b/core_lib/src/external/macosx/macosx.cpp @@ -20,6 +20,13 @@ GNU General Public License for more details. #include #include #include +#include +#include + +#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) + #include +#endif + #include "object.h" #include "editor.h" #include "pencildef.h" @@ -59,7 +66,7 @@ void enableCoalescing() SetMouseCoalescingEnabled(true, NULL); } -void Editor::importMovie (QString filePath, int fps) +void Editor::importMovie(QString filePath, int fps) { int i; @@ -96,7 +103,9 @@ void Editor::importMovie (QString filePath, int fps) {qDebug() << "ERROR: FFmpeg did not finish executing.";} } else - {qDebug() << "Please install FFMPEG: sudo apt-get install ffmpeg";} + { + qDebug() << "Please install FFMPEG: sudo apt-get install ffmpeg"; + } progress.setValue(50); QDir dir1(tempPath); int nFiles = dir1.entryList().count(); diff --git a/core_lib/src/tool/basetool.cpp b/core_lib/src/tool/basetool.cpp index 9c7829f41..6b051ef01 100644 --- a/core_lib/src/tool/basetool.cpp +++ b/core_lib/src/tool/basetool.cpp @@ -18,6 +18,7 @@ GNU General Public License for more details. #include "basetool.h" #include +#include #include "editor.h" #include "viewmanager.h" #include "toolmanager.h" diff --git a/core_lib/src/util/pencildef.h b/core_lib/src/util/pencildef.h index bae2e3496..6bf921af9 100644 --- a/core_lib/src/util/pencildef.h +++ b/core_lib/src/util/pencildef.h @@ -18,6 +18,10 @@ GNU General Public License for more details. #ifndef PENCILDEF_H #define PENCILDEF_H +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + #define PENCIL_MOVIE_EXT \ QObject::tr( "AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv)" ) From 8b4cb830863046606f615053abe9f11261cf6e76 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Mon, 7 May 2018 17:50:55 +1000 Subject: [PATCH 032/184] Xcode compiler error --- tests/src/test_viewmanager.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/src/test_viewmanager.cpp b/tests/src/test_viewmanager.cpp index 4ab3bae9f..38c7ecbfb 100644 --- a/tests/src/test_viewmanager.cpp +++ b/tests/src/test_viewmanager.cpp @@ -15,6 +15,7 @@ GNU General Public License for more details. */ #include "catch.hpp" +#include #include "viewmanager.h" #include "editor.h" #include "object.h" @@ -164,8 +165,8 @@ TEST_CASE("ViewManager::scale") QPointF p1 = v.mapCanvasToScreen(QPointF(1, 1)); QPointF p2 = QPointF(0.01, 0.01); - REQUIRE(std::abs(p1.x() - p2.x()) < 0.000001); - REQUIRE(std::abs(p1.y() - p2.y()) < 0.000001); + REQUIRE(std::fabs(p1.x() - p2.x()) < 0.000001); + REQUIRE(std::fabs(p1.y() - p2.y()) < 0.000001); } delete editor; @@ -350,4 +351,4 @@ void TestViewManager::testSetCameraKey() QTransform canvasShift = QTransform::fromTranslate(50, 50); REQUIRE( t0, c->view * canvasShift); } -*/ \ No newline at end of file +*/ From 2a31c3fd1fec83ab0fcf76e3d7b7e2bf5781a22c Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Mon, 7 May 2018 17:53:04 +1000 Subject: [PATCH 033/184] Ignore moc_predef.h --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b8b13012e..a628cc2d2 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ ui_*.h Makefile* *-build-* .moc +moc_predefs.h Makefile Makefile.Debug From 2943203c125e2ae883c22ee70316381b54b392aa Mon Sep 17 00:00:00 2001 From: CandyFace Date: Thu, 10 May 2018 20:26:07 +0200 Subject: [PATCH 034/184] Add colorsliders, UI and more... Added colorslider widgets + HSV, RGB colorsliders with extendability + Color wheel and color sliders are now separated + Improved performance of painting color square. + Remember color values from last session + Can modify existing swatches on bitmap (forced behaviour for now) + Ability to add colors to palette using the color wheel, and via the dialog through a new button. + Added colorpalette preference icon --- app/app.pro | 6 +- app/data/app.qrc | 3 + app/data/icons/new/checkerboard_smaller | Bin 0 -> 829 bytes app/data/icons/new/svg/color-dialog.svg | 38 +++ app/data/icons/new/svg/more_options.svg | 21 ++ app/src/colorbox.cpp | 38 +-- app/src/colorbox.h | 5 +- app/src/colorinspector.cpp | 208 +++++++++--- app/src/colorinspector.h | 20 +- app/src/colorpalettewidget.cpp | 54 +++- app/src/colorpalettewidget.h | 5 + app/src/colorslider.cpp | 401 ++++++++++++++++++++++++ app/src/colorslider.h | 92 ++++++ app/src/colorwheel.cpp | 78 +++-- app/src/mainwindow2.cpp | 33 +- app/src/mainwindow2.h | 7 +- app/ui/colorinspector.ui | 312 ++++++++++++++++-- app/ui/colorpalette.ui | 87 ++++- core_lib/src/managers/colormanager.cpp | 12 +- 19 files changed, 1269 insertions(+), 151 deletions(-) create mode 100644 app/data/icons/new/checkerboard_smaller create mode 100644 app/data/icons/new/svg/color-dialog.svg create mode 100644 app/data/icons/new/svg/more_options.svg create mode 100644 app/src/colorslider.cpp create mode 100644 app/src/colorslider.h diff --git a/app/app.pro b/app/app.pro index 20927b268..c726f20eb 100644 --- a/app/app.pro +++ b/app/app.pro @@ -58,7 +58,8 @@ HEADERS += \ src/exportimagedialog.h \ src/importimageseqdialog.h \ src/spinslider.h \ - src/doubleprogressdialog.h + src/doubleprogressdialog.h \ + src/colorslider.h SOURCES += \ src/main.cpp \ @@ -85,7 +86,8 @@ SOURCES += \ src/exportimagedialog.cpp \ src/importimageseqdialog.cpp \ src/spinslider.cpp \ - src/doubleprogressdialog.cpp + src/doubleprogressdialog.cpp \ + src/colorslider.cpp FORMS += \ ui/mainwindow2.ui \ diff --git a/app/data/app.qrc b/app/data/app.qrc index 7a68a10d1..2ac121f46 100644 --- a/app/data/app.qrc +++ b/app/data/app.qrc @@ -50,6 +50,7 @@ icons/new/svg/selection.svg icons/new/svg/smudge_detailed.svg icons/new/svg/trash_detailed.svg + icons/new/checkerboard_smaller icons/onion-blue.png @@ -62,5 +63,7 @@ icons/mirrorV.png icons/dialog-error.svg pencil2d_quick_guide.pdf + icons/new/svg/color-dialog.svg + icons/new/svg/more_options.svg diff --git a/app/data/icons/new/checkerboard_smaller b/app/data/icons/new/checkerboard_smaller new file mode 100644 index 0000000000000000000000000000000000000000..71a0822a54c6ea829efdec055a03917f2f11f779 GIT binary patch literal 829 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9Sn@V3f`bi71Ki^|4CM&(%vz$xlkv ztH>-n*TA>HIW;5GqpB!1xXLdi zxhgx^GDXSWj?1RP3TQxXYDuC(MQ%=Bu~mhw64+cTAR8pCucQE0Qj%?}6yY17;GAES zs$i;Ts%M~N$E9FXl#*r@k>g7FXt#Bv$C=6)S^`fSBQuTAW;zSx}OhpQivaGchT@w8U0PNgrg1KGYVVbM@iw z1#;j%PR#>)vk2%PDX-P9fWg$5>FgX(9OUk#;OXjYW@u?KCdRZLOo@l}qav{%eYAex{(& zr64tHR(F(E-1F1~mwBgmJ}=(?ecs`{&zn?d1%ImAEB>iC46L})LcDU+#ew}h; z%L`3O%TsCp|9=bh=l`X3RhDsst;8{JeUrQc&vzy6c`tqJIb+28hid}P#@}jQ7=H2k z>ZtR27U2({>{+F{?Li5z)%z#q`}m)ShiAWpgv3ANdpnDtn{RSTO-<#|E|}@0>dwTVZ^k=E T_5QKxpj7Ya>gTe~DWM4f%6CF% literal 0 HcmV?d00001 diff --git a/app/data/icons/new/svg/color-dialog.svg b/app/data/icons/new/svg/color-dialog.svg new file mode 100644 index 000000000..4a79d4bc7 --- /dev/null +++ b/app/data/icons/new/svg/color-dialog.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/data/icons/new/svg/more_options.svg b/app/data/icons/new/svg/more_options.svg new file mode 100644 index 000000000..07f79b30f --- /dev/null +++ b/app/data/icons/new/svg/more_options.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/colorbox.cpp b/app/src/colorbox.cpp index 3ea82ae6b..16c9b3b20 100644 --- a/app/src/colorbox.cpp +++ b/app/src/colorbox.cpp @@ -18,18 +18,18 @@ GNU General Public License for more details. #include "colorwheel.h" #include "colorinspector.h" #include "colorbox.h" +#include "qsettings.h" +#include "pencildef.h" ColorBox::ColorBox( QWidget* parent ) : BaseDockWidget( parent ) { - setWindowTitle(tr("Color Wheel", "Color Wheel's window title")); + setWindowTitle(tr("Color Box", "Color Box window title")); mColorWheel = new ColorWheel(this); - mColorInspector = new ColorInspector(this); QVBoxLayout* layout = new QVBoxLayout(); layout->setContentsMargins(5, 5, 5, 5); layout->addWidget(mColorWheel); - layout->addWidget(mColorInspector); layout->setStretch(0, 1); layout->setStretch(1, 0); QWidget* mainWidget = new QWidget; @@ -37,13 +37,8 @@ ColorBox::ColorBox( QWidget* parent ) : BaseDockWidget( parent ) setWidget(mainWidget); connect(mColorWheel, &ColorWheel::colorChanged, this, &ColorBox::onWheelMove); - connect(mColorInspector, &ColorInspector::colorChanged, this, &ColorBox::onSpinboxChange); connect(mColorWheel, &ColorWheel::colorSelected, this, &ColorBox::onWheelRelease); - - QColor defaultColor; - defaultColor.setHsv(0, 0, 0); - mColorWheel->setColor(defaultColor); - mColorInspector->setColor(defaultColor); +// connect(this, &ColorBox::colorChanged, mColorWheel, &ColorWheel::setColor); } ColorBox::~ColorBox() @@ -52,6 +47,11 @@ ColorBox::~ColorBox() void ColorBox::initUI() { + QSettings settings(PENCIL2D, PENCIL2D); + + QColor savedColor; + savedColor.setRgba(settings.value("colorOfSliders").toUInt()); + setColor(savedColor); } void ColorBox::updateUI() @@ -65,34 +65,18 @@ QColor ColorBox::color() void ColorBox::setColor(const QColor& newColor) { - if ( newColor.toHsv() != mColorWheel->color() ) + if ( newColor != mColorWheel->color() ) { mColorWheel->setColor(newColor); - mColorInspector->setColor(newColor); - - emit colorChanged(newColor); - } -} - -void ColorBox::onSpinboxChange(const QColor& color) -{ - if ( mColorWheel->color() != color.toHsv() ) - { - mColorWheel->setColor(color); - emit colorChanged(color); } } void ColorBox::onWheelMove(const QColor& color) { - if ( mColorInspector->color() != color ) - { - mColorInspector->setColor(color); - } + emit colorChanged(color); } void ColorBox::onWheelRelease(const QColor& color) { - mColorInspector->setColor(color); emit colorChanged(color); } diff --git a/app/src/colorbox.h b/app/src/colorbox.h index 23d8b604b..3bcc2f890 100644 --- a/app/src/colorbox.h +++ b/app/src/colorbox.h @@ -19,8 +19,6 @@ GNU General Public License for more details. #include "basedockwidget.h" class ColorWheel; -class ColorInspector; - class ColorBox : public BaseDockWidget { @@ -40,12 +38,11 @@ class ColorBox : public BaseDockWidget void colorChanged(const QColor&); private: - void onSpinboxChange(const QColor&); void onWheelMove(const QColor&); void onWheelRelease(const QColor&); ColorWheel* mColorWheel = nullptr; - ColorInspector* mColorInspector = nullptr; +// ColorInspector* mColorInspector = nullptr; }; #endif // COLORBOX_H diff --git a/app/src/colorinspector.cpp b/app/src/colorinspector.cpp index 385eb5555..752f96c51 100644 --- a/app/src/colorinspector.cpp +++ b/app/src/colorinspector.cpp @@ -16,20 +16,53 @@ GNU General Public License for more details. #include "colorinspector.h" #include "ui_colorinspector.h" +#include +#include #include +#include + +#include "colorslider.h" +#include "pencildef.h" ColorInspector::ColorInspector(QWidget *parent) : - QWidget(parent), - ui(new Ui::ColorInspector) + BaseDockWidget(parent) { - ui->setupUi(this); + + QWidget* innerWidget = new QWidget; + setWindowTitle(tr("Color Inspector", "Window title of color inspector")); + + ui = new Ui::ColorInspector; + ui->setupUi(innerWidget); + setWidget(innerWidget); + + QButtonGroup* colorModeChangeGroup = new QButtonGroup(); + + colorModeChangeGroup->addButton(ui->hsvButton); + colorModeChangeGroup->addButton(ui->rgbButton); + colorModeChangeGroup->setExclusive(true); + + QSettings settings(PENCIL2D, PENCIL2D); + isRgbColors = settings.value("isRgb").toBool(); + + if (isRgbColors) { + ui->rgbButton->setChecked(true); + } else { + ui->hsvButton->setChecked(true); + } + onModeChanged(); auto spinBoxChanged = static_cast(&QSpinBox::valueChanged); connect(ui->RedspinBox, spinBoxChanged, this, &ColorInspector::onColorChanged); connect(ui->GreenspinBox, spinBoxChanged, this, &ColorInspector::onColorChanged); connect(ui->BluespinBox, spinBoxChanged, this, &ColorInspector::onColorChanged); connect(ui->AlphaspinBox, spinBoxChanged, this, &ColorInspector::onColorChanged); - connect(ui->rgb, &QRadioButton::toggled, this, &ColorInspector::onModeChanged); + connect(ui->rgbButton, &QPushButton::clicked, this, &ColorInspector::onModeChanged); + connect(ui->hsvButton, &QPushButton::clicked, this, &ColorInspector::onModeChanged); + + connect(ui->red_slider, &ColorSlider::valueChanged, this, &ColorInspector::onSliderChanged); + connect(ui->green_slider, &ColorSlider::valueChanged, this, &ColorInspector::onSliderChanged); + connect(ui->blue_slider, &ColorSlider::valueChanged, this, &ColorInspector::onSliderChanged); + connect(ui->alpha_slider, &ColorSlider::valueChanged, this, &ColorInspector::onSliderChanged); } ColorInspector::~ColorInspector() @@ -37,16 +70,65 @@ ColorInspector::~ColorInspector() delete ui; } +void ColorInspector::initUI() +{ + if (isRgbColors) { + ui->red_slider->init(ColorSlider::ColorType::RED, QColor(255,255,255,255), 0.0, 255.0); + ui->green_slider->init(ColorSlider::ColorType::GREEN, QColor(255,255,255,255), 0.0, 255.0); + ui->blue_slider->init(ColorSlider::ColorType::BLUE, QColor(255,255,255,255), 0.0, 255.0); + ui->alpha_slider->init(ColorSlider::ColorType::ALPHA, QColor(0,255,255,255), 0.0, 255.0); + } else { + ui->red_slider->init(ColorSlider::ColorType::HUE, QColor(359,255,255,255), 0.0, 359.0); + ui->green_slider->init(ColorSlider::ColorType::SAT, QColor(255,255,255,255), 0.0, 255.0); + ui->blue_slider->init(ColorSlider::ColorType::VAL, QColor(255,255,255,255), 0.0, 255.0); + ui->alpha_slider->init(ColorSlider::ColorType::ALPHA, QColor(0,255,255,255), 0.0, 255.0); + } + + QSettings settings(PENCIL2D, PENCIL2D); + + QColor savedColor; + savedColor.setRgba(settings.value("colorOfSliders").toUInt()); + setColor(savedColor); +} + +void ColorInspector::updateUI() +{ +} + +void ColorInspector::onSliderChanged(QColor color) +{ + + if (isRgbColors) { + ui->red_slider->setRgb(color); + ui->green_slider->setRgb(color); + ui->blue_slider->setRgb(color); + ui->alpha_slider->setRgb(color); + } else { + ui->red_slider->setHsv(color); + ui->green_slider->setHsv(color); + ui->blue_slider->setHsv(color); + ui->alpha_slider->setHsv(color); + } + + emit colorChanged(color); +} + void ColorInspector::setColor(const QColor &newColor) { - if (newColor == m_color) + if (newColor == mCurrentColor) { return; } noColorUpdate = true; + qDebug() << "set color"; if(isRgbColors) { + ui->red_slider->setRgb(newColor); + ui->green_slider->setRgb(newColor); + ui->blue_slider->setRgb(newColor); + ui->alpha_slider->setRgb(newColor); + ui->RedspinBox->setValue(newColor.red()); ui->GreenspinBox->setValue(newColor.green()); ui->BluespinBox->setValue(newColor.blue()); @@ -54,42 +136,73 @@ void ColorInspector::setColor(const QColor &newColor) } else { + ui->red_slider->setHsv(newColor); + ui->green_slider->setHsv(newColor); + ui->blue_slider->setHsv(newColor); + ui->alpha_slider->setHsv(newColor); + ui->RedspinBox->setValue(newColor.hsvHue()); ui->GreenspinBox->setValue(qRound(newColor.hsvSaturation() / 2.55)); ui->BluespinBox->setValue(qRound(newColor.value() / 2.55)); ui->AlphaspinBox->setValue(qRound(newColor.alpha() / 2.55)); } - m_color = newColor; + + mCurrentColor = newColor; QPalette p1 = ui->colorWrapper->palette(), p2 = ui->color->palette(); p1.setBrush(QPalette::Background, QBrush(QImage(":/background/checkerboard.png"))); - p2.setColor(QPalette::Background, m_color); + p2.setColor(QPalette::Background, mCurrentColor); ui->colorWrapper->setPalette(p1); ui->color->setPalette(p2); noColorUpdate = false; + update(); } QColor ColorInspector::color() { - return m_color; + return mCurrentColor; +} + +void ColorInspector::paintEvent(QPaintEvent*) +{ + + // HACK: possible bug in 5.9 + // title style is not set when window is not docked + // this enforces the style again. This is what QDockWidget + // should be doing behind the scene + QStyleOptionDockWidget opt; + initStyleOption(&opt); + + QStylePainter p(this); + p.drawControl(QStyle::CE_DockWidgetTitle, opt); +} + +void ColorInspector::mouseReleaseEvent(QMouseEvent*) +{ + + QSettings settings(PENCIL2D, PENCIL2D); + settings.setValue("colorOfSliders", mCurrentColor.rgba()); + } void ColorInspector::onModeChanged() { - bool newValue = ui->rgb->isChecked(); - if (isRgbColors == newValue) - { - return; - } + + // assume hsv if not checked + bool newValue = ui->rgbButton->isChecked(); + + QSettings settings(PENCIL2D, PENCIL2D); + settings.setValue("isRgb", newValue); + isRgbColors = newValue; noColorUpdate = true; if (isRgbColors) { - ui->red->setText(tr("Red")); - ui->green->setText(tr("Green")); - ui->blue->setText(tr("Blue")); - ui->alpha->setText(tr("Alpha")); + ui->red->setText("R"); + ui->green->setText("G"); + ui->blue->setText("B"); + ui->alpha->setText("A"); ui->RedspinBox->setRange(0,255); ui->RedspinBox->setSuffix(""); @@ -99,18 +212,39 @@ void ColorInspector::onModeChanged() ui->BluespinBox->setSuffix(""); ui->AlphaspinBox->setRange(0,255); ui->AlphaspinBox->setSuffix(""); - m_color = m_color.toRgb(); - ui->RedspinBox->setValue(m_color.red()); - ui->GreenspinBox->setValue(m_color.green()); - ui->BluespinBox->setValue(m_color.blue()); - ui->AlphaspinBox->setValue(m_color.alpha()); + mCurrentColor = mCurrentColor.toRgb(); + + ui->red_slider->setMax(255); + ui->red_slider->setColorType(ColorSlider::ColorType::RED); + ui->red_slider->setColorSpecType(ColorSlider::ColorSpecType::RGB); + ui->green_slider->setColorSpecType(ColorSlider::ColorSpecType::RGB); + ui->green_slider->setColorType(ColorSlider::ColorType::GREEN); + ui->blue_slider->setColorSpecType(ColorSlider::ColorSpecType::RGB); + ui->blue_slider->setColorType(ColorSlider::ColorType::BLUE); + ui->alpha_slider->setColorSpecType(ColorSlider::ColorSpecType::RGB); + ui->alpha_slider->setColorType(ColorSlider::ColorType::ALPHA); + + ui->RedspinBox->setValue(mCurrentColor.red()); + ui->GreenspinBox->setValue(mCurrentColor.green()); + ui->BluespinBox->setValue(mCurrentColor.blue()); + ui->AlphaspinBox->setValue(mCurrentColor.alpha()); } else { - ui->red->setText(tr("Hue")); - ui->green->setText(tr("Saturation")); - ui->blue->setText(tr("Value")); - ui->alpha->setText(tr("Alpha")); + ui->red->setText("H"); + ui->green->setText("S"); + ui->blue->setText("V"); + ui->alpha->setText("A"); + + ui->red_slider->setMax(359); + ui->red_slider->setColorType(ColorSlider::ColorType::HUE); + ui->red_slider->setColorSpecType(ColorSlider::ColorSpecType::HSV); + ui->green_slider->setColorType(ColorSlider::ColorType::SAT); + ui->green_slider->setColorSpecType(ColorSlider::ColorSpecType::HSV); + ui->blue_slider->setColorType(ColorSlider::ColorType::VAL); + ui->blue_slider->setColorSpecType(ColorSlider::ColorSpecType::HSV); + ui->alpha_slider->setColorType(ColorSlider::ColorType::ALPHA); + ui->alpha_slider->setColorSpecType(ColorSlider::ColorSpecType::HSV); ui->RedspinBox->setRange(0,359); ui->RedspinBox->setSuffix("°"); @@ -121,12 +255,14 @@ void ColorInspector::onModeChanged() ui->AlphaspinBox->setRange(0,100); ui->AlphaspinBox->setSuffix("%"); - m_color = m_color.toHsv(); - ui->RedspinBox->setValue(m_color.hue()); - ui->GreenspinBox->setValue(m_color.saturation()); - ui->BluespinBox->setValue(m_color.value()); - ui->AlphaspinBox->setValue(m_color.alpha()); + qreal bound = 100.0/255.0; // from 255 to 100 + mCurrentColor = mCurrentColor.toHsv(); + ui->RedspinBox->setValue(mCurrentColor.hsvHue()); + ui->GreenspinBox->setValue(qRound(mCurrentColor.hsvSaturation()*bound)); + ui->BluespinBox->setValue(qRound(mCurrentColor.value()*bound)); + ui->AlphaspinBox->setValue(qRound(mCurrentColor.alpha()*bound)); } + noColorUpdate = false; emit modeChange(isRgbColors); } @@ -137,18 +273,18 @@ void ColorInspector::onColorChanged() QColor c; if (isRgbColors) { - c = QColor::fromRgb( + c.setRgb( ui->RedspinBox->value(), ui->GreenspinBox->value(), ui->BluespinBox->value(), ui->AlphaspinBox->value()); } else { - c = QColor::fromHsv( + c.setHsv( ui->RedspinBox->value(), - ui->GreenspinBox->value() * 2.555, - ui->BluespinBox->value() * 2.555, - ui->AlphaspinBox->value() * 2.555); + ui->GreenspinBox->value()* 2.55, + ui->BluespinBox->value()* 2.55, + ui->AlphaspinBox->value()* 2.55); } emit colorChanged(c); diff --git a/app/src/colorinspector.h b/app/src/colorinspector.h index 137f88f6e..2f9898aba 100644 --- a/app/src/colorinspector.h +++ b/app/src/colorinspector.h @@ -16,20 +16,32 @@ GNU General Public License for more details. #ifndef COLORSPINBOXGROUP_H #define COLORSPINBOXGROUP_H -#include +#include +#include "basedockwidget.h" namespace Ui { class ColorInspector; } -class ColorInspector : public QWidget +class ColorInspector : public BaseDockWidget { Q_OBJECT + + friend class ColorSliders; public: + explicit ColorInspector(QWidget *parent = 0); ~ColorInspector(); QColor color(); + + void initUI() override; + void updateUI() override; + + +protected: + void paintEvent(QPaintEvent *) override; + void mouseReleaseEvent(QMouseEvent *) override; signals: void colorChanged(const QColor& c); void modeChange(const bool& isRgb); @@ -40,12 +52,14 @@ public slots: private slots: void onModeChanged(); void onColorChanged(); + void onSliderChanged(QColor color); private: + Ui::ColorInspector* ui = nullptr; bool isRgbColors = true; bool noColorUpdate = false; - QColor m_color; + QColor mCurrentColor; }; #endif // COLORSPINBOXGROUP_H diff --git a/app/src/colorpalettewidget.cpp b/app/src/colorpalettewidget.cpp index 301d2e2a9..39e18e313 100644 --- a/app/src/colorpalettewidget.cpp +++ b/app/src/colorpalettewidget.cpp @@ -22,6 +22,7 @@ GNU General Public License for more details. #include #include #include "ui_colorpalette.h" +#include "qtoolbar.h" #include "colordictionary.h" #include "colourref.h" @@ -62,6 +63,25 @@ void ColorPaletteWidget::initUI() else setGridMode(); + QColor savedColor; + savedColor.setRgba(settings.value("colorOfSliders").toUInt()); + + buttonStylesheet = "::menu-indicator{ image: none; }" + "QPushButton { border: 0px; }" + "QPushButton:pressed { border: 1px solid #ADADAD; border-radius: 2px; background-color: #D5D5D5; }" + "QPushButton:checked { border: 1px solid #ADADAD; border-radius: 2px; background-color: #D5D5D5; }"; + + + // color number need to be set to add new color to palette + // in cases where the last color was saved + // otherwise first color will be black. + editor()->color()->setColorNumber(0); + editor()->color()->setColor(savedColor); + + ui->addColorButton->setStyleSheet(buttonStylesheet); + ui->removeColorButton->setStyleSheet(buttonStylesheet); + ui->colorDialogButton->setStyleSheet(buttonStylesheet); + palettePreferences(); connect(ui->colorListWidget, &QListWidget::currentItemChanged, this, &ColorPaletteWidget::colorListCurrentItemChanged); @@ -70,6 +90,7 @@ void ColorPaletteWidget::initUI() connect(ui->colorListWidget, &QListWidget::currentTextChanged, this, &ColorPaletteWidget::onActiveColorNameChange); connect(ui->addColorButton, &QPushButton::clicked, this, &ColorPaletteWidget::clickAddColorButton); + connect(ui->colorDialogButton, &QPushButton::clicked, this, &ColorPaletteWidget::clickColorDialogButton); connect(ui->removeColorButton, &QPushButton::clicked, this, &ColorPaletteWidget::clickRemoveColorButton); } @@ -91,6 +112,7 @@ void ColorPaletteWidget::setColor(QColor newColor, int colorIndex) } } + void ColorPaletteWidget::selectColorNumber(int colorNumber) { ui->colorListWidget->setCurrentRow(colorNumber); @@ -202,7 +224,17 @@ void ColorPaletteWidget::palettePreferences() mSeparator = new QAction("", this); mSeparator->setSeparator(true); + buttonStylesheet = "::menu-indicator{ image: none; }" + "QToolButton { border: 0px; }" + "QToolButton:pressed { border: 1px solid #ADADAD; border-radius: 2px; background-color: #D5D5D5; }" + "QToolButton:checked { border: 1px solid #ADADAD; border-radius: 2px; background-color: #D5D5D5; }"; + + // Add to UI + ui->palettePref->setIcon(QIcon(":/app/icons/new/svg/more_options.svg")); + ui->palettePref->setIconSize(QSize(15,15)); + ui->palettePref->setArrowType(Qt::ArrowType::NoArrow); + ui->palettePref->setStyleSheet(buttonStylesheet); ui->palettePref->addAction(ui->listModeAction); ui->palettePref->addAction(ui->gridModeAction); ui->palettePref->addAction(mSeparator); @@ -379,16 +411,32 @@ QString ColorPaletteWidget::getDefaultColorName(QColor c) return nameDict[minLoc]; } +void ColorPaletteWidget::clickColorDialogButton() +{ + mIsColorDialog = true; + clickAddColorButton(); + mIsColorDialog = false; +} + void ColorPaletteWidget::clickAddColorButton() { QColor prevColor = Qt::white; - if (currentColourNumber() > -1) + if (editor()->object()->getLayer(editor()->currentLayerIndex())->type() == Layer::VECTOR) { - prevColor = editor()->object()->getColour(currentColourNumber()).colour; + if (currentColourNumber() > -1) + { + prevColor = editor()->object()->getColour(currentColourNumber()).colour; + } + } + + QColor newColour; + if (mIsColorDialog) { + newColour = QColorDialog::getColor(prevColor.rgba(), this, QString(), QColorDialog::ShowAlphaChannel); + } else { + newColour = editor()->color()->frontColor(); } - QColor newColour = QColorDialog::getColor(prevColor.rgba(), this, QString(), QColorDialog::ShowAlphaChannel); if (!newColour.isValid()) { // User canceled operation diff --git a/app/src/colorpalettewidget.h b/app/src/colorpalettewidget.h index 7386c5b29..19eb828d8 100644 --- a/app/src/colorpalettewidget.h +++ b/app/src/colorpalettewidget.h @@ -66,6 +66,7 @@ private slots: void changeColourName(QListWidgetItem*); void onActiveColorNameChange(QString name); void clickAddColorButton(); + void clickColorDialogButton(); void clickRemoveColorButton(); void palettePreferences(); void setListMode(); @@ -94,6 +95,10 @@ private slots: QMenu* mToolMenu = nullptr; int stepper = 0; + QString buttonStylesheet; + + bool mIsColorDialog = false; + }; #endif diff --git a/app/src/colorslider.cpp b/app/src/colorslider.cpp new file mode 100644 index 000000000..8d8134ea1 --- /dev/null +++ b/app/src/colorslider.cpp @@ -0,0 +1,401 @@ +#include "colorslider.h" + +#include +#include +#include +#include +#include +#include +#include + + +ColorSlider::ColorSlider(QWidget* parent) : QWidget(parent) +{ + +} + +ColorSlider::~ColorSlider() +{ + +} + +void ColorSlider::init(ColorType type, QColor color, qreal min, float max) +{ + init(type, color, min, max, QSize(this->size())); +} + +void ColorSlider::init(ColorType type, QColor color, qreal min, float max, QSize size) +{ + + mMin = min; + mMax = max; + mColor = color; + mColorType = type; + + drawColorBox(color, size); +} + +void ColorSlider::paintEvent(QPaintEvent *) +{ + QPainter painter(this); + + drawColorBox(mColor, mSize); + + painter.drawPixmap(0, 0, mBoxPixmapSource); + drawPicker(mColor); + painter.end(); + +} + + +void ColorSlider::resizeEvent(QResizeEvent *event) +{ + mSize = event->size(); + drawColorBox(mColor, event->size()); +} + +QLinearGradient ColorSlider::setColorSpec(QColor color) +{ + + if (mSpecType == ColorSpecType::HSV) + { + return hsvGradient(color); + } + else if (mSpecType == ColorSpecType::RGB) + { + return rgbGradient(color); + } +} + +QLinearGradient ColorSlider::rgbGradient(QColor color) +{ + int val = 0; + if (mColorType == ColorType::RED) + { + + for (; val < mMax; val += 1) + { + mGradient.setColorAt(val / mMax, QColor::fromRgb(val, + 255, + 255, + color.alpha())); + } + } + else if (mColorType == ColorType::GREEN) + { + + for (; val < mMax; val += 1) + { + mGradient.setColorAt(val / mMax, QColor::fromRgb(color.red(), + val, + color.blue(), + color.alpha())); + } + } + else if (mColorType == ColorType::BLUE) + { + for (; val < mMax; val += 1) + { + mGradient.setColorAt(val / mMax, QColor::fromRgb(color.red(), + color.green(), + val, + color.alpha())); + } + } + else if (mColorType == ColorType::ALPHA) + { + for (; val < mMax; val += 1) + { + mGradient.setColorAt(val / mMax, QColor::fromRgb(0, + 0, + 0, + val)); + } + } + return mGradient; +} + +QLinearGradient ColorSlider::hsvGradient(QColor color) +{ + int val = 0; + if (mColorType == ColorType::HUE) { + + for (; val < mMax; val += 1) + { + mGradient.setColorAt(val / mMax, QColor::fromHsv(val, + 255, + 255, + color.alpha())); + } + } + else if (mColorType == ColorType::SAT) + { + + for (; val < mMax; val += 1) + { + mGradient.setColorAt(val / mMax, QColor::fromHsv(color.hsvHue(), + val, + color.value(), + color.alpha())); + } + } + else if (mColorType == ColorType::VAL) + { + for (; val < mMax; val += 1) + { + mGradient.setColorAt(val / mMax, QColor::fromHsv(color.hsvHue(), + color.hsvSaturation(), + val, + color.alpha())); + } + } + else if (mColorType == ColorType::ALPHA) + { + for (; val < mMax; val += 1) + { + mGradient.setColorAt(val / mMax, QColor::fromHsv(0, + 0, + 0, + val)); + } + } + return mGradient; +} + +void ColorSlider::drawColorBox(QColor color, QSize size) +{ + QStyleOption option; + option.initFrom(this); + + QBrush backgroundBrush = option.palette.window(); + + mBoxPixmapSource = QPixmap(size); + + QPainter painter(&mBoxPixmapSource); + painter.setRenderHint(QPainter::Antialiasing); + + painter.fillRect(mBoxPixmapSource.rect(), backgroundBrush); + + mGradient = QLinearGradient(0,0,mBoxPixmapSource.width(),0); + mGradient = setColorSpec(color); + + painter.end(); + + // draw checkerboard background + painter.begin(&mBoxPixmapSource); + QBrush brush2(QBrush(QPixmap("://icons/new/checkerboard_smaller"))); + + painter.setBrush(brush2); + QPen pen2; + pen2.setWidthF(0); + pen2.setColor(Qt::gray); + pen2.setCosmetic(false); + painter.setPen(pen2); + painter.drawRoundedRect(0, + 0, + mBoxPixmapSource.width(), + mBoxPixmapSource.height(), + 4, + mBoxPixmapSource.width(), + Qt::SizeMode::AbsoluteSize); + + painter.end(); + + painter.begin(&mBoxPixmapSource); + painter.setRenderHint(QPainter::Antialiasing); + + QBrush brush(mGradient); + QPen pen; + pen.setWidthF(0); + pen.setColor(Qt::gray); + pen.setCosmetic(false); + painter.setPen(pen); + + + painter.setBrush(brush); + + painter.drawRoundedRect(0, + 0, + mBoxPixmapSource.width(), + mBoxPixmapSource.height(), + 4, + mBoxPixmapSource.width(), + Qt::SizeMode::AbsoluteSize); + painter.end(); +} + +void ColorSlider::mouseMoveEvent(QMouseEvent* event) +{ + colorPicked(event->pos()); +} + +void ColorSlider::mousePressEvent(QMouseEvent *event) +{ + colorPicked(event->pos()); + +} + +void ColorSlider::drawPicker(QColor color) +{ + QPainter painter(this); + qreal val = 0; + QSize mPickerSize = QSize(10, this->height()-1); + + QPen pen; + pen.setWidth(0); + pen.setColor(QColor(0,0,0,255)); + + if (mSpecType == ColorSpecType::HSV) { + if (mColorType == ColorType::HUE) + { + val = color.hsvHueF() * (mBoxPixmapSource.width()-mPickerSize.width()); + } + else if (mColorType == ColorType::SAT) + { + if ( (color.hsvSaturation() > 127 || color.value() < 127) && color.alpha() > 127) + { + pen.setColor(Qt::white); + } + val = color.hsvSaturationF() * (mBoxPixmapSource.width()-mPickerSize.width()); + } + else if (mColorType == ColorType::VAL) + { + if ( color.value() < 127 && color.alpha() > 127) + { + pen.setColor(Qt::white); + } + val = color.valueF() * (mBoxPixmapSource.width()-mPickerSize.width()); + } + } else if (mSpecType == ColorSpecType::RGB) { + if (mColorType == ColorType::RED) + { + val = color.redF() * (mBoxPixmapSource.width()-mPickerSize.width()); + } + else if (mColorType == ColorType::GREEN) + { + if ( color.alpha() > 127) + { + pen.setColor(Qt::white); + } + val = color.greenF() * (mBoxPixmapSource.width()-mPickerSize.width()); + } + else if (mColorType == ColorType::BLUE) + { + if (color.alpha() > 127) + { + pen.setColor(Qt::white); + } + val = color.blueF() * (mBoxPixmapSource.width()-mPickerSize.width()); + } + } + if (mColorType == ColorType::ALPHA) + { + if ( color.alpha() > 127) + { + pen.setColor(Qt::white); + } + val = color.alphaF() * (mBoxPixmapSource.width()-mPickerSize.width()); + } + + + painter.setPen(pen); + painter.drawRect(val, 0, mPickerSize.width(), mPickerSize.height()); + painter.end(); +} + +void ColorSlider::colorPicked(QPoint point) +{ + QColor colorPicked = mColor; + int colorMax = mMax; + int colorVal = 0; + + colorVal = point.x()*colorMax/mBoxPixmapSource.width(); + + colorVal = (colorVal > colorMax) ? colorMax : colorVal; + colorVal = (colorVal < 0) ? 0 : colorVal; + + if (mSpecType == ColorSpecType::HSV) { + switch(mColorType) + { + case ColorType::HUE: + { + colorPicked = QColor::fromHsv(colorVal, + mColor.hsvSaturation(), + mColor.value(), + mColor.alpha()); + + break; + } + case ColorType::SAT: + { + colorPicked = QColor::fromHsv(mColor.hsvHue(), + colorVal, + mColor.value(), + mColor.alpha()); + break; + } + case ColorType::VAL: + { + colorPicked = QColor::fromHsv(mColor.hsvHue(), + mColor.hsvSaturation(), + colorVal, + mColor.alpha()); + break; + } + case ColorType::ALPHA: + { + + colorPicked = QColor::fromHsv(mColor.hsvHue(), + mColor.hsvSaturation(), + mColor.value(), + colorVal); + break; + } + default: + break; + } + } else if (mSpecType == ColorSpecType::RGB) + { + switch(mColorType) + { + case ColorType::RED: + { + colorPicked = QColor::fromRgb(colorVal, + mColor.green(), + mColor.blue(), + mColor.alpha()); + + break; + } + case ColorType::GREEN: + { + colorPicked = QColor::fromRgb(mColor.red(), + colorVal, + mColor.blue(), + mColor.alpha()); + break; + } + case ColorType::BLUE: + { + colorPicked = QColor::fromRgb(mColor.red(), + mColor.green(), + colorVal, + mColor.alpha()); + break; + } + case ColorType::ALPHA: + { + + colorPicked = QColor::fromRgb(mColor.red(), + mColor.green(), + mColor.blue(), + colorVal); + break; + } + default: + break; + } + } + mColor = colorPicked; + emit valueChanged(mColor); +} diff --git a/app/src/colorslider.h b/app/src/colorslider.h new file mode 100644 index 000000000..310d83f7e --- /dev/null +++ b/app/src/colorslider.h @@ -0,0 +1,92 @@ +#ifndef COLORSLIDER_H +#define COLORSLIDER_H + +#include + + +class ColorSlider : public QWidget +{ + Q_OBJECT +public: + + enum ColorType { + HUE, + SAT, + VAL, + RED, + GREEN, + BLUE, + ALPHA + }; + enum ColorSpecType { + RGB, + HSV, + HSL, + CMYK + }; + + explicit ColorSlider(QWidget* parent); + ~ColorSlider(); + + void init(ColorType type, QColor color, qreal min, float max); + void init(ColorType type, QColor color, qreal min, float max, QSize size); + + QLinearGradient setColorSpec(QColor color); + + QColor color() { return mColor; } + + void setHsv(QColor hsv) { mColor.setHsv(hsv.hsvHue(), + hsv.hsvSaturation(), + hsv.value(), + hsv.alpha()); + } + + void setRgb(QColor rgb) { mColor.setRgb(rgb.red(), + rgb.green(), + rgb.blue(), + rgb.alpha()); + } + + void setColorSpecType(ColorSpecType newType) { this->mSpecType = newType; } + void setColorType(ColorType newType) { this->mColorType = newType; } + + void setMin(float min) { mMin = min; } + void setMax(float max) { mMax = max; } + +protected: + void paintEvent(QPaintEvent* event) override; + void resizeEvent(QResizeEvent* event) override; + void mouseMoveEvent(QMouseEvent* event) override; + void mousePressEvent(QMouseEvent* event) override; + +//public slots: + +signals: + void valueChanged(QColor color); +// void valueChanged(QColor color); + +private: + + void drawColorBox(QColor color, QSize size); + void drawPicker(QColor color); + QLinearGradient hsvGradient(QColor color); + QLinearGradient rgbGradient(QColor color); + + void colorPicked(QPoint point); + + QPixmap mBoxPixmapTarget; + QPixmap mBoxPixmapSource; + + QColor mColor; + float mMin = 0.0; + float mMax = 0.0; + + ColorType mColorType; + ColorSpecType mSpecType; + + QSize mSize = QSize(0,0); + + QLinearGradient mGradient; +}; + +#endif // COLORSLIDER_H diff --git a/app/src/colorwheel.cpp b/app/src/colorwheel.cpp index 3139391b1..8ef1ccb81 100644 --- a/app/src/colorwheel.cpp +++ b/app/src/colorwheel.cpp @@ -14,18 +14,23 @@ GNU General Public License for more details. */ -#include +#include #include #include #include +#include #include +#include #include #include +#include "qsettings.h" +#include "pencildef.h" #include "colorwheel.h" ColorWheel::ColorWheel(QWidget* parent) : QWidget(parent) { + setWindowTitle(tr("Color Wheel", "Color Wheel's window title")); mCurrentColor = mCurrentColor.toHsv(); setMinimumHeight(100); } @@ -65,8 +70,10 @@ void ColorWheel::setColor(const QColor& color) changeRgbColors(color); else if (color.spec() == QColor::Spec::Hsv) changeHsvColors(color); - else + else { + qDebug() << color.spec(); Q_ASSERT(false); + } drawSquareImage(color.hue()); @@ -225,6 +232,8 @@ void ColorWheel::mouseMoveEvent(QMouseEvent* event) void ColorWheel::mouseReleaseEvent(QMouseEvent *) { + QSettings settings(PENCIL2D, PENCIL2D); + settings.setValue("colorOfSliders", mCurrentColor.rgba()); mIsInWheel = false; mIsInSquare = false; emit colorSelected(mCurrentColor); @@ -236,18 +245,24 @@ void ColorWheel::resizeEvent(QResizeEvent* event) mWheelPixmap.fill(palette().background().color()); drawWheelImage(event->size()); drawSquareImage(mCurrentColor.hue()); + update(); } void ColorWheel::paintEvent(QPaintEvent*) { - QPainter painter(this); + + QPainter painter; + + painter.begin(this); QStyleOption opt; opt.initFrom(this); + composeWheel(mWheelPixmap); painter.translate(width() / 2, height() / 2); painter.translate(-mWheelPixmap.width() / 2, -mWheelPixmap.height() / 2); painter.drawPixmap(0, 0, mWheelPixmap); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this); } @@ -312,17 +327,23 @@ void ColorWheel::drawSquareImage(const int &hue) qreal m1 = (width() / 2) - (ir / qSqrt(2)); qreal m2 = (height() / 2) - (ir / qSqrt(2)); - QImage square(255, 255, QImage::Format_ARGB32_Premultiplied); + QImage square(255, 255, QImage::Format_ARGB32); - for (int i = 0; i < 255; ++i) - { - for (int j = 0; j < 255; ++j) - { - QColor color = QColor::fromHsv(hue, i, 255 - j); - QRgb rgb = qRgb(color.red(), color.green(), color.blue()); - square.setPixel(i, j, rgb); - } - } + QLinearGradient colorGradient = QLinearGradient(0, 0, square.width(), 0); + colorGradient.setColorAt(0, QColor(255,255,255)); + colorGradient.setColorAt(1, QColor::fromHsv(color().hsvHue(), color().hsvSaturation(), color().value())); + + QLinearGradient blackGradient = QLinearGradient(0, 0, 0, square.height()); + blackGradient.setColorAt(0, QColor(0,0,0,0)); + blackGradient.setColorAt(1, QColor(0,0,0,255)); + + QBrush colorGradiantBrush = QBrush(colorGradient); + QBrush blackGradiantBrush = QBrush(blackGradient); + + QPainter painter(&square); + + painter.fillRect(square.rect(), colorGradiantBrush); + painter.fillRect(square.rect(), blackGradiantBrush); qreal SquareWidth = 2 * ir / qSqrt(2.1); mSquareImage = square.scaled(SquareWidth, SquareWidth); @@ -358,25 +379,28 @@ void ColorWheel::drawPicker(const QColor& color) { QPainter painter(&mWheelPixmap); painter.setRenderHint(QPainter::Antialiasing); + int ellipseSize = 7; - QPoint squareTopLeft = mSquareRegion.boundingRect().topLeft(); + QPoint squareTopLeft = mSquareRegion.boundingRect().topLeft()-QPoint(1,1); - painter.translate(squareTopLeft.x(), squareTopLeft.y()); + QSize squareSize = mSquareRegion.boundingRect().size()*1.01; - QSize squareSize = mSquareRegion.boundingRect().size(); - - qreal S = color.saturationF() * squareSize.width(); - qreal V = squareSize.height() - (color.valueF() * squareSize.height()); + qreal S = color.hsvSaturationF() * (squareSize.width()); + qreal V = (squareSize.height() - (color.valueF() * (squareSize.height()))); QPen pen; - pen.setWidth(3); - if (color.saturation() > 30 || color.value() < 50) + pen.setWidth(1); + if (color.hsvSaturation() > 30 || color.value() < 50) { pen.setColor(Qt::white); } painter.setPen(pen); - painter.drawEllipse(S - 2, V - 2, 10, 10); + QTransform transform; + transform.translate(-ellipseSize/2,-ellipseSize/2); + transform.translate(squareTopLeft.x()+2,squareTopLeft.y()+2); + painter.setTransform(transform); + painter.drawEllipse(S, V, ellipseSize, ellipseSize); } void ColorWheel::composeWheel(QPixmap& pixmap) @@ -387,7 +411,7 @@ void ColorWheel::composeWheel(QPixmap& pixmap) composePainter.translate(-mSquareImage.width() / 2, -mSquareImage.height() / 2); //move to center of image composePainter.drawImage(0, 0, mSquareImage); composePainter.end(); - drawHueIndicator(mCurrentColor.hue()); + drawHueIndicator(mCurrentColor.hsvHue()); drawPicker(mCurrentColor); } @@ -449,7 +473,7 @@ void ColorWheel::hueChanged(const int &hue) { return; } - int s = mCurrentColor.saturation(); + int s = mCurrentColor.hsvSaturation(); int v = mCurrentColor.value(); int a = mCurrentColor.alpha(); @@ -468,7 +492,7 @@ void ColorWheel::hueChanged(const int &hue) void ColorWheel::saturationChanged(const int &sat) { - int hue = mCurrentColor.hue(); + int hue = mCurrentColor.hsvHue(); int value = mCurrentColor.value(); int alpha = mCurrentColor.alpha(); @@ -480,8 +504,8 @@ void ColorWheel::saturationChanged(const int &sat) void ColorWheel::valueChanged(const int &value) { - int hue = mCurrentColor.hue(); - int sat = mCurrentColor.saturation(); + int hue = mCurrentColor.hsvHue(); + int sat = mCurrentColor.hsvSaturation(); int alpha = mCurrentColor.alpha(); mCurrentColor.setHsv(hue, sat, value, alpha); diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index 364e6b36b..b7047b044 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -54,6 +54,7 @@ GNU General Public License for more details. // app headers #include "scribblearea.h" #include "colorbox.h" +#include "colorinspector.h" #include "colorpalettewidget.h" #include "displayoptionwidget.h" #include "tooloptionwidget.h" @@ -141,9 +142,13 @@ void MainWindow2::createDockWidgets() mTimeLine = new TimeLine(this); mTimeLine->setObjectName("TimeLine"); - mColorWheel = new ColorBox(this); - mColorWheel->setToolTip(tr("color palette:
use (C)
toggle at cursor")); - mColorWheel->setObjectName("ColorWheel"); + mColorBox = new ColorBox(this); + mColorBox->setToolTip(tr("color palette:
use (C)
toggle at cursor")); + mColorBox->setObjectName("ColorWheel"); + + mColorInspector = new ColorInspector(this); + mColorInspector->setToolTip(tr("Color inspector")); + mColorInspector->setObjectName("Color Inspector"); mColorPalette = new ColorPaletteWidget(this); mColorPalette->setObjectName("ColorPalette"); @@ -165,12 +170,14 @@ void MainWindow2::createDockWidgets() mDockWidgets << mTimeLine - << mColorWheel + << mColorBox + << mColorInspector << mColorPalette << mDisplayOptionWidget << mToolOptions << mToolBox; +// mColorInspector->setFloating(true); mStartIcon = QIcon(":icons/controls/play.png"); mStopIcon = QIcon(":icons/controls/stop.png"); @@ -186,12 +193,13 @@ void MainWindow2::createDockWidgets() qDebug() << "Init Dock widget: " << pWidget->objectName(); } - addDockWidget(Qt::RightDockWidgetArea, mColorWheel); + addDockWidget(Qt::RightDockWidgetArea, mColorBox); addDockWidget(Qt::RightDockWidgetArea, mColorPalette); addDockWidget(Qt::RightDockWidgetArea, mDisplayOptionWidget); addDockWidget(Qt::LeftDockWidgetArea, mToolBox); addDockWidget(Qt::LeftDockWidgetArea, mToolOptions); addDockWidget(Qt::BottomDockWidgetArea, mTimeLine); +// addDockWidget(Qt::LeftDockWidgetArea, mColorInspector); setDockNestingEnabled(true); //addDockWidget( Qt::BottomDockWidgetArea, mTimeline2); @@ -205,7 +213,8 @@ void MainWindow2::createDockWidgets() makeConnections(mEditor); makeConnections(mEditor, mTimeLine); - makeConnections(mEditor, mColorWheel); + makeConnections(mEditor, mColorBox); + makeConnections(mEditor, mColorInspector); makeConnections(mEditor, mColorPalette); makeConnections(mEditor, mToolOptions); @@ -324,7 +333,7 @@ void MainWindow2::createMenus() { mToolBox->toggleViewAction(), mToolOptions->toggleViewAction(), - mColorWheel->toggleViewAction(), + mColorBox->toggleViewAction(), mColorPalette->toggleViewAction(), mTimeLine->toggleViewAction(), mDisplayOptionWidget->toggleViewAction() @@ -791,7 +800,7 @@ void MainWindow2::lockWidgets(bool shouldLock) { QDockWidget::DockWidgetFeature feat = shouldLock ? QDockWidget::DockWidgetClosable : QDockWidget::AllDockWidgetFeatures; - mColorWheel->setFeatures(feat); + mColorBox->setFeatures(feat); mColorPalette->setFeatures(feat); mDisplayOptionWidget->setFeatures(feat); mToolOptions->setFeatures(feat); @@ -958,7 +967,7 @@ void MainWindow2::setupKeyboardShortcuts() mToolBox->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_TOOLBOX)); mToolOptions->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_TOOL_OPTIONS)); - mColorWheel->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_COLOR_WHEEL)); + mColorBox->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_COLOR_WHEEL)); mColorPalette->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_COLOR_LIBRARY)); mTimeLine->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_TIMELINE)); mDisplayOptionWidget->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_DISPLAY_OPTIONS)); @@ -1044,6 +1053,12 @@ void MainWindow2::makeConnections(Editor* editor, ColorBox* colorBox) connect(editor->color(), &ColorManager::colorChanged, colorBox, &ColorBox::setColor); } +void MainWindow2::makeConnections(Editor* editor, ColorInspector* colorInspector) +{ + connect(colorInspector, &ColorInspector::colorChanged, editor->color(), &ColorManager::setColor); + connect(editor->color(), &ColorManager::colorChanged, colorInspector, &ColorInspector::setColor); +} + void MainWindow2::makeConnections(Editor* editor, ScribbleArea* scribbleArea) { connect(editor->tools(), &ToolManager::toolChanged, scribbleArea, &ScribbleArea::setCurrentTool); diff --git a/app/src/mainwindow2.h b/app/src/mainwindow2.h index 6933c0efc..cba5e3f26 100644 --- a/app/src/mainwindow2.h +++ b/app/src/mainwindow2.h @@ -36,6 +36,7 @@ class ToolBoxWidget; class PreferencesDialog; class PreviewWidget; class ColorBox; +class ColorInspector; class RecentFileMenu; class Timeline2; class ActionCommands; @@ -117,7 +118,8 @@ private slots: void changePlayState(bool isPlaying); void makeConnections(Editor*); - void makeConnections(Editor*, ColorBox*); + void makeConnections(Editor*, ColorBox* colorBox); + void makeConnections(Editor*, ColorInspector*); void makeConnections(Editor*, ScribbleArea*); void makeConnections(Editor*, ColorPaletteWidget*); void makeConnections(Editor*, TimeLine*); @@ -127,7 +129,7 @@ private slots: void bindActionWithSetting(QAction*, SETTING); // UI: Dock widgets - ColorBox* mColorWheel = nullptr; + ColorBox* mColorBox = nullptr; ColorPaletteWidget* mColorPalette = nullptr; DisplayOptionWidget* mDisplayOptionWidget = nullptr; ToolOptionWidget* mToolOptions = nullptr; @@ -137,6 +139,7 @@ private slots: PreferencesDialog* mPrefDialog = nullptr; //PreviewWidget* mPreview = nullptr; TimeLine* mTimeLine = nullptr; // be public temporary + ColorInspector* mColorInspector = nullptr; // backup BackupElement* mBackupAtSave = nullptr; diff --git a/app/ui/colorinspector.ui b/app/ui/colorinspector.ui index 904581966..1ca70e96a 100644 --- a/app/ui/colorinspector.ui +++ b/app/ui/colorinspector.ui @@ -7,8 +7,8 @@ 0 0 - 114 - 152 + 301 + 162 @@ -22,7 +22,7 @@ 2 - 2 + 5 2 @@ -38,53 +38,170 @@ 2 + + 0 + - + + + + 0 + 0 + + + + + 40 + 0 + + + + + 40 + 20 + + HSV + + + 16 + 16 + + + + true + - + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 5 + 20 + + + + + + + + + 0 + 0 + + + + + 40 + 0 + + + + + 40 + 20 + + RGB - + true + + false + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + - 2 + 0 + + + 0 + 0 + + - Red + R + + + 2 - - - - 255 + + + + A + + + 2 - Green + G + + + 2 - + + + + + 60 + 16777215 + + + + 255 + + + + + + + 60 + 16777215 + + 255 @@ -93,31 +210,172 @@ - Blue + B + + + 2 - - + + + + + 60 + 16777215 + + 255 - - - - Alpha + + + + + 16777215 + 10 + + + + 5 + + + 5 + + + 5 + + + 5 + + + 5 + + - + + + + 60 + 16777215 + + 255 + + + + + 16777215 + 10 + + + + + 5 + + + 5 + + + 5 + + + 5 + + + 5 + + + + + + + + + 16777215 + 10 + + + + + 5 + + + 5 + + + 5 + + + 5 + + + 5 + + + + + + + + + 0 + 0 + + + + + 0 + 10 + + + + + 16777215 + 10 + + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 5 + 20 + + + + @@ -162,9 +420,15 @@ + + + ColorSlider + QWidget +

colorslider.h
+ 1 + + - hsv - rgb RedspinBox GreenspinBox BluespinBox diff --git a/app/ui/colorpalette.ui b/app/ui/colorpalette.ui index 4614f1d97..8c0cf4880 100644 --- a/app/ui/colorpalette.ui +++ b/app/ui/colorpalette.ui @@ -2,18 +2,18 @@ ColorPalette + + + 0 + 0 + 268 + 241 + + Color Palette - - - 0 - 0 - 246 - 337 - - 1 @@ -87,6 +87,69 @@
+ + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 20 + + + + + + + + + 0 + 0 + + + + + 16 + 16 + + + + + 20 + 20 + + + + + 20 + 20 + + + + Native color dialog window + + + + + + + :/app/icons/new/svg/color-dialog.svg:/app/icons/new/svg/color-dialog.svg + + + + 16 + 16 + + + + true + + + @@ -115,12 +178,16 @@ -1 - ... + + + + + :/app/icons/new/svg/more_options.svg:/app/icons/new/svg/more_options.svg 15 - 10 + 15 diff --git a/core_lib/src/managers/colormanager.cpp b/core_lib/src/managers/colormanager.cpp index 126f54bd8..2eb522091 100644 --- a/core_lib/src/managers/colormanager.cpp +++ b/core_lib/src/managers/colormanager.cpp @@ -59,6 +59,7 @@ void ColorManager::workingLayerChanged(Layer* layer) QColor ColorManager::frontColor() { + if (mIsWorkingOnVectorLayer) return object()->getColour(mCurrentColorIndex).colour; else @@ -72,6 +73,7 @@ void ColorManager::setColorNumber(int n) mCurrentColorIndex = n; QColor currentColor = object()->getColour(mCurrentColorIndex).colour; + emit colorNumberChanged(mCurrentColorIndex); emit colorChanged(currentColor, mCurrentColorIndex); } @@ -81,11 +83,13 @@ void ColorManager::setColor(const QColor& newColor) if (mCurrentFrontColor != newColor) { mCurrentFrontColor = newColor; - - if ( mIsWorkingOnVectorLayer ) - object()->setColour(mCurrentColorIndex, newColor); - emit colorChanged(newColor, (mIsWorkingOnVectorLayer) ? mCurrentColorIndex : -1); + emit colorChanged(mCurrentFrontColor, mCurrentColorIndex); + + if (mIsWorkingOnVectorLayer) + { + object()->setColour(mCurrentColorIndex, newColor); + } } } From 1415a016812540e880a4538eca87c26b0d5a6c7a Mon Sep 17 00:00:00 2001 From: CandyFace Date: Wed, 16 May 2018 19:27:42 +0200 Subject: [PATCH 035/184] Use loadcolor instead of qsettings --- app/src/colorbox.cpp | 22 +++++++++++++++------- app/src/colorbox.h | 3 +++ app/src/colorwheel.cpp | 3 --- app/src/mainwindow2.cpp | 1 + core_lib/src/managers/colormanager.cpp | 3 +++ core_lib/src/managers/colormanager.h | 1 + 6 files changed, 23 insertions(+), 10 deletions(-) diff --git a/app/src/colorbox.cpp b/app/src/colorbox.cpp index 16c9b3b20..d0fab3e93 100644 --- a/app/src/colorbox.cpp +++ b/app/src/colorbox.cpp @@ -18,7 +18,6 @@ GNU General Public License for more details. #include "colorwheel.h" #include "colorinspector.h" #include "colorbox.h" -#include "qsettings.h" #include "pencildef.h" ColorBox::ColorBox( QWidget* parent ) : BaseDockWidget( parent ) @@ -38,7 +37,6 @@ ColorBox::ColorBox( QWidget* parent ) : BaseDockWidget( parent ) connect(mColorWheel, &ColorWheel::colorChanged, this, &ColorBox::onWheelMove); connect(mColorWheel, &ColorWheel::colorSelected, this, &ColorBox::onWheelRelease); -// connect(this, &ColorBox::colorChanged, mColorWheel, &ColorWheel::setColor); } ColorBox::~ColorBox() @@ -47,15 +45,11 @@ ColorBox::~ColorBox() void ColorBox::initUI() { - QSettings settings(PENCIL2D, PENCIL2D); - - QColor savedColor; - savedColor.setRgba(settings.value("colorOfSliders").toUInt()); - setColor(savedColor); } void ColorBox::updateUI() { + mColorLoaded = true; } QColor ColorBox::color() @@ -63,8 +57,22 @@ QColor ColorBox::color() return mColorWheel->color(); } +/** + * @brief ColorBox::loadColor + * + * This value is only to be used once + * for further color modifications, use setColor + */ +void ColorBox::loadColor(const QColor& color) +{ + mColorLoaded = false; + mColorWheel->setColor(color); +} + void ColorBox::setColor(const QColor& newColor) { + if (!mColorLoaded) { return; } + if ( newColor != mColorWheel->color() ) { mColorWheel->setColor(newColor); diff --git a/app/src/colorbox.h b/app/src/colorbox.h index 3bcc2f890..0dca261be 100644 --- a/app/src/colorbox.h +++ b/app/src/colorbox.h @@ -33,6 +33,7 @@ class ColorBox : public BaseDockWidget QColor color(); void setColor(const QColor&); + void loadColor(const QColor&); Q_SIGNALS: void colorChanged(const QColor&); @@ -42,6 +43,8 @@ class ColorBox : public BaseDockWidget void onWheelRelease(const QColor&); ColorWheel* mColorWheel = nullptr; + + bool mColorLoaded = false; // ColorInspector* mColorInspector = nullptr; }; diff --git a/app/src/colorwheel.cpp b/app/src/colorwheel.cpp index 8ef1ccb81..787a0218c 100644 --- a/app/src/colorwheel.cpp +++ b/app/src/colorwheel.cpp @@ -23,7 +23,6 @@ GNU General Public License for more details. #include #include #include -#include "qsettings.h" #include "pencildef.h" #include "colorwheel.h" @@ -232,8 +231,6 @@ void ColorWheel::mouseMoveEvent(QMouseEvent* event) void ColorWheel::mouseReleaseEvent(QMouseEvent *) { - QSettings settings(PENCIL2D, PENCIL2D); - settings.setValue("colorOfSliders", mCurrentColor.rgba()); mIsInWheel = false; mIsInSquare = false; emit colorSelected(mCurrentColor); diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index 34d5f21b2..dde469362 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -1052,6 +1052,7 @@ void MainWindow2::makeConnections(Editor* editor, ColorBox* colorBox) { connect(colorBox, &ColorBox::colorChanged, editor->color(), &ColorManager::setColor); connect(editor->color(), &ColorManager::colorChanged, colorBox, &ColorBox::setColor); + connect(editor->color(), &ColorManager::colorLoaded, colorBox, &ColorBox::loadColor); } void MainWindow2::makeConnections(Editor* editor, ColorInspector* colorInspector) diff --git a/core_lib/src/managers/colormanager.cpp b/core_lib/src/managers/colormanager.cpp index 2eb522091..7a8464736 100644 --- a/core_lib/src/managers/colormanager.cpp +++ b/core_lib/src/managers/colormanager.cpp @@ -38,6 +38,9 @@ Status ColorManager::load(Object* o) { mCurrentColorIndex = 0; mCurrentFrontColor = o->data()->getCurrentColor(); + + emit colorLoaded(mCurrentFrontColor); + return Status::OK; } diff --git a/core_lib/src/managers/colormanager.h b/core_lib/src/managers/colormanager.h index 6a7942e23..e60ea2515 100644 --- a/core_lib/src/managers/colormanager.h +++ b/core_lib/src/managers/colormanager.h @@ -43,6 +43,7 @@ class ColorManager : public BaseManager Q_SIGNALS: void colorChanged(QColor, int); // new color and color index void colorNumberChanged(int); + void colorLoaded(QColor); private: QColor mCurrentFrontColor{ 33, 33, 33 }; From c9423c532a7612e9e73c62cc7b8bb1866b7871d2 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Thu, 17 May 2018 10:57:58 +1000 Subject: [PATCH 036/184] Compare the new color and current color under the same color spec --- app/src/colorinspector.cpp | 6 ++++-- app/src/colorinspector.h | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/colorinspector.cpp b/app/src/colorinspector.cpp index 752f96c51..38213b7f6 100644 --- a/app/src/colorinspector.cpp +++ b/app/src/colorinspector.cpp @@ -113,8 +113,11 @@ void ColorInspector::onSliderChanged(QColor color) emit colorChanged(color); } -void ColorInspector::setColor(const QColor &newColor) +void ColorInspector::setColor(QColor newColor) { + // compare under the same color spec + newColor = (isRgbColors) ? newColor.toRgb() : newColor.toHsv(); + if (newColor == mCurrentColor) { return; @@ -187,7 +190,6 @@ void ColorInspector::mouseReleaseEvent(QMouseEvent*) void ColorInspector::onModeChanged() { - // assume hsv if not checked bool newValue = ui->rgbButton->isChecked(); diff --git a/app/src/colorinspector.h b/app/src/colorinspector.h index 2f9898aba..5b81109e4 100644 --- a/app/src/colorinspector.h +++ b/app/src/colorinspector.h @@ -47,7 +47,7 @@ class ColorInspector : public BaseDockWidget void modeChange(const bool& isRgb); public slots: - void setColor(const QColor &c); + void setColor(QColor newColor); private slots: void onModeChanged(); From ed25cfbc8d19966cd0a3f48fae83b40aa43c20a5 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Thu, 17 May 2018 12:17:16 +1000 Subject: [PATCH 037/184] Block signals when updating UI components to avoid unwanted signal emitting - ex. Spinboxes may emit valueChanged when setting a new range, end up sending a invalid color value --- app/src/colorinspector.cpp | 46 +++++++++++++++++++++++++++++++------- app/src/colorinspector.h | 1 - 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/app/src/colorinspector.cpp b/app/src/colorinspector.cpp index 38213b7f6..e6266f481 100644 --- a/app/src/colorinspector.cpp +++ b/app/src/colorinspector.cpp @@ -24,6 +24,7 @@ GNU General Public License for more details. #include "colorslider.h" #include "pencildef.h" + ColorInspector::ColorInspector(QWidget *parent) : BaseDockWidget(parent) { @@ -97,7 +98,6 @@ void ColorInspector::updateUI() void ColorInspector::onSliderChanged(QColor color) { - if (isRgbColors) { ui->red_slider->setRgb(color); ui->green_slider->setRgb(color); @@ -122,16 +122,25 @@ void ColorInspector::setColor(QColor newColor) { return; } - noColorUpdate = true; qDebug() << "set color"; if(isRgbColors) { + QSignalBlocker b1(ui->red_slider); + QSignalBlocker b2(ui->green_slider); + QSignalBlocker b3(ui->blue_slider); + QSignalBlocker b4(ui->alpha_slider); + ui->red_slider->setRgb(newColor); ui->green_slider->setRgb(newColor); ui->blue_slider->setRgb(newColor); ui->alpha_slider->setRgb(newColor); + QSignalBlocker b5(ui->RedspinBox); + QSignalBlocker b6(ui->GreenspinBox); + QSignalBlocker b7(ui->BluespinBox); + QSignalBlocker b8(ui->AlphaspinBox); + ui->RedspinBox->setValue(newColor.red()); ui->GreenspinBox->setValue(newColor.green()); ui->BluespinBox->setValue(newColor.blue()); @@ -139,11 +148,21 @@ void ColorInspector::setColor(QColor newColor) } else { + QSignalBlocker b1(ui->red_slider); + QSignalBlocker b2(ui->green_slider); + QSignalBlocker b3(ui->blue_slider); + QSignalBlocker b4(ui->alpha_slider); + ui->red_slider->setHsv(newColor); ui->green_slider->setHsv(newColor); ui->blue_slider->setHsv(newColor); ui->alpha_slider->setHsv(newColor); + QSignalBlocker b5(ui->RedspinBox); + QSignalBlocker b6(ui->GreenspinBox); + QSignalBlocker b7(ui->BluespinBox); + QSignalBlocker b8(ui->AlphaspinBox); + ui->RedspinBox->setValue(newColor.hsvHue()); ui->GreenspinBox->setValue(qRound(newColor.hsvSaturation() / 2.55)); ui->BluespinBox->setValue(qRound(newColor.value() / 2.55)); @@ -157,7 +176,7 @@ void ColorInspector::setColor(QColor newColor) p2.setColor(QPalette::Background, mCurrentColor); ui->colorWrapper->setPalette(p1); ui->color->setPalette(p2); - noColorUpdate = false; + update(); } @@ -197,10 +216,16 @@ void ColorInspector::onModeChanged() settings.setValue("isRgb", newValue); isRgbColors = newValue; - noColorUpdate = true; if (isRgbColors) { + // Spinboxes may emit unwanted valueChanged signals when setting ranges + // so block them all first + QSignalBlocker b1(ui->RedspinBox); + QSignalBlocker b2(ui->GreenspinBox); + QSignalBlocker b3(ui->BluespinBox); + QSignalBlocker b4(ui->AlphaspinBox); + ui->red->setText("R"); ui->green->setText("G"); ui->blue->setText("B"); @@ -214,6 +239,7 @@ void ColorInspector::onModeChanged() ui->BluespinBox->setSuffix(""); ui->AlphaspinBox->setRange(0,255); ui->AlphaspinBox->setSuffix(""); + mCurrentColor = mCurrentColor.toRgb(); ui->red_slider->setMax(255); @@ -233,6 +259,11 @@ void ColorInspector::onModeChanged() } else { + QSignalBlocker b1(ui->RedspinBox); + QSignalBlocker b2(ui->GreenspinBox); + QSignalBlocker b3(ui->BluespinBox); + QSignalBlocker b4(ui->AlphaspinBox); + ui->red->setText("H"); ui->green->setText("S"); ui->blue->setText("V"); @@ -257,22 +288,21 @@ void ColorInspector::onModeChanged() ui->AlphaspinBox->setRange(0,100); ui->AlphaspinBox->setSuffix("%"); - qreal bound = 100.0/255.0; // from 255 to 100 mCurrentColor = mCurrentColor.toHsv(); + + const qreal bound = 100.0 / 255.0; // from 255 to 100 + ui->RedspinBox->setValue(mCurrentColor.hsvHue()); ui->GreenspinBox->setValue(qRound(mCurrentColor.hsvSaturation()*bound)); ui->BluespinBox->setValue(qRound(mCurrentColor.value()*bound)); ui->AlphaspinBox->setValue(qRound(mCurrentColor.alpha()*bound)); } - noColorUpdate = false; emit modeChange(isRgbColors); } void ColorInspector::onColorChanged() { - if(noColorUpdate) return; - QColor c; if (isRgbColors) { c.setRgb( diff --git a/app/src/colorinspector.h b/app/src/colorinspector.h index 5b81109e4..735f2580c 100644 --- a/app/src/colorinspector.h +++ b/app/src/colorinspector.h @@ -58,7 +58,6 @@ private slots: Ui::ColorInspector* ui = nullptr; bool isRgbColors = true; - bool noColorUpdate = false; QColor mCurrentColor; }; From d31eb9ff0077a0990038c638a949faebe42e9014 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Thu, 17 May 2018 00:03:18 -0600 Subject: [PATCH 038/184] Remove oldColor argument of floodFill, since it isn't used --- core_lib/src/graphics/bitmap/bitmapimage.cpp | 6 +----- core_lib/src/graphics/bitmap/bitmapimage.h | 2 +- core_lib/src/tool/buckettool.cpp | 1 - 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/core_lib/src/graphics/bitmap/bitmapimage.cpp b/core_lib/src/graphics/bitmap/bitmapimage.cpp index 37aa2d3be..07bbe8e05 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.cpp +++ b/core_lib/src/graphics/bitmap/bitmapimage.cpp @@ -563,14 +563,10 @@ bool BitmapImage::compareColor(QRgb color1, QRgb color2, int tolerance) void BitmapImage::floodFill(BitmapImage* targetImage, QRect cameraRect, QPoint point, - QRgb oldColor, QRgb newColor, int tolerance) { - if (oldColor == newColor) - return; - - oldColor = targetImage->pixel(point); + QRgb oldColor = targetImage->pixel(point); oldColor = qRgba(qRed(oldColor), qGreen(oldColor), qBlue(oldColor), qAlpha(oldColor)); // Preparations diff --git a/core_lib/src/graphics/bitmap/bitmapimage.h b/core_lib/src/graphics/bitmap/bitmapimage.h index ddeb7bbd0..66c633502 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.h +++ b/core_lib/src/graphics/bitmap/bitmapimage.h @@ -75,7 +75,7 @@ class BitmapImage : public KeyFrame void clear(QRectF rectangle) { clear(rectangle.toRect()); } static bool compareColor(QRgb color1, QRgb color2, int tolerance); - static void floodFill(BitmapImage* targetImage, QRect cameraRect, QPoint point, QRgb oldColor, QRgb newColor, int tolerance); + static void floodFill(BitmapImage* targetImage, QRect cameraRect, QPoint point, QRgb newColor, int tolerance); void drawLine(QPointF P1, QPointF P2, QPen pen, QPainter::CompositionMode cm, bool antialiasing); void drawRect(QRectF rectangle, QPen pen, QBrush brush, QPainter::CompositionMode cm, bool antialiasing); diff --git a/core_lib/src/tool/buckettool.cpp b/core_lib/src/tool/buckettool.cpp index ec6db74d6..4fb4437cd 100644 --- a/core_lib/src/tool/buckettool.cpp +++ b/core_lib/src/tool/buckettool.cpp @@ -150,7 +150,6 @@ void BucketTool::paintBitmap(Layer* layer) BitmapImage::floodFill( targetImage, cameraRect, point, - Qt::transparent, qPremultiply( mEditor->color()->frontColor().rgba() ), properties.tolerance * 2.55 ); From ccb18639875964b60470925cfa6c3448eb076400 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Thu, 17 May 2018 00:09:27 -0600 Subject: [PATCH 039/184] Fix irregular behavior when flood filling outside of borders --- core_lib/src/graphics/bitmap/bitmapimage.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core_lib/src/graphics/bitmap/bitmapimage.cpp b/core_lib/src/graphics/bitmap/bitmapimage.cpp index 07bbe8e05..160d88ae8 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.cpp +++ b/core_lib/src/graphics/bitmap/bitmapimage.cpp @@ -566,6 +566,13 @@ void BitmapImage::floodFill(BitmapImage* targetImage, QRgb newColor, int tolerance) { + // If the point we are supposed to fill is outside the image and camera bounds, do nothing + if(!cameraRect.united(targetImage->bounds()).contains(point)) + { + return; + } + + QRgb oldColor = targetImage->pixel(point); oldColor = qRgba(qRed(oldColor), qGreen(oldColor), qBlue(oldColor), qAlpha(oldColor)); From 9e66b7848b317f552c830b134af5dd3700e18d6a Mon Sep 17 00:00:00 2001 From: CandyFace Date: Thu, 17 May 2018 20:05:06 +0200 Subject: [PATCH 040/184] remove savedColor remains --- app/src/colorinspector.cpp | 15 --------------- app/src/colorinspector.h | 1 - app/src/colorpalettewidget.cpp | 5 +---- 3 files changed, 1 insertion(+), 20 deletions(-) diff --git a/app/src/colorinspector.cpp b/app/src/colorinspector.cpp index e6266f481..28977b0a2 100644 --- a/app/src/colorinspector.cpp +++ b/app/src/colorinspector.cpp @@ -84,12 +84,6 @@ void ColorInspector::initUI() ui->blue_slider->init(ColorSlider::ColorType::VAL, QColor(255,255,255,255), 0.0, 255.0); ui->alpha_slider->init(ColorSlider::ColorType::ALPHA, QColor(0,255,255,255), 0.0, 255.0); } - - QSettings settings(PENCIL2D, PENCIL2D); - - QColor savedColor; - savedColor.setRgba(settings.value("colorOfSliders").toUInt()); - setColor(savedColor); } void ColorInspector::updateUI() @@ -123,7 +117,6 @@ void ColorInspector::setColor(QColor newColor) return; } - qDebug() << "set color"; if(isRgbColors) { QSignalBlocker b1(ui->red_slider); @@ -199,14 +192,6 @@ void ColorInspector::paintEvent(QPaintEvent*) p.drawControl(QStyle::CE_DockWidgetTitle, opt); } -void ColorInspector::mouseReleaseEvent(QMouseEvent*) -{ - - QSettings settings(PENCIL2D, PENCIL2D); - settings.setValue("colorOfSliders", mCurrentColor.rgba()); - -} - void ColorInspector::onModeChanged() { // assume hsv if not checked diff --git a/app/src/colorinspector.h b/app/src/colorinspector.h index 735f2580c..4bdf49fa0 100644 --- a/app/src/colorinspector.h +++ b/app/src/colorinspector.h @@ -41,7 +41,6 @@ class ColorInspector : public BaseDockWidget protected: void paintEvent(QPaintEvent *) override; - void mouseReleaseEvent(QMouseEvent *) override; signals: void colorChanged(const QColor& c); void modeChange(const bool& isRgb); diff --git a/app/src/colorpalettewidget.cpp b/app/src/colorpalettewidget.cpp index c4631474f..e49b1710e 100644 --- a/app/src/colorpalettewidget.cpp +++ b/app/src/colorpalettewidget.cpp @@ -66,9 +66,6 @@ void ColorPaletteWidget::initUI() else setGridMode(); - QColor savedColor; - savedColor.setRgba(settings.value("colorOfSliders").toUInt()); - buttonStylesheet = "::menu-indicator{ image: none; }" "QPushButton { border: 0px; }" "QPushButton:pressed { border: 1px solid #ADADAD; border-radius: 2px; background-color: #D5D5D5; }" @@ -79,7 +76,7 @@ void ColorPaletteWidget::initUI() // in cases where the last color was saved // otherwise first color will be black. editor()->color()->setColorNumber(0); - editor()->color()->setColor(savedColor); + editor()->color()->setColor(editor()->color()->frontColor()); ui->addColorButton->setStyleSheet(buttonStylesheet); ui->removeColorButton->setStyleSheet(buttonStylesheet); From 523c1cfe3f38c45fbecee3bc890d084ac4f1f421 Mon Sep 17 00:00:00 2001 From: CandyFace Date: Thu, 17 May 2018 20:30:53 +0200 Subject: [PATCH 041/184] only show style if docked --- app/src/colorinspector.cpp | 11 +++++++---- app/src/mainwindow2.cpp | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/src/colorinspector.cpp b/app/src/colorinspector.cpp index 28977b0a2..98628441c 100644 --- a/app/src/colorinspector.cpp +++ b/app/src/colorinspector.cpp @@ -185,11 +185,14 @@ void ColorInspector::paintEvent(QPaintEvent*) // title style is not set when window is not docked // this enforces the style again. This is what QDockWidget // should be doing behind the scene - QStyleOptionDockWidget opt; - initStyleOption(&opt); + if (!this->isFloating()) { - QStylePainter p(this); - p.drawControl(QStyle::CE_DockWidgetTitle, opt); + QStyleOptionDockWidget opt; + initStyleOption(&opt); + + QStylePainter p(this); + p.drawControl(QStyle::CE_DockWidgetTitle, opt); + } } void ColorInspector::onModeChanged() diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index dde469362..2e13c61a0 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -199,7 +199,7 @@ void MainWindow2::createDockWidgets() addDockWidget(Qt::LeftDockWidgetArea, mToolBox); addDockWidget(Qt::LeftDockWidgetArea, mToolOptions); addDockWidget(Qt::BottomDockWidgetArea, mTimeLine); -// addDockWidget(Qt::LeftDockWidgetArea, mColorInspector); + addDockWidget(Qt::LeftDockWidgetArea, mColorInspector); setDockNestingEnabled(true); //addDockWidget( Qt::BottomDockWidgetArea, mTimeline2); From 10ba107e679345a96c601d0ef3649b91656f7dde Mon Sep 17 00:00:00 2001 From: CandyFace Date: Thu, 17 May 2018 21:54:42 +0200 Subject: [PATCH 042/184] color wheel should always use full value and sat --- app/src/colorwheel.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/colorwheel.cpp b/app/src/colorwheel.cpp index 787a0218c..662e7a9b4 100644 --- a/app/src/colorwheel.cpp +++ b/app/src/colorwheel.cpp @@ -328,7 +328,9 @@ void ColorWheel::drawSquareImage(const int &hue) QLinearGradient colorGradient = QLinearGradient(0, 0, square.width(), 0); colorGradient.setColorAt(0, QColor(255,255,255)); - colorGradient.setColorAt(1, QColor::fromHsv(color().hsvHue(), color().hsvSaturation(), color().value())); + + // color square should always use full value and saturation + colorGradient.setColorAt(1, QColor::fromHsv(color().hsvHue(), 255, 255)); QLinearGradient blackGradient = QLinearGradient(0, 0, 0, square.height()); blackGradient.setColorAt(0, QColor(0,0,0,0)); From 4bec74ce58f550d3f5bfd11fb40ea9192d211a96 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 15 May 2018 20:09:59 +1000 Subject: [PATCH 043/184] - Uninitialised variables - Delete a unused member - Delete a unused #include --- core_lib/src/interface/editor.h | 1 - core_lib/src/interface/scribblearea.cpp | 6 +----- core_lib/src/interface/scribblearea.h | 10 +++++----- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/core_lib/src/interface/editor.h b/core_lib/src/interface/editor.h index 09a4cc638..21a0b295b 100644 --- a/core_lib/src/interface/editor.h +++ b/core_lib/src/interface/editor.h @@ -18,7 +18,6 @@ GNU General Public License for more details. #ifndef EDITOR_H #define EDITOR_H -#include #include #include #include diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index 005a9d6d9..8912995a8 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -71,8 +71,6 @@ bool ScribbleArea::init() mIsSimplified = mPrefs->isOn(SETTING::OUTLINES); mMultiLayerOnionSkin = mPrefs->isOn(SETTING::MULTILAYER_ONION); - mShowAllLayers = 1; - mBufferImg = new BitmapImage; QRect newSelection(QPoint(0, 0), QSize(0, 0)); @@ -82,7 +80,7 @@ bool ScribbleArea::init() mOffset.setX(0); mOffset.setY(0); selectionTransformation.reset(); - selectionTolerance = 8.0; + updateCanvasCursor(); setMouseTracking(true); // reacts to mouse move events, even if the button is not pressed @@ -1130,8 +1128,6 @@ void ScribbleArea::drawCanvas(int frame, QRect rect) mCanvasPainter.setViewTransform(vm->getView(), vm->getViewInverse()); mCanvasPainter.paint(object, mEditor->layers()->currentLayerIndex(), frame, rect); - - return; } void ScribbleArea::setGaussianGradient(QGradient &gradient, QColor colour, qreal opacity, qreal offset) diff --git a/core_lib/src/interface/scribblearea.h b/core_lib/src/interface/scribblearea.h index f9a689f14..af9dff91f 100644 --- a/core_lib/src/interface/scribblearea.h +++ b/core_lib/src/interface/scribblearea.h @@ -67,7 +67,7 @@ class ScribbleArea : public QWidget QRectF getSelection() const { return mySelection; } bool somethingSelected = false; QRectF mySelection, myTransformedSelection, myTempTransformedSelection; - qreal myRotatedAngle; + qreal myRotatedAngle = 0.0; QList mClosestCurves; bool areLayersSane() const; @@ -190,7 +190,7 @@ public slots: void settingUpdated(SETTING setting); MoveMode mMoveMode = MIDDLE; - ToolType mPrevTemporalToolType; + ToolType mPrevTemporalToolType = ERASER; ToolType mPrevToolType = PEN; // previous tool (except temporal) BitmapImage mBitmapSelection; // used to temporary store a transformed portion of a bitmap image @@ -203,7 +203,7 @@ public slots: bool mIsSimplified = false; bool mShowThinLines = false; bool mQuickSizing = true; - int mShowAllLayers; + int mShowAllLayers = 1; bool mUsePressure = true; bool mMakeInvisible = false; bool mToolCursors = true; @@ -223,11 +223,11 @@ public slots: QPointF mLastPoint; QPointF mCurrentPoint; - qreal selectionTolerance; + qreal selectionTolerance = 8.0; QList mClosestVertices; QPointF mOffset; QPoint mCursorCenterPos; - int mCursorWidth; + QPointF transformedCursorPos; //instant tool (temporal eg. eraser) From 5d3e1a5a91e8a27d7e9b5852788b70ee23549f6d Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Fri, 18 May 2018 22:09:42 +1000 Subject: [PATCH 044/184] Fix: ColorInspector was not initialised correctly --- app/src/colorinspector.cpp | 61 ++++++++++++++++------------ app/src/colorslider.cpp | 5 +-- core_lib/src/managers/colormanager.h | 2 +- core_lib/src/structure/objectdata.h | 2 +- 4 files changed, 40 insertions(+), 30 deletions(-) diff --git a/app/src/colorinspector.cpp b/app/src/colorinspector.cpp index 98628441c..3e3217824 100644 --- a/app/src/colorinspector.cpp +++ b/app/src/colorinspector.cpp @@ -23,12 +23,13 @@ GNU General Public License for more details. #include "colorslider.h" #include "pencildef.h" +#include "editor.h" +#include "colormanager.h" ColorInspector::ColorInspector(QWidget *parent) : BaseDockWidget(parent) { - QWidget* innerWidget = new QWidget; setWindowTitle(tr("Color Inspector", "Window title of color inspector")); @@ -36,11 +37,21 @@ ColorInspector::ColorInspector(QWidget *parent) : ui->setupUi(innerWidget); setWidget(innerWidget); - QButtonGroup* colorModeChangeGroup = new QButtonGroup(); + QButtonGroup* colorModeChangeGroup = new QButtonGroup; colorModeChangeGroup->addButton(ui->hsvButton); colorModeChangeGroup->addButton(ui->rgbButton); colorModeChangeGroup->setExclusive(true); +} + +ColorInspector::~ColorInspector() +{ + delete ui; +} + +void ColorInspector::initUI() +{ + mCurrentColor = editor()->color()->frontColor(); QSettings settings(PENCIL2D, PENCIL2D); isRgbColors = settings.value("isRgb").toBool(); @@ -52,6 +63,27 @@ ColorInspector::ColorInspector(QWidget *parent) : } onModeChanged(); + QPalette p1 = ui->colorWrapper->palette(), p2 = ui->color->palette(); + p1.setBrush(QPalette::Background, QBrush(QImage(":/background/checkerboard.png"))); + p2.setColor(QPalette::Background, mCurrentColor); + ui->colorWrapper->setPalette(p1); + ui->color->setPalette(p2); + + if (isRgbColors) + { + ui->red_slider->init(ColorSlider::ColorType::RED, mCurrentColor, 0.0, 255.0); + ui->green_slider->init(ColorSlider::ColorType::GREEN, mCurrentColor, 0.0, 255.0); + ui->blue_slider->init(ColorSlider::ColorType::BLUE, mCurrentColor, 0.0, 255.0); + ui->alpha_slider->init(ColorSlider::ColorType::ALPHA, mCurrentColor, 0.0, 255.0); + } + else + { + ui->red_slider->init(ColorSlider::ColorType::HUE, mCurrentColor, 0.0, 359.0); + ui->green_slider->init(ColorSlider::ColorType::SAT, mCurrentColor, 0.0, 255.0); + ui->blue_slider->init(ColorSlider::ColorType::VAL, mCurrentColor, 0.0, 255.0); + ui->alpha_slider->init(ColorSlider::ColorType::ALPHA, mCurrentColor, 0.0, 255.0); + } + auto spinBoxChanged = static_cast(&QSpinBox::valueChanged); connect(ui->RedspinBox, spinBoxChanged, this, &ColorInspector::onColorChanged); connect(ui->GreenspinBox, spinBoxChanged, this, &ColorInspector::onColorChanged); @@ -66,26 +98,6 @@ ColorInspector::ColorInspector(QWidget *parent) : connect(ui->alpha_slider, &ColorSlider::valueChanged, this, &ColorInspector::onSliderChanged); } -ColorInspector::~ColorInspector() -{ - delete ui; -} - -void ColorInspector::initUI() -{ - if (isRgbColors) { - ui->red_slider->init(ColorSlider::ColorType::RED, QColor(255,255,255,255), 0.0, 255.0); - ui->green_slider->init(ColorSlider::ColorType::GREEN, QColor(255,255,255,255), 0.0, 255.0); - ui->blue_slider->init(ColorSlider::ColorType::BLUE, QColor(255,255,255,255), 0.0, 255.0); - ui->alpha_slider->init(ColorSlider::ColorType::ALPHA, QColor(0,255,255,255), 0.0, 255.0); - } else { - ui->red_slider->init(ColorSlider::ColorType::HUE, QColor(359,255,255,255), 0.0, 359.0); - ui->green_slider->init(ColorSlider::ColorType::SAT, QColor(255,255,255,255), 0.0, 255.0); - ui->blue_slider->init(ColorSlider::ColorType::VAL, QColor(255,255,255,255), 0.0, 255.0); - ui->alpha_slider->init(ColorSlider::ColorType::ALPHA, QColor(0,255,255,255), 0.0, 255.0); - } -} - void ColorInspector::updateUI() { } @@ -180,13 +192,12 @@ QColor ColorInspector::color() void ColorInspector::paintEvent(QPaintEvent*) { - // HACK: possible bug in 5.9 // title style is not set when window is not docked // this enforces the style again. This is what QDockWidget // should be doing behind the scene - if (!this->isFloating()) { - + if (!this->isFloating()) + { QStyleOptionDockWidget opt; initStyleOption(&opt); diff --git a/app/src/colorslider.cpp b/app/src/colorslider.cpp index 8d8134ea1..3d2597b7b 100644 --- a/app/src/colorslider.cpp +++ b/app/src/colorslider.cpp @@ -26,7 +26,6 @@ void ColorSlider::init(ColorType type, QColor color, qreal min, float max) void ColorSlider::init(ColorType type, QColor color, qreal min, float max, QSize size) { - mMin = min; mMax = max; mColor = color; @@ -47,7 +46,6 @@ void ColorSlider::paintEvent(QPaintEvent *) } - void ColorSlider::resizeEvent(QResizeEvent *event) { mSize = event->size(); @@ -56,7 +54,6 @@ void ColorSlider::resizeEvent(QResizeEvent *event) QLinearGradient ColorSlider::setColorSpec(QColor color) { - if (mSpecType == ColorSpecType::HSV) { return hsvGradient(color); @@ -65,6 +62,8 @@ QLinearGradient ColorSlider::setColorSpec(QColor color) { return rgbGradient(color); } + Q_ASSERT(false); + return QLinearGradient(); } QLinearGradient ColorSlider::rgbGradient(QColor color) diff --git a/core_lib/src/managers/colormanager.h b/core_lib/src/managers/colormanager.h index e60ea2515..94bb46cc0 100644 --- a/core_lib/src/managers/colormanager.h +++ b/core_lib/src/managers/colormanager.h @@ -46,7 +46,7 @@ class ColorManager : public BaseManager void colorLoaded(QColor); private: - QColor mCurrentFrontColor{ 33, 33, 33 }; + QColor mCurrentFrontColor{ 33, 33, 33, 255 }; int mCurrentColorIndex = 0; bool mIsWorkingOnVectorLayer = false; }; diff --git a/core_lib/src/structure/objectdata.h b/core_lib/src/structure/objectdata.h index 3b3abd6e6..8ece24f16 100644 --- a/core_lib/src/structure/objectdata.h +++ b/core_lib/src/structure/objectdata.h @@ -56,7 +56,7 @@ class ObjectData private: int mCurrentFrame = 1; - QColor mCurrentColor{ 0, 0, 0, 255 }; + QColor mCurrentColor{ 33, 33, 33, 255 }; int mCurrentLayer = 2; // Layers are counted bottom up // 0 - Camera Layer // 1 - Vector Layer From 67fd3344230174e0a23b5585c31e52c6e58999cc Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Fri, 18 May 2018 22:53:01 +1000 Subject: [PATCH 045/184] Fix: color wheel & color inspector didn't get correct color after loading a project - remove some unwanted code which causes complicated signal/slot behaviours --- app/src/colorbox.cpp | 41 +++++++++------------- app/src/colorbox.h | 4 +-- app/src/colorinspector.cpp | 7 ++++ app/src/colorinspector.h | 3 +- app/src/colorpalettewidget.cpp | 7 ---- app/src/colorwheel.cpp | 48 ++++++-------------------- app/src/colorwheel.h | 3 +- app/src/mainwindow2.cpp | 2 -- core_lib/src/managers/colormanager.cpp | 2 -- core_lib/src/managers/colormanager.h | 1 - core_lib/src/structure/objectdata.h | 2 +- 11 files changed, 37 insertions(+), 83 deletions(-) diff --git a/app/src/colorbox.cpp b/app/src/colorbox.cpp index d0fab3e93..60401a8b6 100644 --- a/app/src/colorbox.cpp +++ b/app/src/colorbox.cpp @@ -16,17 +16,25 @@ GNU General Public License for more details. #include #include "colorwheel.h" -#include "colorinspector.h" #include "colorbox.h" -#include "pencildef.h" +#include "editor.h" +#include "colormanager.h" + ColorBox::ColorBox( QWidget* parent ) : BaseDockWidget( parent ) { setWindowTitle(tr("Color Box", "Color Box window title")); +} +ColorBox::~ColorBox() +{ +} + +void ColorBox::initUI() +{ mColorWheel = new ColorWheel(this); - QVBoxLayout* layout = new QVBoxLayout(); + QVBoxLayout* layout = new QVBoxLayout; layout->setContentsMargins(5, 5, 5, 5); layout->addWidget(mColorWheel); layout->setStretch(0, 1); @@ -37,19 +45,14 @@ ColorBox::ColorBox( QWidget* parent ) : BaseDockWidget( parent ) connect(mColorWheel, &ColorWheel::colorChanged, this, &ColorBox::onWheelMove); connect(mColorWheel, &ColorWheel::colorSelected, this, &ColorBox::onWheelRelease); -} -ColorBox::~ColorBox() -{ -} - -void ColorBox::initUI() -{ + connect(editor(), &Editor::objectLoaded, this, &ColorBox::updateUI); } void ColorBox::updateUI() { - mColorLoaded = true; + QColor newColor = editor()->color()->frontColor(); + setColor(newColor); } QColor ColorBox::color() @@ -57,21 +60,9 @@ QColor ColorBox::color() return mColorWheel->color(); } -/** - * @brief ColorBox::loadColor - * - * This value is only to be used once - * for further color modifications, use setColor - */ -void ColorBox::loadColor(const QColor& color) -{ - mColorLoaded = false; - mColorWheel->setColor(color); -} - -void ColorBox::setColor(const QColor& newColor) +void ColorBox::setColor(QColor newColor) { - if (!mColorLoaded) { return; } + newColor = newColor.toHsv(); if ( newColor != mColorWheel->color() ) { diff --git a/app/src/colorbox.h b/app/src/colorbox.h index 0dca261be..1d5bbb2dd 100644 --- a/app/src/colorbox.h +++ b/app/src/colorbox.h @@ -32,8 +32,7 @@ class ColorBox : public BaseDockWidget void updateUI() override; QColor color(); - void setColor(const QColor&); - void loadColor(const QColor&); + void setColor(QColor); Q_SIGNALS: void colorChanged(const QColor&); @@ -44,7 +43,6 @@ class ColorBox : public BaseDockWidget ColorWheel* mColorWheel = nullptr; - bool mColorLoaded = false; // ColorInspector* mColorInspector = nullptr; }; diff --git a/app/src/colorinspector.cpp b/app/src/colorinspector.cpp index 3e3217824..536e29b75 100644 --- a/app/src/colorinspector.cpp +++ b/app/src/colorinspector.cpp @@ -96,10 +96,14 @@ void ColorInspector::initUI() connect(ui->green_slider, &ColorSlider::valueChanged, this, &ColorInspector::onSliderChanged); connect(ui->blue_slider, &ColorSlider::valueChanged, this, &ColorInspector::onSliderChanged); connect(ui->alpha_slider, &ColorSlider::valueChanged, this, &ColorInspector::onSliderChanged); + + connect(editor(), &Editor::objectLoaded, this, &ColorInspector::updateUI); } void ColorInspector::updateUI() { + QColor newColor = editor()->color()->frontColor(); + setColor(newColor); } void ColorInspector::onSliderChanged(QColor color) @@ -121,6 +125,9 @@ void ColorInspector::onSliderChanged(QColor color) void ColorInspector::setColor(QColor newColor) { + // this is a UI update function, never emit any signals + // grab the color from color manager, and then update itself, that's it. + // compare under the same color spec newColor = (isRgbColors) ? newColor.toRgb() : newColor.toHsv(); diff --git a/app/src/colorinspector.h b/app/src/colorinspector.h index 4bdf49fa0..1b4bca07e 100644 --- a/app/src/colorinspector.h +++ b/app/src/colorinspector.h @@ -30,7 +30,6 @@ class ColorInspector : public BaseDockWidget friend class ColorSliders; public: - explicit ColorInspector(QWidget *parent = 0); ~ColorInspector(); QColor color(); @@ -38,9 +37,9 @@ class ColorInspector : public BaseDockWidget void initUI() override; void updateUI() override; - protected: void paintEvent(QPaintEvent *) override; + signals: void colorChanged(const QColor& c); void modeChange(const bool& isRgb); diff --git a/app/src/colorpalettewidget.cpp b/app/src/colorpalettewidget.cpp index e49b1710e..558ed1caa 100644 --- a/app/src/colorpalettewidget.cpp +++ b/app/src/colorpalettewidget.cpp @@ -71,13 +71,6 @@ void ColorPaletteWidget::initUI() "QPushButton:pressed { border: 1px solid #ADADAD; border-radius: 2px; background-color: #D5D5D5; }" "QPushButton:checked { border: 1px solid #ADADAD; border-radius: 2px; background-color: #D5D5D5; }"; - - // color number need to be set to add new color to palette - // in cases where the last color was saved - // otherwise first color will be black. - editor()->color()->setColorNumber(0); - editor()->color()->setColor(editor()->color()->frontColor()); - ui->addColorButton->setStyleSheet(buttonStylesheet); ui->removeColorButton->setStyleSheet(buttonStylesheet); ui->colorDialogButton->setStyleSheet(buttonStylesheet); diff --git a/app/src/colorwheel.cpp b/app/src/colorwheel.cpp index 662e7a9b4..7b91ddeee 100644 --- a/app/src/colorwheel.cpp +++ b/app/src/colorwheel.cpp @@ -39,50 +39,22 @@ QColor ColorWheel::color() return mCurrentColor; } -void ColorWheel::changeColor(const QColor& color) +void ColorWheel::setColor(QColor color) { - if (color.toHsv() == mCurrentColor) - { - return; - } + // this is a UI updating function, never emit any signals + // and don't call any functions that will emit signals - if (color.spec() == QColor::Spec::Rgb) - changeRgbColors(color); - else - changeHsvColors(color); + color = color.toHsv(); - if (color.alpha() != mCurrentColor.alpha()) - { - alphaChanged(color.alpha()); - } - update(); -} - -void ColorWheel::setColor(const QColor& color) -{ - if (color.toHsv() == mCurrentColor) + if (color == mCurrentColor) { return; } - if (color.spec() == QColor::Spec::Rgb) - changeRgbColors(color); - else if (color.spec() == QColor::Spec::Hsv) - changeHsvColors(color); - else { - qDebug() << color.spec(); - Q_ASSERT(false); - } + mCurrentColor = color; drawSquareImage(color.hue()); - - if (color.alpha() != mCurrentColor.alpha()) - { - alphaChanged(color.alpha()); - } - update(); - emit colorSelected(color); } void ColorWheel::changeRgbColors(const QColor& color) @@ -330,7 +302,7 @@ void ColorWheel::drawSquareImage(const int &hue) colorGradient.setColorAt(0, QColor(255,255,255)); // color square should always use full value and saturation - colorGradient.setColorAt(1, QColor::fromHsv(color().hsvHue(), 255, 255)); + colorGradient.setColorAt(1, QColor::fromHsv(hue, 255, 255)); QLinearGradient blackGradient = QLinearGradient(0, 0, 0, square.height()); blackGradient.setColorAt(0, QColor(0,0,0,0)); @@ -378,14 +350,14 @@ void ColorWheel::drawPicker(const QColor& color) { QPainter painter(&mWheelPixmap); painter.setRenderHint(QPainter::Antialiasing); - int ellipseSize = 7; + int ellipseSize = 10; QPoint squareTopLeft = mSquareRegion.boundingRect().topLeft()-QPoint(1,1); - QSize squareSize = mSquareRegion.boundingRect().size()*1.01; + QSize squareSize = mSquareRegion.boundingRect().size() * 1.01; qreal S = color.hsvSaturationF() * (squareSize.width()); - qreal V = (squareSize.height() - (color.valueF() * (squareSize.height()))); + qreal V = (squareSize.height() - (color.valueF() * squareSize.height())); QPen pen; pen.setWidth(1); diff --git a/app/src/colorwheel.h b/app/src/colorwheel.h index 10630c95e..b856b5cf8 100644 --- a/app/src/colorwheel.h +++ b/app/src/colorwheel.h @@ -33,7 +33,7 @@ class ColorWheel : public QWidget void colorChanged(const QColor& color); public slots: - void setColor(const QColor& color); + void setColor(QColor color); protected: void mousePressEvent(QMouseEvent*) override; @@ -43,7 +43,6 @@ public slots: void paintEvent(QPaintEvent*) override; private: - void changeColor(const QColor&); void hueChanged(const int& hue); void saturationChanged(const int& sat); void valueChanged(const int& value); diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index 2e13c61a0..3c41b378c 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -552,7 +552,6 @@ bool MainWindow2::openObject(QString strFilePath) // Refresh the Palette mColorPalette->refreshColorList(); - mEditor->color()->setColorNumber(0); mEditor->layers()->notifyAnimationLengthChanged(); progress.setValue(progress.maximum()); @@ -1052,7 +1051,6 @@ void MainWindow2::makeConnections(Editor* editor, ColorBox* colorBox) { connect(colorBox, &ColorBox::colorChanged, editor->color(), &ColorManager::setColor); connect(editor->color(), &ColorManager::colorChanged, colorBox, &ColorBox::setColor); - connect(editor->color(), &ColorManager::colorLoaded, colorBox, &ColorBox::loadColor); } void MainWindow2::makeConnections(Editor* editor, ColorInspector* colorInspector) diff --git a/core_lib/src/managers/colormanager.cpp b/core_lib/src/managers/colormanager.cpp index 7a8464736..5ad12c5ec 100644 --- a/core_lib/src/managers/colormanager.cpp +++ b/core_lib/src/managers/colormanager.cpp @@ -39,8 +39,6 @@ Status ColorManager::load(Object* o) mCurrentColorIndex = 0; mCurrentFrontColor = o->data()->getCurrentColor(); - emit colorLoaded(mCurrentFrontColor); - return Status::OK; } diff --git a/core_lib/src/managers/colormanager.h b/core_lib/src/managers/colormanager.h index 94bb46cc0..523c2499a 100644 --- a/core_lib/src/managers/colormanager.h +++ b/core_lib/src/managers/colormanager.h @@ -43,7 +43,6 @@ class ColorManager : public BaseManager Q_SIGNALS: void colorChanged(QColor, int); // new color and color index void colorNumberChanged(int); - void colorLoaded(QColor); private: QColor mCurrentFrontColor{ 33, 33, 33, 255 }; diff --git a/core_lib/src/structure/objectdata.h b/core_lib/src/structure/objectdata.h index 8ece24f16..1b3d91d25 100644 --- a/core_lib/src/structure/objectdata.h +++ b/core_lib/src/structure/objectdata.h @@ -56,7 +56,7 @@ class ObjectData private: int mCurrentFrame = 1; - QColor mCurrentColor{ 33, 33, 33, 255 }; + QColor mCurrentColor{ 55, 33, 33, 255 }; int mCurrentLayer = 2; // Layers are counted bottom up // 0 - Camera Layer // 1 - Vector Layer From 81f8da7d4105c579b480c5793abeba953311a3b2 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Fri, 18 May 2018 22:58:16 +1000 Subject: [PATCH 046/184] Remove unused code --- app/src/colorwheel.cpp | 101 ----------------------------------------- app/src/colorwheel.h | 7 --- 2 files changed, 108 deletions(-) diff --git a/app/src/colorwheel.cpp b/app/src/colorwheel.cpp index 7b91ddeee..cdc2287d1 100644 --- a/app/src/colorwheel.cpp +++ b/app/src/colorwheel.cpp @@ -57,42 +57,6 @@ void ColorWheel::setColor(QColor color) update(); } -void ColorWheel::changeRgbColors(const QColor& color) -{ - if (color.red() != mCurrentColor.red()) - { - redChanged(color.red()); - } - - if (color.green() != mCurrentColor.green()) - { - greenChanged(color.green()); - } - - if (color.blue() != mCurrentColor.blue()) - { - blueChanged(color.blue()); - } -} - -void ColorWheel::changeHsvColors(const QColor& color) -{ - if (color.hue() != mCurrentColor.hue()) - { - hueChanged(color.hue()); - } - - if (color.saturation() != mCurrentColor.saturation()) - { - saturationChanged(color.saturation()); - } - - if (color.value() != mCurrentColor.value()) - { - valueChanged(color.value()); - } -} - QColor ColorWheel::pickColor(const QPoint& point) { if (!mWheelPixmap.rect().contains(point)) @@ -220,7 +184,6 @@ void ColorWheel::resizeEvent(QResizeEvent* event) void ColorWheel::paintEvent(QPaintEvent*) { - QPainter painter; painter.begin(this); @@ -386,58 +349,6 @@ void ColorWheel::composeWheel(QPixmap& pixmap) drawPicker(mCurrentColor); } -void ColorWheel::redChanged(const int &red) -{ - int g = mCurrentColor.green(); - int b = mCurrentColor.blue(); - int a = mCurrentColor.alpha(); - - mCurrentColor.setRgb(red, g, b, a); - - if (!isVisible()) - { - return; - } - - update(); - emit colorChanged(mCurrentColor); -} - -void ColorWheel::greenChanged(const int &green) -{ - int r = mCurrentColor.red(); - int b = mCurrentColor.blue(); - int a = mCurrentColor.alpha(); - - mCurrentColor.setRgb(r, green, b, a); - - if (!isVisible()) - { - return; - } - - update(); - emit colorChanged(mCurrentColor); -} - -void ColorWheel::blueChanged(const int &blue) -{ - int r = mCurrentColor.red(); - int g = mCurrentColor.green(); - int a = mCurrentColor.alpha(); - - mCurrentColor.setRgb(r, g, blue, a); - - if (!isVisible()) - { - return; - } - - update(); - emit colorChanged(mCurrentColor); -} - - void ColorWheel::hueChanged(const int &hue) { if (hue < 0 || hue > 359) @@ -483,15 +394,3 @@ void ColorWheel::valueChanged(const int &value) update(); emit colorChanged(mCurrentColor); } - -void ColorWheel::alphaChanged(const int &alpha) -{ - mCurrentColor.setAlpha(alpha); - - if (!isVisible()) - { - return; - } - - emit colorChanged(mCurrentColor); -} diff --git a/app/src/colorwheel.h b/app/src/colorwheel.h index b856b5cf8..e2c32acc3 100644 --- a/app/src/colorwheel.h +++ b/app/src/colorwheel.h @@ -46,13 +46,6 @@ public slots: void hueChanged(const int& hue); void saturationChanged(const int& sat); void valueChanged(const int& value); - void redChanged(const int& red); - void greenChanged(const int& green); - void blueChanged(const int& blue); - void alphaChanged(const int& alpha); - - void changeRgbColors(const QColor& color); - void changeHsvColors(const QColor& color); QColor pickColor(const QPoint& point); From c078532f1b01918a5a6bced184c3f9343a458bbc Mon Sep 17 00:00:00 2001 From: CandyFace Date: Sat, 19 May 2018 19:30:15 +0200 Subject: [PATCH 047/184] Fix remove color button and add context menu --- app/src/colorpalettewidget.cpp | 123 +++++++++++++++------ app/src/colorpalettewidget.h | 9 +- app/ui/colorpalette.ui | 22 +--- core_lib/src/graphics/vector/colourref.cpp | 11 ++ core_lib/src/graphics/vector/colourref.h | 2 + core_lib/src/managers/colormanager.cpp | 10 +- core_lib/src/structure/object.cpp | 43 ++++--- core_lib/src/structure/object.h | 8 +- 8 files changed, 161 insertions(+), 67 deletions(-) diff --git a/app/src/colorpalettewidget.cpp b/app/src/colorpalettewidget.cpp index 558ed1caa..9b2b150a0 100644 --- a/app/src/colorpalettewidget.cpp +++ b/app/src/colorpalettewidget.cpp @@ -17,8 +17,10 @@ GNU General Public License for more details. #include "colorpalettewidget.h" #include "ui_colorpalette.h" -#include +// Standard libraries +#include "cmath" +// Qt #include #include #include @@ -26,7 +28,9 @@ GNU General Public License for more details. #include #include #include +#include +// Project #include "colordictionary.h" #include "colourref.h" #include "object.h" @@ -50,16 +54,13 @@ ColorPaletteWidget::~ColorPaletteWidget() void ColorPaletteWidget::initUI() { - // "Remove color" feature is disabled because - // vector strokes that are linked to palette - // colors don't handle color removal from palette - ui->removeColorButton->hide(); - QSettings settings(PENCIL2D, PENCIL2D); int colorGridSize = settings.value("PreferredColorGridSize", 34).toInt(); mIconSize = QSize(colorGridSize, colorGridSize); + ui->colorListWidget->setContextMenuPolicy(Qt::CustomContextMenu); + QString sViewMode = settings.value("ColorPaletteViewMode", "ListMode").toString(); if (sViewMode == "ListMode") setListMode(); @@ -71,13 +72,19 @@ void ColorPaletteWidget::initUI() "QPushButton:pressed { border: 1px solid #ADADAD; border-radius: 2px; background-color: #D5D5D5; }" "QPushButton:checked { border: 1px solid #ADADAD; border-radius: 2px; background-color: #D5D5D5; }"; + + // color number need to be set to add new color to palette + // in cases where the last color was saved + // otherwise first color will be black. + editor()->color()->setColorNumber(0); + editor()->color()->setColor(editor()->color()->frontColor()); + ui->addColorButton->setStyleSheet(buttonStylesheet); ui->removeColorButton->setStyleSheet(buttonStylesheet); ui->colorDialogButton->setStyleSheet(buttonStylesheet); palettePreferences(); - connect(ui->colorListWidget, &QListWidget::currentItemChanged, this, &ColorPaletteWidget::colorListCurrentItemChanged); connect(ui->colorListWidget, &QListWidget::itemClicked, this, &ColorPaletteWidget::clickColorListItem); connect(ui->colorListWidget, &QListWidget::itemDoubleClicked, this, &ColorPaletteWidget::changeColourName); connect(ui->colorListWidget, &QListWidget::currentTextChanged, this, &ColorPaletteWidget::onActiveColorNameChange); @@ -85,6 +92,8 @@ void ColorPaletteWidget::initUI() connect(ui->addColorButton, &QPushButton::clicked, this, &ColorPaletteWidget::clickAddColorButton); connect(ui->colorDialogButton, &QPushButton::clicked, this, &ColorPaletteWidget::clickColorDialogButton); connect(ui->removeColorButton, &QPushButton::clicked, this, &ColorPaletteWidget::clickRemoveColorButton); + connect(ui->colorListWidget, &QListWidget::itemSelectionChanged, this, &ColorPaletteWidget::selectedItems); + connect(ui->colorListWidget, &QListWidget::customContextMenuRequested, this, &ColorPaletteWidget::showContextMenu); } void ColorPaletteWidget::updateUI() @@ -93,6 +102,55 @@ void ColorPaletteWidget::updateUI() updateGridUI(); } +void ColorPaletteWidget::showContextMenu(const QPoint &pos) +{ + QPoint globalPos = ui->colorListWidget->mapToGlobal(pos); + + QMenu* menu = new QMenu(); + menu->addAction(tr("Add"), this, &ColorPaletteWidget::addItem, 0); + menu->addAction(tr("Replace"), this, &ColorPaletteWidget::replaceItem, 0); + menu->addAction(tr("Remove"), this, &ColorPaletteWidget::removeItem, 0); + + menu->exec(globalPos); +} + +void ColorPaletteWidget::addItem() +{ + QSignalBlocker b(ui->colorListWidget); + QColor newColour = editor()->color()->frontColor(); + + // add in front of selected color + int colorIndex = ui->colorListWidget->currentRow()+1; + + ColourRef ref(newColour); + ref.name = getDefaultColorName(newColour); + + editor()->object()->addColourAtIndex(colorIndex, ref); + refreshColorList(); +} + +void ColorPaletteWidget::replaceItem() +{ + QSignalBlocker b(ui->colorListWidget); + int index = ui->colorListWidget->currentRow(); + + QColor newColour = editor()->color()->frontColor(); + + if (index > 0) + { + updateItemColor(index, newColour); + emit colorChanged(newColour); + ui->colorListWidget->setCurrentRow(index); + } + +} + +void ColorPaletteWidget::removeItem() +{ + QSignalBlocker b(ui->colorListWidget); + clickRemoveColorButton(); +} + void ColorPaletteWidget::setColor(QColor newColor, int colorIndex) { QSignalBlocker b(ui->colorListWidget); @@ -100,11 +158,14 @@ void ColorPaletteWidget::setColor(QColor newColor, int colorIndex) if (colorIndex > 0) { - updateItemColor(colorIndex, newColor); emit colorChanged(newColor); } } +QList ColorPaletteWidget::selectedItems() const +{ + return ui->colorListWidget->selectedItems(); +} void ColorPaletteWidget::selectColorNumber(int colorNumber) { @@ -123,7 +184,6 @@ int ColorPaletteWidget::currentColourNumber() void ColorPaletteWidget::refreshColorList() { QSignalBlocker b(ui->colorListWidget); - if (ui->colorListWidget->count() > 0) { ui->colorListWidget->clear(); @@ -135,7 +195,9 @@ void ColorPaletteWidget::refreshColorList() swatchPainter.end(); QPixmap colourSwatch; - for (int i = 0; i < editor()->object()->getColourCount(); i++) + int colourCount = editor()->object()->getColourCount(); + + for (int i = 0; i < colourCount; i++) { const ColourRef colourRef = editor()->object()->getColour(i); QListWidgetItem* colourItem = new QListWidgetItem(ui->colorListWidget); @@ -193,17 +255,14 @@ void ColorPaletteWidget::onActiveColorNameChange(QString name) } } -void ColorPaletteWidget::colorListCurrentItemChanged(QListWidgetItem* current, QListWidgetItem* previous) -{ - if (!current) - { - current = previous; - } - emit colorNumberChanged(ui->colorListWidget->row(current)); -} - void ColorPaletteWidget::clickColorListItem(QListWidgetItem* currentItem) { + auto modifiers = qApp->keyboardModifiers(); + + // to avoid conflicts with multiple selections + // ie. will be seen as selected twice and cause problems + if (modifiers & Qt::ShiftModifier || modifiers & Qt::ControlModifier) { return; } + int colorIndex = ui->colorListWidget->row(currentItem); emit colorNumberChanged(colorIndex); @@ -417,15 +476,8 @@ void ColorPaletteWidget::clickAddColorButton() { QColor prevColor = Qt::white; - if (editor()->object()->getLayer(editor()->currentLayerIndex())->type() == Layer::VECTOR) - { - if (currentColourNumber() > -1) - { - prevColor = editor()->object()->getColour(currentColourNumber()).colour; - } - } - QColor newColour; + if (mIsColorDialog) { newColour = QColorDialog::getColor(prevColor.rgba(), this, QString(), QColorDialog::ShowAlphaChannel); } else { @@ -438,24 +490,30 @@ void ColorPaletteWidget::clickAddColorButton() return; } + int colorIndex = editor()->object()->getColourCount(); ColourRef ref(newColour); ref.name = getDefaultColorName(newColour); editor()->object()->addColour(ref); refreshColorList(); - int colorIndex = editor()->object()->getColourCount() - 1; - editor()->color()->setColorNumber(colorIndex); editor()->color()->setColor(ref.colour); } void ColorPaletteWidget::clickRemoveColorButton() { - int colorNumber = ui->colorListWidget->currentRow(); - editor()->object()->removeColour(colorNumber); + for (auto item : selectedItems()) + { + int index = ui->colorListWidget->row(item); - refreshColorList(); + // items are not deleted by qt, has to be done manually + // delete should happen before removing the color from from palette + // as the palette will be one ahead and crash otherwise + delete item; + + editor()->object()->removeColour(index); + } } void ColorPaletteWidget::updateItemColor(int itemIndex, QColor newColor) @@ -464,6 +522,7 @@ void ColorPaletteWidget::updateItemColor(int itemIndex, QColor newColor) QPainter swatchPainter(&colourSwatch); swatchPainter.drawTiledPixmap(0, 0, mIconSize.width(), mIconSize.height(), QPixmap(":/background/checkerboard.png")); swatchPainter.fillRect(0, 0, mIconSize.width(), mIconSize.height(), newColor); + ui->colorListWidget->item(itemIndex)->setIcon(colourSwatch); // Make sure to update grid in grid mode diff --git a/app/src/colorpalettewidget.h b/app/src/colorpalettewidget.h index 60529f143..bb45fb55e 100644 --- a/app/src/colorpalettewidget.h +++ b/app/src/colorpalettewidget.h @@ -53,15 +53,16 @@ class ColorPaletteWidget : public BaseDockWidget void setColor(QColor, int); void refreshColorList(); + void showContextMenu(const QPoint&); + signals: void colorChanged(QColor); void colorNumberChanged(int); protected: - void resizeEvent(QResizeEvent *event) override; + void resizeEvent(QResizeEvent* event) override; private slots: - void colorListCurrentItemChanged(QListWidgetItem*, QListWidgetItem*); void clickColorListItem(QListWidgetItem*); void changeColourName(QListWidgetItem*); void onActiveColorNameChange(QString name); @@ -74,6 +75,10 @@ private slots: void setSwatchSizeSmall(); void setSwatchSizeMedium(); void setSwatchSizeLarge(); + QList selectedItems() const; + void addItem(); + void replaceItem(); + void removeItem(); private: void updateItemColor(int, QColor); diff --git a/app/ui/colorpalette.ui b/app/ui/colorpalette.ui index 8c0cf4880..50b14930f 100644 --- a/app/ui/colorpalette.ui +++ b/app/ui/colorpalette.ui @@ -228,6 +228,9 @@ 16 + + QAbstractItemView::ExtendedSelection + QListView::Fixed @@ -312,24 +315,7 @@ - - - removeColorButton - clicked() - ColorPalette - clickRemoveColorButton() - - - 36 - 43 - - - 133 - 128 - - - - + colorListCurrentItemChanged(QListWidgetItem*,QListWidgetItem*) clickColorListItem(QListWidgetItem*) diff --git a/core_lib/src/graphics/vector/colourref.cpp b/core_lib/src/graphics/vector/colourref.cpp index f01fd26a3..3a44fa677 100644 --- a/core_lib/src/graphics/vector/colourref.cpp +++ b/core_lib/src/graphics/vector/colourref.cpp @@ -16,6 +16,8 @@ GNU General Public License for more details. */ #include "colourref.h" +#include + ColourRef::ColourRef() { colour = Qt::green; @@ -51,3 +53,12 @@ bool ColourRef::operator!=(ColourRef colourRef1) return false; } } + +QDebug operator<<(QDebug debug, const ColourRef& colourRef) +{ + debug.nospace() << "ColourRef(" << colourRef.colour << " " << colourRef.name <<")"; + return debug.maybeSpace(); +} + + + diff --git a/core_lib/src/graphics/vector/colourref.h b/core_lib/src/graphics/vector/colourref.h index 53b564a96..80066d742 100644 --- a/core_lib/src/graphics/vector/colourref.h +++ b/core_lib/src/graphics/vector/colourref.h @@ -33,4 +33,6 @@ class ColourRef QString name; }; +QDebug operator<<(QDebug debug, const ColourRef &colourRef); + #endif diff --git a/core_lib/src/managers/colormanager.cpp b/core_lib/src/managers/colormanager.cpp index 5ad12c5ec..8da6f2052 100644 --- a/core_lib/src/managers/colormanager.cpp +++ b/core_lib/src/managers/colormanager.cpp @@ -62,7 +62,15 @@ QColor ColorManager::frontColor() { if (mIsWorkingOnVectorLayer) - return object()->getColour(mCurrentColorIndex).colour; + if (object()->getColourCount() == 0) + { + object()->useAsTempPaletteColor(mCurrentFrontColor); + return mCurrentFrontColor; + } + else + { + return object()->getColour(mCurrentColorIndex).colour; + } else return mCurrentFrontColor; } diff --git a/core_lib/src/structure/object.cpp b/core_lib/src/structure/object.cpp index a38fd8111..5a46d2bac 100644 --- a/core_lib/src/structure/object.cpp +++ b/core_lib/src/structure/object.cpp @@ -20,6 +20,7 @@ GNU General Public License for more details. #include #include #include +#include #include "layer.h" #include "layerbitmap.h" @@ -272,12 +273,14 @@ void Object::deleteLayer(Layer* layer) } } -ColourRef Object::getColour(int i) const +ColourRef Object::getColour(int index) const { ColourRef result(Qt::white, "error"); - if (i > -1 && i < mPalette.size()) + if (index > -1 && index < mPalette.size()) { - result = mPalette.at(i); + result = mPalette.at(index); + } else { + return mFrontColor; } return result; } @@ -285,14 +288,34 @@ ColourRef Object::getColour(int i) const void Object::setColour(int index, QColor newColour) { Q_ASSERT(index >= 0); + + // To allow a clean color palette, we return if it's empty + if (mPalette.isEmpty()) + { + return; + } mPalette[index].colour = newColour; } +void Object::setColourRef(int index, ColourRef newColourRef) +{ + if (mPalette.isEmpty()) + { + return; + } + mPalette[index] = newColourRef; +} + void Object::addColour(QColor colour) { addColour(ColourRef(colour, "Colour " + QString::number(mPalette.size()))); } +void Object::addColourAtIndex(int index, ColourRef newColour) +{ + mPalette.insert(index, newColour); +} + bool Object::removeColour(int index) { for (int i = 0; i < getLayerCount(); i++) @@ -301,19 +324,13 @@ bool Object::removeColour(int index) if (layer->type() == Layer::VECTOR) { LayerVector* layerVector = (LayerVector*)layer; - if (layerVector->usesColour(index)) return false; - } - } - for (int i = 0; i < getLayerCount(); i++) - { - Layer* layer = getLayer(i); - if (layer->type() == Layer::VECTOR) - { - LayerVector* layerVector = (LayerVector*)layer; + layerVector->removeColour(index); } } + mPalette.removeAt(index); + return true; // update the vector pictures using that colour ! } @@ -419,7 +436,7 @@ void Object::loadDefaultPalette() addColour(ColourRef(QColor(255, 214, 156), QString(tr("Skin")))); addColour(ColourRef(QColor(207, 174, 127), QString(tr("Skin - shade")))); addColour(ColourRef(QColor(255, 198, 116), QString(tr("Dark Skin")))); - addColour(ColourRef(QColor(227, 177, 105), QString(tr("Dark Skin - shade")))); + addColour(ColourRef(QColor(227, 177, 105), QString(tr("Dark Skin - shade")) )); } void Object::paintImage(QPainter& painter, int frameNumber, diff --git a/core_lib/src/structure/object.h b/core_lib/src/structure/object.h index dfc115080..12de37f1d 100644 --- a/core_lib/src/structure/object.h +++ b/core_lib/src/structure/object.h @@ -82,10 +82,14 @@ class Object : public QObject QString copyFileToDataFolder( QString strFilePath ); // Color palette - ColourRef getColour( int i ) const; + ColourRef getColour( int index ) const; + void useAsTempPaletteColor(QColor color) { mFrontColor = ColourRef(color, "Front Color"); } void setColour(int index, QColor newColour); + void setColourRef(int index, ColourRef newColourRef); void addColour( QColor ); + void addColour( ColourRef newColour ) { mPalette.append( newColour ); } + void addColourAtIndex(int index, ColourRef newColour); bool removeColour( int index ); void renameColour( int i, QString text ); int getColourCount() { return mPalette.size(); } @@ -150,6 +154,8 @@ class Object : public QObject QList mPalette; + ColourRef mFrontColor; + std::unique_ptr mData; }; From eaaf02d9bfdcf27f45ebd3a0c95c2b154f6a4e93 Mon Sep 17 00:00:00 2001 From: CandyFace Date: Sun, 20 May 2018 10:33:00 +0200 Subject: [PATCH 048/184] Show dialog if color is being used already --- app/src/colorpalettewidget.cpp | 8 +++--- core_lib/src/structure/object.cpp | 41 ++++++++++++++++++++++++++++++- core_lib/src/structure/object.h | 1 + 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/app/src/colorpalettewidget.cpp b/app/src/colorpalettewidget.cpp index 9b2b150a0..2e544e986 100644 --- a/app/src/colorpalettewidget.cpp +++ b/app/src/colorpalettewidget.cpp @@ -510,9 +510,11 @@ void ColorPaletteWidget::clickRemoveColorButton() // items are not deleted by qt, has to be done manually // delete should happen before removing the color from from palette // as the palette will be one ahead and crash otherwise - delete item; - - editor()->object()->removeColour(index); + if (editor()->object()->shouldDeleteColor(index)) { + delete item; + editor()->object()->removeColour(index); + editor()->updateCurrentFrame(); + } } } diff --git a/core_lib/src/structure/object.cpp b/core_lib/src/structure/object.cpp index 5a46d2bac..954ebacaf 100644 --- a/core_lib/src/structure/object.cpp +++ b/core_lib/src/structure/object.cpp @@ -21,6 +21,7 @@ GNU General Public License for more details. #include #include #include +#include #include "layer.h" #include "layerbitmap.h" @@ -316,8 +317,9 @@ void Object::addColourAtIndex(int index, ColourRef newColour) mPalette.insert(index, newColour); } -bool Object::removeColour(int index) +bool Object::shouldDeleteColor(int index) { + bool usesColor = false; for (int i = 0; i < getLayerCount(); i++) { Layer* layer = getLayer(i); @@ -325,6 +327,43 @@ bool Object::removeColour(int index) { LayerVector* layerVector = (LayerVector*)layer; + if (layerVector->usesColour(index)) + { + usesColor = true; + } + } + } + + if (usesColor) + { + QMessageBox msgBox; + msgBox.setText(tr("The color you are trying to delete is currently being used by one or multiple strokes, " + "if you wish to delete it anyway, you accept that the stroke(s) will be bound to the next available color")); + QPushButton* cancelButton = msgBox.addButton(tr("Cancel"), QMessageBox::RejectRole); + QPushButton* removeButton = msgBox.addButton(tr("Remove anyway"), QMessageBox::AcceptRole); + + msgBox.exec(); + if (msgBox.clickedButton() == cancelButton) + { + return false; + } + else if (msgBox.clickedButton() == removeButton) + { + return true; + } + } + return true; + +} + +bool Object::removeColour(int index) +{ + for (int i = 0; i < getLayerCount(); i++) + { + Layer* layer = getLayer(i); + if (layer->type() == Layer::VECTOR) + { + LayerVector* layerVector = (LayerVector*)layer; layerVector->removeColour(index); } } diff --git a/core_lib/src/structure/object.h b/core_lib/src/structure/object.h index 12de37f1d..2cdb7170c 100644 --- a/core_lib/src/structure/object.h +++ b/core_lib/src/structure/object.h @@ -91,6 +91,7 @@ class Object : public QObject void addColour( ColourRef newColour ) { mPalette.append( newColour ); } void addColourAtIndex(int index, ColourRef newColour); bool removeColour( int index ); + bool shouldDeleteColor( int index ); void renameColour( int i, QString text ); int getColourCount() { return mPalette.size(); } bool importPalette( QString filePath ); From e064770db61641344b84bbe1f7b27ecfaea60dcb Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Sun, 20 May 2018 15:26:50 -0600 Subject: [PATCH 049/184] Fix Import Image Sequence spacing regression --- app/src/mainwindow2.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index 3c41b378c..1d3f85e81 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -762,6 +762,11 @@ void MainWindow2::importImageSequence() failedImport = true; } } + + for (int i = 1; i < number; i++) + { + mEditor->scrubForward(); + } } if (failedImport) @@ -773,11 +778,6 @@ void MainWindow2::importImageSequence() QMessageBox::Ok); } - for (int i = 1; i < number; i++) - { - mEditor->scrubForward(); - } - mEditor->layers()->notifyAnimationLengthChanged(); progress.close(); From beb7e041a7f3459c3d8bc844275ddba42657ccf4 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Sun, 20 May 2018 16:16:03 -0600 Subject: [PATCH 050/184] Add Color Inspector to Windows menu --- app/src/mainwindow2.cpp | 5 ++++- core_lib/data/resources/kb.ini | 1 + core_lib/src/util/pencildef.h | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index 1d3f85e81..d2c30bb4b 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -337,7 +337,8 @@ void MainWindow2::createMenus() mColorBox->toggleViewAction(), mColorPalette->toggleViewAction(), mTimeLine->toggleViewAction(), - mDisplayOptionWidget->toggleViewAction() + mDisplayOptionWidget->toggleViewAction(), + mColorInspector->toggleViewAction() }; for (QAction* action : actions) @@ -801,6 +802,7 @@ void MainWindow2::lockWidgets(bool shouldLock) QDockWidget::DockWidgetFeature feat = shouldLock ? QDockWidget::DockWidgetClosable : QDockWidget::AllDockWidgetFeatures; mColorBox->setFeatures(feat); + mColorInspector->setFeatures(feat); mColorPalette->setFeatures(feat); mDisplayOptionWidget->setFeatures(feat); mToolOptions->setFeatures(feat); @@ -971,6 +973,7 @@ void MainWindow2::setupKeyboardShortcuts() mColorPalette->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_COLOR_LIBRARY)); mTimeLine->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_TIMELINE)); mDisplayOptionWidget->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_DISPLAY_OPTIONS)); + mColorInspector->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_COLOR_INSPECTOR)); ui->actionHelp->setShortcut(cmdKeySeq(CMD_HELP)); ui->actionExit->setShortcut(cmdKeySeq(CMD_EXIT)); diff --git a/core_lib/data/resources/kb.ini b/core_lib/data/resources/kb.ini index 9ad5097ab..4e1be0b29 100644 --- a/core_lib/data/resources/kb.ini +++ b/core_lib/data/resources/kb.ini @@ -66,3 +66,4 @@ CmdToggleColorWheel=Ctrl+3 CmdToggleColorLibrary=Ctrl+4 CmdToggleDisplayOptions=Ctrl+5 CmdToggleTimeline=Ctrl+6 +CmdToggleColorInspector=Ctrl+7 diff --git a/core_lib/src/util/pencildef.h b/core_lib/src/util/pencildef.h index f49768311..cb2d5354a 100644 --- a/core_lib/src/util/pencildef.h +++ b/core_lib/src/util/pencildef.h @@ -141,6 +141,7 @@ enum StabilizationLevel #define CMD_TOGGLE_TOOLBOX "CmdToggleToolBox" #define CMD_TOGGLE_TOOL_OPTIONS "CmdToggleToolOptions" #define CMD_TOGGLE_COLOR_WHEEL "CmdToggleColorWheel" +#define CMD_TOGGLE_COLOR_INSPECTOR "CmdToggleColorInspector" #define CMD_TOGGLE_COLOR_LIBRARY "CmdToggleColorLibrary" #define CMD_TOGGLE_DISPLAY_OPTIONS "CmdToggleDisplayOptions" #define CMD_TOGGLE_TIMELINE "CmdToggleTimeline" From 2e64f1a7087da86e645e099ae1eff949b150e762 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Sun, 20 May 2018 15:50:52 -0600 Subject: [PATCH 051/184] Rearrange default dock widget locations --- app/src/mainwindow2.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index d2c30bb4b..b07e868c2 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -194,12 +194,12 @@ void MainWindow2::createDockWidgets() } addDockWidget(Qt::RightDockWidgetArea, mColorBox); + addDockWidget(Qt::RightDockWidgetArea, mColorInspector); addDockWidget(Qt::RightDockWidgetArea, mColorPalette); - addDockWidget(Qt::RightDockWidgetArea, mDisplayOptionWidget); addDockWidget(Qt::LeftDockWidgetArea, mToolBox); addDockWidget(Qt::LeftDockWidgetArea, mToolOptions); + addDockWidget(Qt::LeftDockWidgetArea, mDisplayOptionWidget); addDockWidget(Qt::BottomDockWidgetArea, mTimeLine); - addDockWidget(Qt::LeftDockWidgetArea, mColorInspector); setDockNestingEnabled(true); //addDockWidget( Qt::BottomDockWidgetArea, mTimeline2); From 46e206d4840910459c14656561a1b2a725471f82 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Sun, 20 May 2018 19:30:02 -0600 Subject: [PATCH 052/184] Add save warning before opening recent files Fixes #963 --- app/src/mainwindow2.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index b07e868c2..41b472c58 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -495,11 +495,14 @@ bool MainWindow2::saveAsNewDocument() void MainWindow2::openFile(QString filename) { - bool ok = openObject(filename); - if (!ok) + if (maybeSave()) { - QMessageBox::warning(this, tr("Warning"), tr("Pencil cannot read this file. If you want to import images, use the command import.")); - newDocument(); + bool ok = openObject(filename); + if (!ok) + { + QMessageBox::warning(this, tr("Warning"), tr("Pencil cannot read this file. If you want to import images, use the command import.")); + newDocument(); + } } } From 1977b4a627a73945621adaf73309c2441b85035e Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Mon, 21 May 2018 22:37:32 +1000 Subject: [PATCH 053/184] Fix #960: camera is not working in 0.6.1 --- core_lib/src/movieexporter.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core_lib/src/movieexporter.cpp b/core_lib/src/movieexporter.cpp index 43e51df25..b197c8439 100644 --- a/core_lib/src/movieexporter.cpp +++ b/core_lib/src/movieexporter.cpp @@ -246,9 +246,9 @@ Status MovieExporter::assembleAudio(const Object* obj, std::function progress) { // Quicktime assemble call - int startFrame = mDesc.startFrame; - int endFrame = mDesc.endFrame; - int fps = mDesc.fps; + const int startFrame = mDesc.startFrame; + const int endFrame = mDesc.endFrame; + const int fps = mDesc.fps; Q_ASSERT(startFrame >= 0); Q_ASSERT(endFrame >= startFrame); @@ -411,8 +411,6 @@ Status MovieExporter::generateMovie( } imageToExportBase.fill(bgColor); - QTransform view = cameraLayer->getViewAtFrame(currentFrame); - QSize camSize = cameraLayer->getViewSize(); QTransform centralizeCamera; centralizeCamera.translate(camSize.width() / 2, camSize.height() / 2); @@ -479,10 +477,12 @@ Status MovieExporter::generateMovie( QImage imageToExport = imageToExportBase.copy(); QPainter painter(&imageToExport); + QTransform view = cameraLayer->getViewAtFrame(currentFrame); painter.setWorldTransform(view * centralizeCamera); painter.setWindow(QRect(0, 0, camSize.width(), camSize.height())); obj->paintImage(painter, currentFrame, false, true); + painter.end(); // Should use sizeInBytes instead of byteCount to support large images, // but this is only supported in QT 5.10+ From 6c52902bd0b8a6f066a1b9ad862080231c3d8bc8 Mon Sep 17 00:00:00 2001 From: Matt Date: Tue, 22 May 2018 09:34:33 +1000 Subject: [PATCH 054/184] Update build_win.md --- docs/build_win.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/build_win.md b/docs/build_win.md index 7e9c6b689..04bdd16c9 100644 --- a/docs/build_win.md +++ b/docs/build_win.md @@ -2,7 +2,7 @@ These are instructions for building Pencil2D on a Windows PC. If you are using Mac go [here](docs/build_mac.md), and Linux please go [here](docs/build_linux.md). -This guide is primarily targeted towards developers. If you just want to use the latest version, download it from our [nightly builds](https://drive.google.com/drive/folders/0BxdcdOiOmg-CcWhLazdKR1oydHM). This tutorial was made with Windows 10 in mind, however this will work with Windows 7 and up. +This guide is primarily targeted towards developers. If you just want to use the latest version, download it from our [nightly builds](https://www.pencil2d.org/download/#nightlybuild). This tutorial was made with Windows 10 in mind, however this will work with Windows 7 and up. There are 3 steps in total: @@ -22,7 +22,7 @@ Pencil2D is built upon Qt, you have to install it before you can compile the pro - Download the **Qt Online Installer for Windows** from [Qt Downloads](https://www.qt.io/download-open-source/) - Open up the installer, you can skip the step of creating Qt account, it's not necessary. -- In the next step, choose the Qt version and used C++ compiler. +- In the next step, choose the Qt version and your C++ compiler. - If you have no idea what to do, please select latest `Qt 5.9.x -> MinGW 5.x` and `Tools -> MinGW 5.x`. - Agree to the license and start the installation. It will take a long time to download all of the files, so be patient. When the installation is complete, press `Done` and it will launch Qt Creator for you. @@ -39,7 +39,7 @@ Now it's time to build the application. - Open up the Qt Creator application. - From the menu bar select **File** and then **Open File or Project**. Navigate to Pencil2D's root source folder and open the `pencil2d.pro` file. -- Next, you'll be asked to configure your kits for the project. Kits determine compilers, target environment, and various build settings among other things. The Desktop option should be the only one checked. Click Configure Project to complete the kit selection. +- Next, you'll be asked to configure your `kits` for the project. Kits determine compilers, target environment, and various build settings among other things. The Desktop option should be the only one checked. Click Configure Project to complete the kit selection. - Now all you have to do to is click the plain **green arrow** in the bottom left corner or press `Ctrl+r`. A small progress bar will show up on the bottom right and console output will appear in the bottom section. - If everything goes well then the Pencil2D application that you build will open up automatically and you're done! @@ -49,7 +49,7 @@ If any error occurred, the issues tab will open up at the bottom and display err Yes, you can compile Pencil2D with Visual Studio if you like. -- First, make sure you have Visual Studio 2015 or later versions installed. +- Firstly, have Visual Studio 2015 or later versions installed. - Next, install the Qt SDK which matches your VS version (e.g. Qt 5.6 msvc2015 64bit if you use VS2015). - Download and install the [Qt Visual Studio Add-in](http://doc.qt.io/archives/vs-addin/index.html). - Open Visual Studio, from the Menu bar -> Qt VS Tools -> Open Qt Project File (.pro), navigate to the Pencil2D source folder and select `pencil2d.pro`. From b46cefb6b47327821b25395f1987319adbc0c5e8 Mon Sep 17 00:00:00 2001 From: Matt Date: Tue, 22 May 2018 09:36:02 +1000 Subject: [PATCH 055/184] Update build_linux.md --- docs/build_linux.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/build_linux.md b/docs/build_linux.md index fd98cc237..878bc71bb 100644 --- a/docs/build_linux.md +++ b/docs/build_linux.md @@ -1,6 +1,6 @@ # Building Pencil2D on Linux -These are instructions for building Pencil2D on Linux. If you are using Windows go [here](docs/build_win.md), and if you are using macOS go [here](docs/build_mac.md). This guide is primarily targeted towards developers. If you just want to use the latest version you can just download one of our [nightly builds](https://drive.google.com/drive/folders/0BxdcdOiOmg-CcWhLazdKR1oydHM). +These are instructions for building Pencil2D on Linux. If you are using Windows go [here](docs/build_win.md), and macOS go [here](docs/build_mac.md). This guide is primarily targeted towards developers. If you just want to use the latest version you can just download one of our [nightly builds](https://www.pencil2d.org/download/#nightlybuild). This tutorial was made with Ubuntu Xenial Xerus (16.04) and Arch Linux in mind, however you should be able to adapt this guide to other versions or distributions if necessary. From f0513e670c02d53bc26d08455e8f7256f6802058 Mon Sep 17 00:00:00 2001 From: Matt Date: Tue, 22 May 2018 09:38:42 +1000 Subject: [PATCH 056/184] Update build_mac.md --- docs/build_mac.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/build_mac.md b/docs/build_mac.md index 6dcd6d0f4..64236979f 100644 --- a/docs/build_mac.md +++ b/docs/build_mac.md @@ -2,7 +2,7 @@ These are instructions for building Pencil2D on a Mac. If you are using Windows go [here](docs/build_win.md), and Linux please go [here](docs/build_linux.md). -This guide is primarily targeted towards developers. If you just want to use the latest version, download it from our [nightly builds](https://drive.google.com/drive/folders/0BxdcdOiOmg-CcWhLazdKR1oydHM). This tutorial was made with macOS Sierra (10.12) in mind, however this will probably work with all versions Mountain Lion (10.8) and up. +This guide is primarily targeted towards developers. If you just want to use the latest version, download it from our [nightly builds](https://www.pencil2d.org/download/#nightlybuild). This tutorial was made with macOS Sierra (10.12) in mind, however this will probably work with all versions Yosemite (10.10) and up. There are 4 steps in total: @@ -40,7 +40,7 @@ A dialog should pop up asking if you want to install the command line developer - The file is the Qt installer application, so go ahead and open it. Click continue. You can skip the the step of creating Qt account. It's not necessary. - Next, specify a location for Qt, put it somewhere you can find it in case you ever need to navigate to the Qt files manually. - Then choose the Qt version and components you wish to install. - - If you have no idea what to do, select `Qt 5.9.2 -> macOS`. + - If you have no idea what to do, select `Qt 5.9.x -> macOS`. - Also make sure Qt Creator under the Tools section is being installed (at the time of writing there is no option to uncheck this, but it's worth double checking!). - Agree to the license and begin the installation. It will take a long time to download all of the files, so be patient. When the installation is complete, press `Done` and it will launch Qt Creator for you. @@ -68,7 +68,7 @@ Now it's time to build the application. - Open up the Qt Creator application. - From the menu bar select **File** and then **Open File or Project**. Navigate to Pencil2D's root source folder and open the `pencil2d.pro` file. -- Next, you'll be asked to configure your kits for the project. Kits determine compilers, target environment, and various build settings among other things. The Desktop option should be the only one checked. Click Configure Project to complete the kit selection. +- Next, you'll be asked to configure your **kits** for the project. Kits determine compilers, target environment, and various build settings among other things. The Desktop option should be the only one checked. Click Configure Project to complete the kit selection. - Now all you have to do to build is click the plain **green arrow** in the bottom left corner of the window or press `Command+r`. A small progress bar will show up on the bottom right and console output will appear in the bottom section. - If everything goes well then the version of Pencil2D that you build will open up automatically and you're done! From ee596ca833b0f94afa994b9f8bf21c046ea917fe Mon Sep 17 00:00:00 2001 From: Matt Date: Tue, 22 May 2018 09:40:07 +1000 Subject: [PATCH 057/184] Update build_linux.md --- docs/build_linux.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/build_linux.md b/docs/build_linux.md index 878bc71bb..deb78ba9d 100644 --- a/docs/build_linux.md +++ b/docs/build_linux.md @@ -107,4 +107,4 @@ You can then open Pencil2D by running this from the source directory: ## Next steps -Now that you can build Pencil2D, the next step is to learn about [navigating the source code](docs/dive-into-code.md). +Now that you can build Pencil2D, the next step is to learn about [navigating the source code](dive-into-code.md). From be741cfbc0cc744738656b3d2dc615d75bcfab1b Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Sun, 20 May 2018 20:35:10 -0600 Subject: [PATCH 058/184] Add timeline length update for frame forward action --- app/src/actioncommands.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/actioncommands.cpp b/app/src/actioncommands.cpp index bb5406c48..4a697f704 100644 --- a/app/src/actioncommands.cpp +++ b/app/src/actioncommands.cpp @@ -546,6 +546,8 @@ void ActionCommands::moveFrameForward() mEditor->scrubForward(); } } + + mEditor->layers()->notifyAnimationLengthChanged(); } void ActionCommands::moveFrameBackward() From a4f480cb943cf8c7461d17d6dd8459ff1c9b4816 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Sun, 20 May 2018 21:04:36 -0600 Subject: [PATCH 059/184] Add timeline length update for frame drag action --- core_lib/src/interface/timelinecells.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/core_lib/src/interface/timelinecells.cpp b/core_lib/src/interface/timelinecells.cpp index 140e48124..e84929bf3 100644 --- a/core_lib/src/interface/timelinecells.cpp +++ b/core_lib/src/interface/timelinecells.cpp @@ -592,6 +592,7 @@ void TimeLineCells::mouseMoveEvent(QMouseEvent* event) int offset = frameNumber - mLastFrameNumber; currentLayer->moveSelectedFrames(offset); + mEditor->layers()->notifyAnimationLengthChanged(); mEditor->updateCurrentFrame(); } else if (mCanBoxSelect) From ad59aaf0c617181f5e8b794444ecc40122d48ab6 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Sun, 20 May 2018 21:19:57 -0600 Subject: [PATCH 060/184] Make timeline length update exponential --- core_lib/src/interface/timeline.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/core_lib/src/interface/timeline.cpp b/core_lib/src/interface/timeline.cpp index 323d2197a..6954e9c0d 100644 --- a/core_lib/src/interface/timeline.cpp +++ b/core_lib/src/interface/timeline.cpp @@ -240,12 +240,19 @@ void TimeLine::setLength(int frame) updateLength(); } +/** Extends the tineline frame length if necessary + * + * If the new animation length is more than 75% of the timeline + * frame length, then double the timeline frame length, otherwise + * do nothing. + * + * @param[in] frame The new animation length + */ void TimeLine::extendLength(int frame) { - int extendFrame = frame + 10; - if (extendFrame > mTracks->getFrameLength()) - { - mTracks->setFrameLength(extendFrame); + int frameLength = mTracks->getFrameLength(); + if(frame > frameLength * 0.75) { + mTracks->setFrameLength(frameLength * 1.5); updateLength(); } } From 8d619a7965d1512104df63d38b967e75b1771ac3 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Thu, 17 May 2018 01:12:36 -0600 Subject: [PATCH 061/184] Change flood algorithm to use euclidian distance --- core_lib/src/graphics/bitmap/bitmapimage.cpp | 53 +++++++++++--------- core_lib/src/graphics/bitmap/bitmapimage.h | 2 +- core_lib/src/tool/buckettool.cpp | 2 +- 3 files changed, 31 insertions(+), 26 deletions(-) diff --git a/core_lib/src/graphics/bitmap/bitmapimage.cpp b/core_lib/src/graphics/bitmap/bitmapimage.cpp index 160d88ae8..9882249fb 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.cpp +++ b/core_lib/src/graphics/bitmap/bitmapimage.cpp @@ -18,6 +18,7 @@ GNU General Public License for more details. #include #include +#include #include "util.h" BitmapImage::BitmapImage() @@ -528,34 +529,36 @@ void BitmapImage::clear(QRect rectangle) modification(); } -bool BitmapImage::compareColor(QRgb color1, QRgb color2, int tolerance) +/** Compare colors for the purposes of flood filling + * + * Calculates the Eulcidian difference of the RGB channels + * of the image and compares it to the tolerance + * + * @param[in] newColor The first color to compare + * @param[in] oldColor The second color to compare + * @param[in] tolerance The threshold limit between a matching and non-matching color + * + * @return Returns true if the colors have a similarity below the tolerance level + * (i.e. if Eulcidian distance squared is <= tolerance) + */ +bool BitmapImage::compareColor(QRgb newColor, QRgb oldColor, int tolerance) { - if (color1 == color2) return true; + // Handle trivial case + if (newColor == oldColor) return true; - int red1 = qRed(color1); - int green1 = qGreen(color1); - int blue1 = qBlue(color1); - int alpha1 = qAlpha(color1); + // Get Eulcidian distance between colors + // Not an accurate representation of human perception, + // but it's the best any image editing program ever does + int diffRed = qPow(qRed(oldColor) - qRed(newColor), 2); + int diffGreen = qPow(qGreen(oldColor) - qGreen(newColor), 2); + int diffBlue = qPow(qBlue(oldColor) - qBlue(newColor), 2); + // This may not be the best way to handle alpha since the other channels become less relevant as + // the alpha is reduces (ex. QColor(0,0,0,0) is the same as QColor(255,255,255,0)) + int diffAlpha = qPow(qAlpha(oldColor) - qAlpha(newColor), 2); - int red2 = qRed(color2); - int green2 = qGreen(color2); - int blue2 = qBlue(color2); - int alpha2 = qAlpha(color2); + bool isSimilar = (diffRed + diffGreen + diffBlue + diffAlpha) <= tolerance; - int diffRed = abs(red2 - red1); - int diffGreen = abs(green2 - green1); - int diffBlue = abs(blue2 - blue1); - int diffAlpha = abs(alpha2 - alpha1); - - if (diffRed > tolerance || - diffGreen > tolerance || - diffBlue > tolerance || - diffAlpha > tolerance) - { - return false; - } - - return true; + return isSimilar; } // Flood fill @@ -572,6 +575,8 @@ void BitmapImage::floodFill(BitmapImage* targetImage, return; } + // Square tolerance for use with compareColor + tolerance = qPow(tolerance, 2); QRgb oldColor = targetImage->pixel(point); oldColor = qRgba(qRed(oldColor), qGreen(oldColor), qBlue(oldColor), qAlpha(oldColor)); diff --git a/core_lib/src/graphics/bitmap/bitmapimage.h b/core_lib/src/graphics/bitmap/bitmapimage.h index 66c633502..871762565 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.h +++ b/core_lib/src/graphics/bitmap/bitmapimage.h @@ -74,7 +74,7 @@ class BitmapImage : public KeyFrame void clear(QRect rectangle); void clear(QRectF rectangle) { clear(rectangle.toRect()); } - static bool compareColor(QRgb color1, QRgb color2, int tolerance); + static bool compareColor(QRgb newColor, QRgb oldColor, int tolerance); static void floodFill(BitmapImage* targetImage, QRect cameraRect, QPoint point, QRgb newColor, int tolerance); void drawLine(QPointF P1, QPointF P2, QPen pen, QPainter::CompositionMode cm, bool antialiasing); diff --git a/core_lib/src/tool/buckettool.cpp b/core_lib/src/tool/buckettool.cpp index 4fb4437cd..d9bec9608 100644 --- a/core_lib/src/tool/buckettool.cpp +++ b/core_lib/src/tool/buckettool.cpp @@ -151,7 +151,7 @@ void BucketTool::paintBitmap(Layer* layer) cameraRect, point, qPremultiply( mEditor->color()->frontColor().rgba() ), - properties.tolerance * 2.55 ); + properties.tolerance ); mScribbleArea->setModified( layerNumber, mEditor->currentFrame() ); mScribbleArea->setAllDirty(); From 1bd6218d6abe76d78288567988028411ce97f417 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 22 May 2018 23:03:55 +1000 Subject: [PATCH 062/184] Remove unwanted connections in ui file --- app/ui/colorpalette.ui | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/app/ui/colorpalette.ui b/app/ui/colorpalette.ui index 8c0cf4880..bde38d637 100644 --- a/app/ui/colorpalette.ui +++ b/app/ui/colorpalette.ui @@ -312,24 +312,7 @@ - - - removeColorButton - clicked() - ColorPalette - clickRemoveColorButton() - - - 36 - 43 - - - 133 - 128 - - - - + colorListCurrentItemChanged(QListWidgetItem*,QListWidgetItem*) clickColorListItem(QListWidgetItem*) From ba81f853990d01fc0c4be387e46224911c085517 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 22 May 2018 23:12:03 +1000 Subject: [PATCH 063/184] Fix #958: Renaming color is not working - the signal currentTextChanged didn't work as expected. It emits signals before users enter the new color name. So even the text on color palette changed, the object doesn't get the new name. --- app/src/colorpalettewidget.cpp | 12 ++++++------ app/src/colorpalettewidget.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/src/colorpalettewidget.cpp b/app/src/colorpalettewidget.cpp index 558ed1caa..14165436b 100644 --- a/app/src/colorpalettewidget.cpp +++ b/app/src/colorpalettewidget.cpp @@ -79,8 +79,9 @@ void ColorPaletteWidget::initUI() connect(ui->colorListWidget, &QListWidget::currentItemChanged, this, &ColorPaletteWidget::colorListCurrentItemChanged); connect(ui->colorListWidget, &QListWidget::itemClicked, this, &ColorPaletteWidget::clickColorListItem); + connect(ui->colorListWidget, &QListWidget::itemDoubleClicked, this, &ColorPaletteWidget::changeColourName); - connect(ui->colorListWidget, &QListWidget::currentTextChanged, this, &ColorPaletteWidget::onActiveColorNameChange); + connect(ui->colorListWidget, &QListWidget::itemChanged, this, &ColorPaletteWidget::onItemChanged); connect(ui->addColorButton, &QPushButton::clicked, this, &ColorPaletteWidget::clickAddColorButton); connect(ui->colorDialogButton, &QPushButton::clicked, this, &ColorPaletteWidget::clickColorDialogButton); @@ -185,12 +186,11 @@ void ColorPaletteWidget::changeColourName(QListWidgetItem* item) } } -void ColorPaletteWidget::onActiveColorNameChange(QString name) +void ColorPaletteWidget::onItemChanged(QListWidgetItem* item) { - if (!name.isNull()) - { - editor()->object()->renameColour(ui->colorListWidget->currentRow(), name); - } + int index = ui->colorListWidget->currentRow(); + QString newColorName = item->text(); + editor()->object()->renameColour(index, newColorName); } void ColorPaletteWidget::colorListCurrentItemChanged(QListWidgetItem* current, QListWidgetItem* previous) diff --git a/app/src/colorpalettewidget.h b/app/src/colorpalettewidget.h index 60529f143..6584d8291 100644 --- a/app/src/colorpalettewidget.h +++ b/app/src/colorpalettewidget.h @@ -64,7 +64,7 @@ private slots: void colorListCurrentItemChanged(QListWidgetItem*, QListWidgetItem*); void clickColorListItem(QListWidgetItem*); void changeColourName(QListWidgetItem*); - void onActiveColorNameChange(QString name); + void onItemChanged(QListWidgetItem* item); void clickAddColorButton(); void clickColorDialogButton(); void clickRemoveColorButton(); From 525914202f144caad902c9b51ba3ea8dbba9655f Mon Sep 17 00:00:00 2001 From: Jakob Gahde Date: Tue, 22 May 2018 15:33:33 +0200 Subject: [PATCH 064/184] Fix Doxygen main page for Travis builds --- util/docs/Doxyfile-Travis | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/docs/Doxyfile-Travis b/util/docs/Doxyfile-Travis index 09d9699d0..587e4c202 100644 --- a/util/docs/Doxyfile-Travis +++ b/util/docs/Doxyfile-Travis @@ -982,7 +982,7 @@ FILTER_SOURCE_PATTERNS = # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. -USE_MDFILE_AS_MAINPAGE = docs/main.md +USE_MDFILE_AS_MAINPAGE = $(TRAVIS_BUILD_DIR)/docs/main.md #--------------------------------------------------------------------------- # Configuration options related to source browsing From c7e28e979bb72396b496f4db7bd9248183e61eb8 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Wed, 23 May 2018 15:52:51 +1000 Subject: [PATCH 065/184] Make a DebugDetails class to give more details during saving files --- app/src/mainwindow2.cpp | 4 +- core_lib/src/graphics/vector/bezierarea.cpp | 11 +- core_lib/src/graphics/vector/beziercurve.cpp | 41 +++---- core_lib/src/graphics/vector/vectorimage.cpp | 29 +++-- core_lib/src/managers/viewmanager.cpp | 2 +- core_lib/src/structure/filemanager.cpp | 17 ++- core_lib/src/structure/layer.cpp | 13 +-- core_lib/src/structure/layerbitmap.cpp | 12 +- core_lib/src/structure/layervector.cpp | 10 +- core_lib/src/util/pencilerror.cpp | 117 +++++++++++-------- core_lib/src/util/pencilerror.h | 46 +++++--- 11 files changed, 171 insertions(+), 131 deletions(-) diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index 41b472c58..336cf4c12 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -601,7 +601,7 @@ bool MainWindow2::saveObject(QString strSavedFileName) if (eLog.open(QIODevice::WriteOnly | QIODevice::Text)) { QTextStream out(&eLog); - out << st.details().replace("
", "\n", Qt::CaseInsensitive); + out << st.details().str(); // .replace("
", "\n", Qt::CaseInsensitive); } eLog.close(); @@ -609,7 +609,7 @@ bool MainWindow2::saveObject(QString strSavedFileName) st.description().append(tr("

An error has occurred and your file may not have saved successfully." "If you believe that this error is an issue with Pencil2D, please create a new issue at:" "
https://github.com/pencil2d/pencil/issues
" - "Please be sure to include the following details in your issue:")), st.details()); + "Please be sure to include the following details in your issue:")), st.details().html()); errorDialog.exec(); return false; } diff --git a/core_lib/src/graphics/vector/bezierarea.cpp b/core_lib/src/graphics/vector/bezierarea.cpp index fdea410cf..0387ff81f 100644 --- a/core_lib/src/graphics/vector/bezierarea.cpp +++ b/core_lib/src/graphics/vector/bezierarea.cpp @@ -72,11 +72,12 @@ Status BezierArea::createDomElement( QXmlStreamWriter& xmlStream ) if ( xmlStream.hasError() && errorLocation >= 0 ) { - QStringList debugInfo = QStringList() << "BezierArea::createDomElement" - << QString( "colourNumber = %1" ).arg( mColourNumber ) - << QString( "- mVertex[%1] has failed to write" ).arg( errorLocation ) - << QString( "  curve = %1" ).arg( mVertex.at( errorLocation ).curveNumber ) - << QString( "  vertex = %1 " ).arg( mVertex.at( errorLocation ).vertexNumber ); + DebugDetails debugInfo; + debugInfo << "BezierArea::createDomElement"; + debugInfo << QString("colourNumber = %1").arg(mColourNumber); + debugInfo << QString("- mVertex[%1] has failed to write").arg(errorLocation); + debugInfo << QString("  curve = %1").arg(mVertex.at(errorLocation).curveNumber); + debugInfo << QString("  vertex = %1 ").arg(mVertex.at(errorLocation).vertexNumber); return Status( Status::FAIL, debugInfo ); } diff --git a/core_lib/src/graphics/vector/beziercurve.cpp b/core_lib/src/graphics/vector/beziercurve.cpp index 773d2b296..c55ff4667 100644 --- a/core_lib/src/graphics/vector/beziercurve.cpp +++ b/core_lib/src/graphics/vector/beziercurve.cpp @@ -110,26 +110,27 @@ Status BezierCurve::createDomElement( QXmlStreamWriter& xmlStream ) if ( xmlStream.hasError() && errorLocation >= 0 ) { - QStringList debugInfo = QStringList() << "BezierCurve::createDomElement" - << QString( "width = %1" ).arg( width ) - << QString( "variableWidth = %1" ).arg( "variableWidth" ) - << QString( "feather = %1" ).arg( feather ) - << QString( "invisible = %1" ).arg( invisible ) - << QString( "filled = %1" ).arg( mFilled ) - << QString( "colourNumber = %1" ).arg( colourNumber ) - << QString( "originX = %1" ).arg( origin.x() ) - << QString( "originY = %1" ).arg( origin.y() ) - << QString( "originPressure = %1" ).arg( pressure.at( 0 ) ) - << QString( "- segmentTag[%1] has failed to write" ).arg( errorLocation ) - << QString( "  c1x = %1" ).arg( c1.at( errorLocation ).x() ) - << QString( "  c1y = %1" ).arg( c1.at( errorLocation ).y() ) - << QString( "  c2x = %1" ).arg( c2.at( errorLocation ).x() ) - << QString( "  c2y = %1" ).arg( c2.at( errorLocation ).y() ) - << QString( "  vx = %1" ).arg( vertex.at( errorLocation ).x() ) - << QString( "  vy = %1" ).arg( vertex.at( errorLocation ).y() ) - << QString( "  pressure = %1" ).arg( pressure.at( errorLocation + 1 ) ); - - return Status( Status::FAIL, debugInfo ); + DebugDetails debugInfo; + debugInfo << "BezierCurve::createDomElement"; + debugInfo << QString("width = %1").arg(width); + debugInfo << QString("variableWidth = %1").arg("variableWidth"); + debugInfo << QString("feather = %1").arg(feather); + debugInfo << QString("invisible = %1").arg(invisible); + debugInfo << QString("filled = %1").arg(mFilled); + debugInfo << QString("colourNumber = %1").arg(colourNumber); + debugInfo << QString("originX = %1").arg(origin.x()); + debugInfo << QString("originY = %1").arg(origin.y()); + debugInfo << QString("originPressure = %1").arg(pressure.at(0)); + debugInfo << QString("- segmentTag[%1] has failed to write").arg(errorLocation); + debugInfo << QString("  c1x = %1").arg(c1.at(errorLocation).x()); + debugInfo << QString("  c1y = %1").arg(c1.at(errorLocation).y()); + debugInfo << QString("  c2x = %1").arg(c2.at(errorLocation).x()); + debugInfo << QString("  c2y = %1").arg(c2.at(errorLocation).y()); + debugInfo << QString("  vx = %1").arg(vertex.at(errorLocation).x()); + debugInfo << QString("  vy = %1").arg(vertex.at(errorLocation).y()); + debugInfo << QString("  pressure = %1").arg(pressure.at(errorLocation + 1)); + + return Status(Status::FAIL, debugInfo); } return Status::OK; diff --git a/core_lib/src/graphics/vector/vectorimage.cpp b/core_lib/src/graphics/vector/vectorimage.cpp index faca4c54e..cf2d36744 100644 --- a/core_lib/src/graphics/vector/vectorimage.cpp +++ b/core_lib/src/graphics/vector/vectorimage.cpp @@ -88,7 +88,7 @@ bool VectorImage::read(QString filePath) */ Status VectorImage::write(QString filePath, QString format) { - QStringList debugInfo; + DebugDetails debugInfo; debugInfo << "VectorImage::write"; debugInfo << QString("filePath = ").append(filePath); debugInfo << QString("format = ").append(format); @@ -98,13 +98,14 @@ Status VectorImage::write(QString filePath, QString format) if (!result) { qDebug() << "VectorImage - Cannot write file" << filePath << file.error(); - return Status(Status::FAIL, debugInfo << QString("file.error() = ").append(file.errorString())); + debugInfo << ("file.error() = " + file.errorString()); + return Status(Status::FAIL, debugInfo); } if (format != "VEC") { - qDebug() << "--- Not the VEC format!"; - return Status(Status::FAIL, debugInfo << "Unrecognized format"); + debugInfo << "Unrecognized format"; + return Status(Status::FAIL, debugInfo); } QXmlStreamWriter xmlStream(&file); @@ -114,11 +115,13 @@ Status VectorImage::write(QString filePath, QString format) xmlStream.writeStartElement("image"); xmlStream.writeAttribute("type", "vector"); + Status st = createDomElement(xmlStream); if (!st.ok()) { - const QString xmlDetails = st.detailsList().join("  "); - return Status(Status::FAIL, debugInfo << "- xml creation failed" << xmlDetails); + debugInfo.collect(st.details()); + debugInfo << "- xml creation failed"; + return Status(Status::FAIL, debugInfo); } xmlStream.writeEndElement(); // Close image element xmlStream.writeEndDocument(); @@ -134,14 +137,17 @@ Status VectorImage::write(QString filePath, QString format) */ Status VectorImage::createDomElement(QXmlStreamWriter& xmlStream) { - QStringList debugInfo = QStringList() << "VectorImage::createDomElement"; + DebugDetails debugInfo; + debugInfo << "VectorImage::createDomElement"; + for (int i = 0; i < mCurves.size(); i++) { Status st = mCurves[i].createDomElement(xmlStream); if (!st.ok()) { - const QString curveDetails = st.detailsList().join("  "); - return Status(Status::FAIL, debugInfo << QString("- m_curves[%1] failed to write").arg(i) << curveDetails); + debugInfo.collect(st.details()); + debugInfo << QString("- m_curves[%1] failed to write").arg(i); + return Status(Status::FAIL, debugInfo); } } for (int i = 0; i < mArea.size(); i++) @@ -149,8 +155,9 @@ Status VectorImage::createDomElement(QXmlStreamWriter& xmlStream) Status st = mArea[i].createDomElement(xmlStream); if (!st.ok()) { - const QString areaDetails = st.detailsList().join("  "); - return Status(Status::FAIL, debugInfo << QString("- area[%1] failed to write").arg(i) << areaDetails); + debugInfo.collect(st.details()); + debugInfo << QString("- area[%1] failed to write").arg(i); + return Status(Status::FAIL, debugInfo); } } return Status::OK; diff --git a/core_lib/src/managers/viewmanager.cpp b/core_lib/src/managers/viewmanager.cpp index e19958c2c..786a086cf 100644 --- a/core_lib/src/managers/viewmanager.cpp +++ b/core_lib/src/managers/viewmanager.cpp @@ -58,7 +58,7 @@ Status ViewManager::load(Object*) Status ViewManager::save(Object* o) { o->data()->setCurrentView(mView); - return Status(); + return Status::OK; } void ViewManager::workingLayerChanged(Layer* layer) diff --git a/core_lib/src/structure/filemanager.cpp b/core_lib/src/structure/filemanager.cpp index 9639ebfc0..7d0a57689 100644 --- a/core_lib/src/structure/filemanager.cpp +++ b/core_lib/src/structure/filemanager.cpp @@ -177,13 +177,14 @@ bool FileManager::isOldForamt(const QString& fileName) Status FileManager::save(Object* object, QString strFileName) { - QStringList debugDetails; + DebugDetails debugDetails; debugDetails << "FileManager::save"; - debugDetails << QString("strFileName = ").append(strFileName); + debugDetails << ("strFileName = " + strFileName); if (object == nullptr) { - return Status(Status::INVALID_ARGUMENT, debugDetails << "object parameter is null"); + debugDetails << "object parameter is null"; + return Status(Status::INVALID_ARGUMENT, debugDetails); } int totalCount = object->totalKeyFrameCount(); @@ -281,12 +282,8 @@ Status FileManager::save(Object* object, QString strFileName) if (!st.ok()) { saveLayerOK = false; - QStringList layerDetails = st.detailsList(); - for (QString& detail : layerDetails) - { - detail.prepend("  "); - } - debugDetails << QString("- Layer[%1] failed to save").arg(i) << layerDetails; + debugDetails.collect(st.details()); + debugDetails << QString("- Layer[%1] failed to save").arg(i); } } @@ -333,7 +330,7 @@ Status FileManager::save(Object* object, QString strFileName) if (!ok) { return Status(Status::ERROR_MINIZ_FAIL, debugDetails, - tr("Internal Error"), + tr("MiniZ Error"), tr("An internal error occurred. Your file may not be saved successfully.")); } qCDebug(mLog) << "Compressed. File saved."; diff --git a/core_lib/src/structure/layer.cpp b/core_lib/src/structure/layer.cpp index 6b8aa90b8..6cd1b582b 100644 --- a/core_lib/src/structure/layer.cpp +++ b/core_lib/src/structure/layer.cpp @@ -279,11 +279,12 @@ bool Layer::loadKey(KeyFrame* pKey) Status Layer::save(QString strDataFolder, ProgressCallback progressStep) { - QStringList debugInfo; + DebugDetails debugInfo; debugInfo << "Layer::save"; - debugInfo << QString("strDataFolder = ").append(strDataFolder); + debugInfo << ("strDataFolder = " + strDataFolder); bool isOkay = true; + for (auto pair : mKeyFrames) { KeyFrame* pKeyFrame = pair.second; @@ -292,12 +293,8 @@ Status Layer::save(QString strDataFolder, ProgressCallback progressStep) { isOkay = false; - QStringList keyFrameDetails = st.detailsList(); - for (QString detail : keyFrameDetails) - { - detail.prepend("  "); - } - debugInfo << QString("- Keyframe[%1] failed to save").arg(pKeyFrame->pos()) << keyFrameDetails; + debugInfo.collect(st.details()); + debugInfo << QString("- Keyframe[%1] failed to save").arg(pKeyFrame->pos()); // << keyFrameDetails; } progressStep(); } diff --git a/core_lib/src/structure/layerbitmap.cpp b/core_lib/src/structure/layerbitmap.cpp index 96e0d1db4..82b392023 100644 --- a/core_lib/src/structure/layerbitmap.cpp +++ b/core_lib/src/structure/layerbitmap.cpp @@ -67,12 +67,12 @@ Status LayerBitmap::saveKeyFrameFile(KeyFrame* keyframe, QString path) Status st = bitmapImage->writeFile(strFilePath); if (!st.ok()) { - QStringList debugInfo; - debugInfo << "LayerBitmap::saveKeyFrame" - << QString(" KeyFrame.pos() = %1").arg(keyframe->pos()) - << QString(" path = %1").arg(path) - << QString(" strFilePath = %1").arg(strFilePath) - << QString("BitmapImage could not be saved"); + DebugDetails debugInfo; + debugInfo << "LayerBitmap::saveKeyFrame"; + debugInfo << QString(" KeyFrame.pos() = %1").arg(keyframe->pos()); + debugInfo << QString(" path = %1").arg(path); + debugInfo << QString(" strFilePath = %1").arg(strFilePath); + debugInfo << QString("BitmapImage could not be saved"); return Status(Status::FAIL, debugInfo); } diff --git a/core_lib/src/structure/layervector.cpp b/core_lib/src/structure/layervector.cpp index 0c5dec964..5967a1ef3 100644 --- a/core_lib/src/structure/layervector.cpp +++ b/core_lib/src/structure/layervector.cpp @@ -80,18 +80,14 @@ Status LayerVector::saveKeyFrameFile(KeyFrame* keyFrame, QString path) Status st = vecImage->write(strFilePath, "VEC"); if (!st.ok()) { - QStringList debugInfo; + DebugDetails debugInfo; debugInfo << "LayerVector::saveKeyFrame"; debugInfo << QString("pKeyFrame.pos() = %1").arg(keyFrame->pos()); debugInfo << QString("path = ").append(path); debugInfo << QString("strFilePath = ").append(strFilePath); - QStringList vecImageDetails = st.detailsList(); - for (QString detail : vecImageDetails) - { - detail.prepend("  "); - } - debugInfo << QString("- VectorImage failed to write") << vecImageDetails; + debugInfo.collect(st.details()); + debugInfo << "- VectorImage failed to write"; return Status(Status::FAIL, debugInfo); } diff --git a/core_lib/src/util/pencilerror.cpp b/core_lib/src/util/pencilerror.cpp index 4b3832732..c343b683c 100644 --- a/core_lib/src/util/pencilerror.cpp +++ b/core_lib/src/util/pencilerror.cpp @@ -21,65 +21,90 @@ GNU General Public License for more details. #include #include "pencildef.h" -Status::Status(Status::ErrorCode eCode, QStringList detailsList, QString title, QString description) - : mCode( eCode ) - , mTitle( title ) - , mDescription( description ) - , mDetails( detailsList ) +DebugDetails::DebugDetails() { } -QString Status::msg() +DebugDetails::~DebugDetails() { - static std::map msgMap = - { - // error messages. - { OK, QObject::tr( "Everything ok." ) }, - { FAIL, QObject::tr( "Ooops, Something went wrong." ) }, - { FILE_NOT_FOUND, QObject::tr( "File doesn't exist." ) }, - { ERROR_FILE_CANNOT_OPEN, QObject::tr( "Cannot open file." ) }, - { ERROR_INVALID_XML_FILE, QObject::tr( "The file is not a valid xml document." ) }, - { ERROR_INVALID_PENCIL_FILE, QObject::tr( "The file is not valid pencil document." ) }, - }; +} - auto it = msgMap.find( mCode ); - if ( it == msgMap.end() ) +void DebugDetails::collect(const DebugDetails& d) +{ + for (const QString& s : d.mDetails) { - return msgMap[ FAIL ]; + mDetails.append("  " + s); } - return msgMap[ mCode ]; } -QString Status::details() +QString DebugDetails::str() { - QString details = mDetails.join("
"); - details.append("

"); - details.append( QString( - "Error Display
" - "Title: %1
" - "Description: %2" - ).arg( mTitle, - mDescription ) - ); - details.append("

"); + appendSystemInfo(); + return mDetails.join("\n"); +} + +QString DebugDetails::html() +{ + appendSystemInfo(); + return mDetails.join("
"); +} + +DebugDetails& DebugDetails::operator<<(const QString& s) +{ + mDetails.append(s); + return *this; +} + +void DebugDetails::appendSystemInfo() +{ + if (mDetails.last() == "end") + return; + #if QT_VERSION >= 0x050400 - details.append( QString( - "System Info
" - "Pencil version: %1
" - "Build ABI: %2
" - "Kernel: %3 %4
" - "Product name: %5" - ).arg( APP_VERSION, - QSysInfo::buildAbi(), - QSysInfo::kernelType(), - QSysInfo::kernelVersion(), - QSysInfo::prettyProductName() ) - ); + mDetails << "System Info"; + mDetails << "Pencil version: " APP_VERSION; + mDetails << "Build ABI: " + QSysInfo::buildAbi(); + mDetails << "Kernel: " + QSysInfo::kernelType() + ", " + QSysInfo::kernelVersion(); + mDetails << "Operating System: " + QSysInfo::prettyProductName(); + mDetails << "end"; #endif - return details; } -bool Status::operator==( Status::ErrorCode code ) const +Status::Status(ErrorCode code) + : mCode(code) +{ +} + +Status::Status(Status::ErrorCode eCode, const DebugDetails& detailsList, QString title, QString description) + : mCode(eCode) + , mTitle(title) + , mDescription(description) + , mDetails(detailsList) +{ +} + +QString Status::msg() +{ + static std::map msgMap = + { + // error messages. + { OK, QObject::tr("Everything ok.") }, + { FAIL, QObject::tr("Ooops, Something went wrong.") }, + { FILE_NOT_FOUND, QObject::tr("File doesn't exist.") }, + { ERROR_FILE_CANNOT_OPEN, QObject::tr("Cannot open file.") }, + { ERROR_INVALID_XML_FILE, QObject::tr("The file is not a valid xml document.") }, + { ERROR_INVALID_PENCIL_FILE, QObject::tr("The file is not valid pencil document.") }, + }; + + auto it = msgMap.find(mCode); + if (it == msgMap.end()) + { + return msgMap[FAIL]; + } + return msgMap[mCode]; +} + +bool Status::operator==(Status::ErrorCode code) const { - return ( mCode == code ); + return (mCode == code); } diff --git a/core_lib/src/util/pencilerror.h b/core_lib/src/util/pencilerror.h index aaf4cc4e1..64aa438c5 100644 --- a/core_lib/src/util/pencilerror.h +++ b/core_lib/src/util/pencilerror.h @@ -18,9 +18,26 @@ GNU General Public License for more details. #ifndef PENCILERROR_H #define PENCILERROR_H -#include #include + +class DebugDetails +{ +public: + DebugDetails(); + ~DebugDetails(); + + void collect(const DebugDetails& d); + QString str(); + QString html(); + DebugDetails& operator<<(const QString& s); + +private: + void appendSystemInfo(); + QStringList mDetails; +}; + + class Status { public: @@ -56,32 +73,31 @@ class Status ERROR_NEED_AT_LEAST_ONE_CAMERA_LAYER, }; - - Status() {} - Status( ErrorCode eCode, QStringList detailsList = QStringList(), QString title = QString(), QString description = QString() ); + Status(ErrorCode code); + Status(ErrorCode code, const DebugDetails& detailsList, QString title = "", QString description = ""); ErrorCode code() { return mCode; } - bool ok() const { return ( mCode == OK ) || ( mCode == SAFE ); } + bool ok() const { return (mCode == OK) || (mCode == SAFE); } QString msg(); QString title() { return !mTitle.isEmpty() ? mTitle : msg(); } - QString description() { return mDescription; } - QString details(); - QStringList detailsList() { return mDetails; } + QString description() const { return mDescription; } + DebugDetails details() const { return mDetails; } - void setTitle( QString title ) { mTitle = title; } - void setDescription( QString description ) { mDescription = description; } - void setDetailsList( QStringList detailsList ) { mDetails = detailsList; } + void setTitle(QString title) { mTitle = title; } + void setDescription(QString description) { mDescription = description; } - bool operator==( ErrorCode code ) const; + bool operator==(ErrorCode code) const; private: ErrorCode mCode = OK; - QString mTitle, mDescription; - QStringList mDetails; + QString mTitle; + QString mDescription; + DebugDetails mDetails; }; #ifndef STATUS_CHECK #define STATUS_CHECK( x )\ - { Status st = (x); if ( !st.ok() ) { return st; } } + { Status st = (x); if (!st.ok()) { return st; } } #endif + #endif // PENCILERROR_H From 6121e0e3041a72f74c9eec79b4bfaa9cb40808e5 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Sat, 26 May 2018 11:36:33 +1000 Subject: [PATCH 066/184] Revert the link change --- docs/build_linux.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/build_linux.md b/docs/build_linux.md index deb78ba9d..878bc71bb 100644 --- a/docs/build_linux.md +++ b/docs/build_linux.md @@ -107,4 +107,4 @@ You can then open Pencil2D by running this from the source directory: ## Next steps -Now that you can build Pencil2D, the next step is to learn about [navigating the source code](dive-into-code.md). +Now that you can build Pencil2D, the next step is to learn about [navigating the source code](docs/dive-into-code.md). From fb96101b5b6ab631b83e1b132fee40d5c63f77ac Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Fri, 25 May 2018 21:59:51 -0600 Subject: [PATCH 067/184] Fix incorrect image scale in movieexporter Fixes #982 --- core_lib/src/movieexporter.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/core_lib/src/movieexporter.cpp b/core_lib/src/movieexporter.cpp index b197c8439..cfb197021 100644 --- a/core_lib/src/movieexporter.cpp +++ b/core_lib/src/movieexporter.cpp @@ -432,7 +432,7 @@ Status MovieExporter::generateMovie( QString strCmd = QString("\"%1\"").arg(ffmpegPath); strCmd += QString(" -f rawvideo -pixel_format bgra"); - strCmd += QString(" -video_size %1x%2").arg(camSize.width()).arg(camSize.height()); + strCmd += QString(" -video_size %1x%2").arg(exportSize.width()).arg(exportSize.height()); strCmd += QString(" -framerate %1").arg(mDesc.fps); //strCmd += QString( " -r %1").arg( exportFps ); @@ -444,7 +444,6 @@ Status MovieExporter::generateMovie( strCmd += QString(" -i \"%1\" ").arg(tempAudioPath); } - strCmd += QString(" -s %1x%2").arg(exportSize.width()).arg(exportSize.height()); if(strOutputFile.endsWith(".apng")) { strCmd += QString(" -plays %1").arg(loop ? "0" : "1"); @@ -564,15 +563,13 @@ Status MovieExporter::generateGif( QString strCmd = QString("\"%1\"").arg(ffmpegPath); strCmd += QString(" -f rawvideo -pixel_format bgra"); - strCmd += QString(" -video_size %1x%2").arg(camSize.width()).arg(camSize.height()); + strCmd += QString(" -video_size %1x%2").arg(exportSize.width()).arg(exportSize.height()); strCmd += QString(" -framerate %1").arg(mDesc.fps); strCmd += " -i -"; strCmd += " -y"; - strCmd += QString(" -s %1x%2").arg(exportSize.width()).arg(exportSize.height()); - strCmd += " -filter_complex \"[0:v]palettegen [p]; [0:v][p] paletteuse\""; strCmd += QString(" -loop %1").arg(loop ? "0" : "-1"); From c816e54b15587de6a001110b39f67980931cb1f6 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Fri, 25 May 2018 23:47:27 -0600 Subject: [PATCH 068/184] Do not show a second warning dialog if file open fails From my understanding, newDocument needs to be called if file open encounters an error or else the program could be left in a bad state. Users are already prompted about unsaved changes when they try to open a file, so there should be no additional risk of loosing unsaved work as a result of these changes. --- app/src/mainwindow2.cpp | 8 ++++---- app/src/mainwindow2.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index 336cf4c12..b1dfb704e 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -431,9 +431,9 @@ void MainWindow2::tabletEvent(QTabletEvent* event) event->ignore(); } -void MainWindow2::newDocument() +void MainWindow2::newDocument(bool force) { - if (maybeSave()) + if (force || maybeSave()) { Object* object = new Object(); object->init(); @@ -471,7 +471,7 @@ void MainWindow2::openDocument() if (!ok) { QMessageBox::warning(this, tr("Warning"), tr("Pencil cannot read this file. If you want to import images, use the command import.")); - newDocument(); + newDocument(true); } } updateSaveState(); @@ -501,7 +501,7 @@ void MainWindow2::openFile(QString filename) if (!ok) { QMessageBox::warning(this, tr("Warning"), tr("Pencil cannot read this file. If you want to import images, use the command import.")); - newDocument(); + newDocument(true); } } } diff --git a/app/src/mainwindow2.h b/app/src/mainwindow2.h index cba5e3f26..bcf22bf6b 100644 --- a/app/src/mainwindow2.h +++ b/app/src/mainwindow2.h @@ -68,7 +68,7 @@ class MainWindow2 : public QMainWindow public: void setOpacity(int opacity); - void newDocument(); + void newDocument(bool force = false); void openDocument(); bool saveDocument(); bool saveAsNewDocument(); From 24298db8340fd50d880c3c65e859ba857f8efb2f Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Sat, 26 May 2018 02:33:30 -0600 Subject: [PATCH 069/184] Produce much more useful error messages when file open fails --- app/src/mainwindow2.cpp | 85 ++++++++++++++++++++------ app/src/mainwindow2.h | 2 +- app/ui/errordialog.ui | 3 + core_lib/src/structure/filemanager.cpp | 76 +++++++++++++++++++++-- 4 files changed, 141 insertions(+), 25 deletions(-) diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index b1dfb704e..b79103d59 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -467,14 +467,8 @@ void MainWindow2::openDocument() return; } - bool ok = openObject(fileName); - if (!ok) - { - QMessageBox::warning(this, tr("Warning"), tr("Pencil cannot read this file. If you want to import images, use the command import.")); - newDocument(true); - } + openObject(fileName, false); } - updateSaveState(); } bool MainWindow2::saveAsNewDocument() @@ -495,19 +489,53 @@ bool MainWindow2::saveAsNewDocument() void MainWindow2::openFile(QString filename) { - if (maybeSave()) - { - bool ok = openObject(filename); - if (!ok) - { - QMessageBox::warning(this, tr("Warning"), tr("Pencil cannot read this file. If you want to import images, use the command import.")); - newDocument(true); - } - } + openObject(filename, true); } -bool MainWindow2::openObject(QString strFilePath) +bool MainWindow2::openObject(QString strFilePath, bool checkForChanges) { + if(checkForChanges && !maybeSave()) return false; // Open cancelled by user + + // Check for potential issues with the file + QFileInfo fileInfo(strFilePath); + if (fileInfo.isDir()) + { + ErrorDialog errorDialog(tr("Could not open file"), + tr("The file you have selected is a directory, so we are unable to open it. " + "If you are are trying to open a project that uses the old structure, please " + "open the file ending with .pcl, not the data folder."), + QString("Raw file path: %1\nResolved file path: %2").arg(strFilePath, fileInfo.absoluteFilePath())); + errorDialog.exec(); + return false; + } + if (!fileInfo.exists()) + { + ErrorDialog errorDialog(tr("Could not open file"), + tr("The file you have selected does not exist, so we are unable to open it. Please check " + "to make sure that you've entered the correct path and that the file is accessible and try again."), + QString("Raw file path: %1\nResolved file path: %2").arg(strFilePath, fileInfo.absoluteFilePath())); + errorDialog.exec(); + return false; + } + if (!fileInfo.isReadable()) + { + ErrorDialog errorDialog(tr("Could not open file"), + tr("This program does not have permission to read the file you have selected. " + "Please check that you have read permissions for this file and try again."), + QString("Raw file path: %1\nResolved file path: %2\nPermissions: 0x%3") \ + .arg(strFilePath, fileInfo.absoluteFilePath(), QString::number(fileInfo.permissions(), 16))); + errorDialog.exec(); + return false; + } + if (!fileInfo.isWritable()) + { + QMessageBox::warning(this, tr("Warning"), + tr("This program does not currently have permission to write to the file you have selected. " + "Please make sure you have write permission for this file before attempting to save it. " + "Alternatively, you can use the Save As... menu option to save to a writable location."), + QMessageBox::Ok); + } + QProgressDialog progress(tr("Opening document..."), tr("Abort"), 0, 100, this); // Don't show progress bar if running without a GUI (aka. when rendering from command line) @@ -535,8 +563,27 @@ bool MainWindow2::openObject(QString strFilePath) Object* object = fm.load(strFilePath); - if (object == nullptr || !fm.error().ok()) + if (!fm.error().ok()) { + Status error = fm.error(); + DebugDetails dd; + dd << QString("Raw file path: ").append(strFilePath) + << QString("Resolved file path: ").append(fileInfo.absoluteFilePath()); + dd.collect(error.details()); + ErrorDialog errorDialog(error.title(), + error.description(), + dd.str()); + errorDialog.exec(); + newDocument(true); + return false; + } + + if (object == nullptr) { + ErrorDialog errorDialog(tr("Could not open file"), + tr("An unknown error occurred while trying to load the file and we are not able to load your file."), + QString("Raw file path: %1\nResolved file path: %2").arg(strFilePath, fileInfo.absoluteFilePath())); + errorDialog.exec(); + newDocument(true); return false; } @@ -560,6 +607,8 @@ bool MainWindow2::openObject(QString strFilePath) progress.setValue(progress.maximum()); + updateSaveState(); + return true; } diff --git a/app/src/mainwindow2.h b/app/src/mainwindow2.h index bcf22bf6b..ac89b6bff 100644 --- a/app/src/mainwindow2.h +++ b/app/src/mainwindow2.h @@ -99,7 +99,7 @@ private slots: void resetAndDockAllSubWidgets(); private: - bool openObject(QString strFilename); + bool openObject(QString strFilename, bool checkForChanges); bool saveObject(QString strFileName); void createDockWidgets(); diff --git a/app/ui/errordialog.ui b/app/ui/errordialog.ui index 71cdf0412..7e955dca5 100644 --- a/app/ui/errordialog.ui +++ b/app/ui/errordialog.ui @@ -73,6 +73,9 @@ true + + true + diff --git a/core_lib/src/structure/filemanager.cpp b/core_lib/src/structure/filemanager.cpp index 7d0a57689..567cc9624 100644 --- a/core_lib/src/structure/filemanager.cpp +++ b/core_lib/src/structure/filemanager.cpp @@ -32,10 +32,14 @@ mLog("FileManager") Object* FileManager::load(QString strFileName) { + DebugDetails dd; + dd << QString("File name: ").append(strFileName); if (!QFile::exists(strFileName)) { qCDebug(mLog) << "ERROR - File doesn't exist."; - return cleanUpWithErrorCode(Status::FILE_NOT_FOUND); + return cleanUpWithErrorCode(Status(Status::FILE_NOT_FOUND, dd, tr("Could not open file"), + tr("The file you have selected does not exist, so we are unable to open it. Please check " + "to make sure that you've entered the correct path and that the file is accessible and try again."))); } progressForward(); @@ -49,6 +53,7 @@ Object* FileManager::load(QString strFileName) // Test file format: new zipped .pclx or old .pcl? bool oldFormat = isOldForamt(strFileName); + dd << QString("Is old format: ").append(oldFormat ? "true" : "false"); if (oldFormat) { @@ -70,6 +75,9 @@ Object* FileManager::load(QString strFileName) qCDebug(mLog) << " XML=" << strMainXMLFile; qCDebug(mLog) << " Data Folder=" << strDataFolder; qCDebug(mLog) << " Working Folder=" << obj->workingDir(); + dd << QString("XML file: ").append(strMainXMLFile) + << QString("Data folder: ").append(strDataFolder) + << QString("Working folder: ").append(obj->workingDir()); obj->setDataDir(strDataFolder); obj->setMainXMLFile(strMainXMLFile); @@ -79,28 +87,74 @@ Object* FileManager::load(QString strFileName) emit progressRangeChanged(mMaxProgressValue); QFile file(strMainXMLFile); + if (!file.exists()) + { + dd << "Main XML file does not exist"; + return cleanUpWithErrorCode(Status(Status::ERROR_INVALID_XML_FILE, dd, tr("Could not open file"), + tr("There was an error processing your file. This usually means that your project has " + "been at least partially corrupted. You can try again with a newer version of Pencil2D, " + "or you can try to use a backup file if you have one. If you contact us through one of " + "our offical channels we may be able to further assist you. For reporting issues, " + "the best places to reach us are:").append(""))); + } if (!file.open(QFile::ReadOnly)) { - return cleanUpWithErrorCode(Status::ERROR_FILE_CANNOT_OPEN); + return cleanUpWithErrorCode(Status(Status::ERROR_FILE_CANNOT_OPEN, dd, tr("Could not open file"), + tr("This program does not have permission to read the file you have selected. " + "Please check that you have read permissions for this file and try again."))); } QDomDocument xmlDoc; if (!xmlDoc.setContent(&file)) { qCDebug(mLog) << "Couldn't open the main XML file."; - return cleanUpWithErrorCode(Status::ERROR_INVALID_XML_FILE); + dd << "Error parsing or opening the main XML file"; + return cleanUpWithErrorCode(Status(Status::ERROR_INVALID_XML_FILE, dd, tr("Could not open file"), + tr("There was an error processing your file. This usually means that your project has " + "been at least partially corrupted. You can try again with a newer version of Pencil2D, " + "or you can try to use a backup file if you have one. If you contact us through one of " + "our offical channels we may be able to further assist you. For reporting issues, " + "the best places to reach us are:").append(""))); } QDomDocumentType type = xmlDoc.doctype(); if (!(type.name() == "PencilDocument" || type.name() == "MyObject")) { - return cleanUpWithErrorCode(Status::ERROR_INVALID_PENCIL_FILE); + dd << QString("Invalid main XML doctype: ").append(type.name()); + return cleanUpWithErrorCode(Status(Status::ERROR_INVALID_PENCIL_FILE, dd, tr("Could not open file"), + tr("There was an error processing your file. This usually means that your project has " + "been at least partially corrupted. You can try again with a newer version of Pencil2D, " + "or you can try to use a backup file if you have one. If you contact us through one of " + "our offical channels we may be able to further assist you. For reporting issues, " + "the best places to reach us are:").append(""))); } QDomElement root = xmlDoc.documentElement(); if (root.isNull()) { - return cleanUpWithErrorCode(Status::ERROR_INVALID_PENCIL_FILE); + dd << "Main XML root node is null"; + return cleanUpWithErrorCode(Status(Status::ERROR_INVALID_PENCIL_FILE, dd, tr("Could not open file"), + tr("There was an error processing your file. This usually means that your project has " + "been at least partially corrupted. You can try again with a newer version of Pencil2D, " + "or you can try to use a backup file if you have one. If you contact us through one of " + "our offical channels we may be able to further assist you. For reporting issues, " + "the best places to reach us are:").append(""))); } loadPalette(obj); @@ -119,7 +173,17 @@ Object* FileManager::load(QString strFileName) if (!ok) { delete obj; - return cleanUpWithErrorCode(Status::ERROR_INVALID_PENCIL_FILE); + dd << "Issue occurred during object loading"; + return cleanUpWithErrorCode(Status(Status::ERROR_INVALID_PENCIL_FILE, dd, tr("Could not open file"), + tr("There was an error processing your file. This usually means that your project has " + "been at least partially corrupted. You can try again with a newer version of Pencil2D, " + "or you can try to use a backup file if you have one. If you contact us through one of " + "our offical channels we may be able to further assist you. For reporting issues, " + "the best places to reach us are:").append(""))); } verifyObject(obj); From 320e0b5841c48fd6d37039e99b0039f0fb28cbbe Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Sat, 26 May 2018 02:55:36 -0600 Subject: [PATCH 070/184] Include commit information in DebugDetails::appendSystemInfo --- app/src/aboutdialog.cpp | 7 ++----- core_lib/src/util/pencildef.h | 4 ++++ core_lib/src/util/pencilerror.cpp | 9 ++++++++- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/app/src/aboutdialog.cpp b/app/src/aboutdialog.cpp index f3c68b4c5..edb6a3221 100644 --- a/app/src/aboutdialog.cpp +++ b/app/src/aboutdialog.cpp @@ -21,6 +21,8 @@ GNU General Public License for more details. #include #include +#include "pencildef.h" + AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent), ui(new Ui::AboutDialog) @@ -37,11 +39,6 @@ AboutDialog::~AboutDialog() void AboutDialog::init() { -#define STRINGIFY(x) #x -#define TOSTRING(x) STRINGIFY(x) -#define S__GIT_TIMESTAMP TOSTRING(GIT_TIMESTAMP) -#define S__GIT_COMMIT_HASH TOSTRING(GIT_CURRENT_SHA1) - QStringList devText; devText << tr("Version: %1", "Version Number in About Dialog").arg(APP_VERSION); #if defined(GIT_EXISTS) && defined(NIGHTLY_BUILD) diff --git a/core_lib/src/util/pencildef.h b/core_lib/src/util/pencildef.h index cb2d5354a..aee0eb282 100644 --- a/core_lib/src/util/pencildef.h +++ b/core_lib/src/util/pencildef.h @@ -28,6 +28,10 @@ GNU General Public License for more details. #define PENCIL_IMAGE_FILTER \ QObject::tr( "Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif)" ) +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) +#define S__GIT_TIMESTAMP TOSTRING(GIT_TIMESTAMP) +#define S__GIT_COMMIT_HASH TOSTRING(GIT_CURRENT_SHA1) enum ToolType : int { diff --git a/core_lib/src/util/pencilerror.cpp b/core_lib/src/util/pencilerror.cpp index c343b683c..433c44c73 100644 --- a/core_lib/src/util/pencilerror.cpp +++ b/core_lib/src/util/pencilerror.cpp @@ -62,7 +62,14 @@ void DebugDetails::appendSystemInfo() #if QT_VERSION >= 0x050400 mDetails << "System Info"; - mDetails << "Pencil version: " APP_VERSION; +#if !defined(PENCIL2D_RELEASE) + mDetails << "Pencil version: " APP_VERSION " (dev)"; +#else + mDetails << "Pencil version: " APP_VERSION " (stable)"; +#endif +#if defined(GIT_EXISTS) + mDetails << "Commit: " S__GIT_COMMIT_HASH; +#endif mDetails << "Build ABI: " + QSysInfo::buildAbi(); mDetails << "Kernel: " + QSysInfo::kernelType() + ", " + QSysInfo::kernelVersion(); mDetails << "Operating System: " + QSysInfo::prettyProductName(); From 24f1ff07bcb128015af75e34f9dc5ba5ebc6661c Mon Sep 17 00:00:00 2001 From: CandyFace Date: Sat, 26 May 2018 18:05:33 +0200 Subject: [PATCH 071/184] Look for next frame if previous doesn't exist - #950 --- core_lib/src/interface/scribblearea.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index 8912995a8..e3fefc20e 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -517,16 +517,28 @@ void ScribbleArea::mousePressEvent(QMouseEvent* event) Layer* layer = mEditor->layers()->currentLayer(); Q_ASSUME(layer != nullptr); + bool keyExists = layer->keyExists(mEditor->currentFrame()); + int keyFrameIndex = mEditor->currentFrame(); + + // usually we look the previous frame but if there's no previous frame to look for + // bad stuff happens, therefore look for next index + // we know that one has to exist. + if (!keyExists) + keyFrameIndex = mEditor->layers()->currentLayer()->getNextFrameNumber(mEditor->currentFrame(), true); + if (layer->type() == Layer::VECTOR) { auto pLayerVector = static_cast(layer); - VectorImage* vectorImage = pLayerVector->getLastVectorImageAtFrame(mEditor->currentFrame(), 0); + VectorImage* vectorImage = pLayerVector->getLastVectorImageAtFrame(keyFrameIndex, 0); + Q_CHECK_PTR(vectorImage); } else if (layer->type() == Layer::BITMAP) { auto pLayerBitmap = static_cast(layer); - BitmapImage* bitmapImage = pLayerBitmap->getLastBitmapImageAtFrame(mEditor->currentFrame(), 0); + + BitmapImage* bitmapImage = pLayerBitmap->getLastBitmapImageAtFrame(keyFrameIndex, 0); + Q_CHECK_PTR(bitmapImage); } From 1d5e3ef9181ecbd902243b573ca5fdc7d7b938bd Mon Sep 17 00:00:00 2001 From: CandyFace Date: Tue, 29 May 2018 20:06:32 +0200 Subject: [PATCH 072/184] Check if key exists --- core_lib/src/structure/object.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/core_lib/src/structure/object.cpp b/core_lib/src/structure/object.cpp index a38fd8111..689da25eb 100644 --- a/core_lib/src/structure/object.cpp +++ b/core_lib/src/structure/object.cpp @@ -451,11 +451,26 @@ void Object::paintImage(QPainter& painter, int frameNumber, if (layer->type() == Layer::BITMAP) { LayerBitmap* layerBitmap = (LayerBitmap*)layer; - layerBitmap->getLastBitmapImageAtFrame(frameNumber, 0)->paintImage(painter); + + // Make sure there's a key before painting anything + // otherwise return + if (!layer->keyExists(frameNumber)) { + return; + } + + layerBitmap->getLastBitmapImageAtFrame(frameNumber)->paintImage(painter); + } // paints the vector images if (layer->type() == Layer::VECTOR) { + + // Make sure there's a key before painting anything + // otherwise return + if (!layer->keyExists(frameNumber)) { + return; + } + LayerVector* layerVector = (LayerVector*)layer; layerVector->getLastVectorImageAtFrame(frameNumber, 0)->paintImage(painter, false, From a58faee16ebbe05a6bec67c1085bcc93bb8d665e Mon Sep 17 00:00:00 2001 From: CandyFace Date: Tue, 29 May 2018 20:14:41 +0200 Subject: [PATCH 073/184] Remove redundant code --- core_lib/src/interface/scribblearea.cpp | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index e3fefc20e..947218f52 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -517,31 +517,6 @@ void ScribbleArea::mousePressEvent(QMouseEvent* event) Layer* layer = mEditor->layers()->currentLayer(); Q_ASSUME(layer != nullptr); - bool keyExists = layer->keyExists(mEditor->currentFrame()); - int keyFrameIndex = mEditor->currentFrame(); - - // usually we look the previous frame but if there's no previous frame to look for - // bad stuff happens, therefore look for next index - // we know that one has to exist. - if (!keyExists) - keyFrameIndex = mEditor->layers()->currentLayer()->getNextFrameNumber(mEditor->currentFrame(), true); - - if (layer->type() == Layer::VECTOR) - { - auto pLayerVector = static_cast(layer); - VectorImage* vectorImage = pLayerVector->getLastVectorImageAtFrame(keyFrameIndex, 0); - - Q_CHECK_PTR(vectorImage); - } - else if (layer->type() == Layer::BITMAP) - { - auto pLayerBitmap = static_cast(layer); - - BitmapImage* bitmapImage = pLayerBitmap->getLastBitmapImageAtFrame(keyFrameIndex, 0); - - Q_CHECK_PTR(bitmapImage); - } - if (!layer->visible() && currentTool()->type() != HAND && (event->button() != Qt::RightButton)) { QMessageBox::warning(this, tr("Warning"), From 2d25738fb4c8d2282e5480432a7ea5ea94767a96 Mon Sep 17 00:00:00 2001 From: CandyFace Date: Mon, 21 May 2018 15:14:16 +0200 Subject: [PATCH 074/184] fix selection transform not working with constraint also added @martinvanzijl corner threshold fix. --- core_lib/src/tool/movetool.cpp | 54 ++++++++++++++++++++++------------ core_lib/src/tool/movetool.h | 6 +++- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/core_lib/src/tool/movetool.cpp b/core_lib/src/tool/movetool.cpp index f5093f222..aedf63e1e 100644 --- a/core_lib/src/tool/movetool.cpp +++ b/core_lib/src/tool/movetool.cpp @@ -167,10 +167,12 @@ void MoveTool::pressOperation(QMouseEvent* event, Layer* layer) if (mScribbleArea->somethingSelected) // there is an area selection { - if (event->modifiers() != Qt::ShiftModifier && !selectionRect.contains(getCurrentPoint())) - mScribbleArea->deselectAll(); + // Below will return true if a corner point was in range of the click. + bool cornerPointInRange = whichTransformationPoint(); - whichTransformationPoint(); + if (event->modifiers() != Qt::ShiftModifier && !selectionRect.contains(getCurrentPoint()) + && !cornerPointInRange) + mScribbleArea->deselectAll(); // calculate new transformation in case click only mScribbleArea->calculateSelectionTransformation(); @@ -243,81 +245,97 @@ void MoveTool::actionOnVector(QMouseEvent* event, Layer* layer) } } -void MoveTool::whichTransformationPoint() +bool MoveTool::whichTransformationPoint() { QRectF transformPoint = mScribbleArea->myTransformedSelection; - if (QLineF(getLastPoint(), transformPoint.topLeft()).length() < 10) + // Give the user a margin to select a corner point. + bool cornerInRange = false; + const double marginInPixels = 12; + const double scale = mEditor->view()->getView().inverted().m11(); + const double scaledMargin = fabs(marginInPixels * scale); + + if (QLineF(getLastPoint(), transformPoint.topLeft()).length() < scaledMargin) { mScribbleArea->setMoveMode(ScribbleArea::TOPLEFT); anchorOriginPoint = mScribbleArea->mySelection.bottomRight(); + cornerInRange = true; } - if (QLineF(getLastPoint(), transformPoint.topRight()).length() < 10) + if (QLineF(getLastPoint(), transformPoint.topRight()).length() < scaledMargin) { mScribbleArea->setMoveMode(ScribbleArea::TOPRIGHT); anchorOriginPoint = mScribbleArea->mySelection.bottomLeft(); + cornerInRange = true; } - if (QLineF(getLastPoint(), transformPoint.bottomLeft()).length() < 10) + if (QLineF(getLastPoint(), transformPoint.bottomLeft()).length() < scaledMargin) { mScribbleArea->setMoveMode(ScribbleArea::BOTTOMLEFT); anchorOriginPoint = mScribbleArea->mySelection.topRight(); + cornerInRange = true; } - if (QLineF(getLastPoint(), transformPoint.bottomRight()).length() < 10) + if (QLineF(getLastPoint(), transformPoint.bottomRight()).length() < scaledMargin) { mScribbleArea->setMoveMode(ScribbleArea::BOTTOMRIGHT); anchorOriginPoint = mScribbleArea->mySelection.topLeft(); + cornerInRange = true; } + return cornerInRange; } void MoveTool::transformSelection(qreal offsetX, qreal offsetY) { + QRectF& transformedSelection = mScribbleArea->myTransformedSelection; switch (mScribbleArea->mMoveMode) { case ScribbleArea::MIDDLE: if (QLineF(getLastPressPixel(), getCurrentPixel()).length() > 4) { mScribbleArea->myTempTransformedSelection = - mScribbleArea->myTransformedSelection.translated(QPointF(offsetX, offsetY)); + transformedSelection.translated(QPointF(offsetX, offsetY)); } break; case ScribbleArea::TOPRIGHT: { mScribbleArea->myTempTransformedSelection = - mScribbleArea->myTransformedSelection.adjusted(0, offsetY, offsetX, 0); + transformedSelection.adjusted(0, offsetY, offsetX, 0); - mScribbleArea->manageSelectionOrigin(getCurrentPoint(), anchorOriginPoint); + mScribbleArea->manageSelectionOrigin(QPointF(transformedSelection.topRight().x()+offsetX, + transformedSelection.topRight().y()+offsetY), anchorOriginPoint); break; } case ScribbleArea::TOPLEFT: { mScribbleArea->myTempTransformedSelection = - mScribbleArea->myTransformedSelection.adjusted(offsetX, offsetY, 0, 0); + transformedSelection.adjusted(offsetX, offsetY, 0, 0); - mScribbleArea->manageSelectionOrigin(getCurrentPoint(), anchorOriginPoint); + mScribbleArea->manageSelectionOrigin(QPointF(transformedSelection.x()+offsetX, + transformedSelection.y()+offsetY), anchorOriginPoint); break; } case ScribbleArea::BOTTOMLEFT: { mScribbleArea->myTempTransformedSelection = - mScribbleArea->myTransformedSelection.adjusted(offsetX, 0, 0, offsetY); + transformedSelection.adjusted(offsetX, 0, 0, offsetY); - mScribbleArea->manageSelectionOrigin(getCurrentPoint(), anchorOriginPoint); + mScribbleArea->manageSelectionOrigin(QPointF(transformedSelection.bottomLeft().x()+offsetX, + transformedSelection.bottomLeft().y()+offsetY), anchorOriginPoint); break; } case ScribbleArea::BOTTOMRIGHT: { mScribbleArea->myTempTransformedSelection = - mScribbleArea->myTransformedSelection.adjusted(0, 0, offsetX, offsetY); + transformedSelection.adjusted(0, 0, offsetX, offsetY); - mScribbleArea->manageSelectionOrigin(getCurrentPoint(), anchorOriginPoint); + mScribbleArea->manageSelectionOrigin(QPointF(transformedSelection.bottomRight().x()+offsetX, + transformedSelection.bottomRight().y()+offsetY), anchorOriginPoint); break; } case ScribbleArea::ROTATION: { mScribbleArea->myTempTransformedSelection = - mScribbleArea->myTransformedSelection; // @ necessary? + transformedSelection; // @ necessary? mScribbleArea->myRotatedAngle = getCurrentPixel().x() - getLastPressPixel().x(); break; } diff --git a/core_lib/src/tool/movetool.h b/core_lib/src/tool/movetool.h index c656285a3..ecc733bd4 100644 --- a/core_lib/src/tool/movetool.h +++ b/core_lib/src/tool/movetool.h @@ -44,7 +44,11 @@ class MoveTool : public BaseTool void applyChanges(); void resetSelectionProperties(); void paintTransformedSelection(); - void whichTransformationPoint(); + + /// @brief Selects which corner-point of the selection to move, if + /// one is range of the last click. + /// @return true if a corner point was selected, false otherwise. + bool whichTransformationPoint(); void transformSelection(qreal offsetX, qreal offsetY); void pressOperation(QMouseEvent* event, Layer *layer); void actionOnVector(QMouseEvent *event, Layer *layer); From f12fa618866c02d4fd1d19021ca8e98d1f31276f Mon Sep 17 00:00:00 2001 From: CandyFace Date: Mon, 21 May 2018 15:15:00 +0200 Subject: [PATCH 075/184] fix not able to create new selection #974 --- core_lib/src/tool/selecttool.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/core_lib/src/tool/selecttool.cpp b/core_lib/src/tool/selecttool.cpp index 566e3a28e..904f7d35b 100644 --- a/core_lib/src/tool/selecttool.cpp +++ b/core_lib/src/tool/selecttool.cpp @@ -52,10 +52,8 @@ void SelectTool::mousePressEvent(QMouseEvent* event) if (event->button() == Qt::LeftButton) { - if (!mScribbleArea->somethingSelected) - { - anchorOriginPoint = getLastPoint(); // Store original click position for help with selection rectangle. - } + + anchorOriginPoint = getLastPoint(); // Store original click position for help with selection rectangle. if (layer->isPaintable()) { From ee8fb3645762dc087774172cd977859c99fbc6d0 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Thu, 24 May 2018 00:54:07 -0600 Subject: [PATCH 076/184] Optimize bucket fill with cache --- core_lib/src/graphics/bitmap/bitmapimage.cpp | 25 ++++++++++++++------ core_lib/src/graphics/bitmap/bitmapimage.h | 2 +- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/core_lib/src/graphics/bitmap/bitmapimage.cpp b/core_lib/src/graphics/bitmap/bitmapimage.cpp index 9882249fb..0fa990a36 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.cpp +++ b/core_lib/src/graphics/bitmap/bitmapimage.cpp @@ -537,15 +537,19 @@ void BitmapImage::clear(QRect rectangle) * @param[in] newColor The first color to compare * @param[in] oldColor The second color to compare * @param[in] tolerance The threshold limit between a matching and non-matching color + * @param[in,out] cache Contains a mapping of previous results of compareColor with rule that + * cache[someColor] = compareColor(someColor, oldColor, tolerance) * * @return Returns true if the colors have a similarity below the tolerance level * (i.e. if Eulcidian distance squared is <= tolerance) */ -bool BitmapImage::compareColor(QRgb newColor, QRgb oldColor, int tolerance) +bool BitmapImage::compareColor(QRgb newColor, QRgb oldColor, int tolerance, QHash *cache) { // Handle trivial case if (newColor == oldColor) return true; + if(cache && cache->contains(newColor)) return cache->value(newColor); + // Get Eulcidian distance between colors // Not an accurate representation of human perception, // but it's the best any image editing program ever does @@ -558,6 +562,12 @@ bool BitmapImage::compareColor(QRgb newColor, QRgb oldColor, int tolerance) bool isSimilar = (diffRed + diffGreen + diffBlue + diffAlpha) <= tolerance; + if(cache) + { + Q_ASSERT(cache->contains(isSimilar) ? isSimilar == (*cache)[newColor] : true); + (*cache)[newColor] = isSimilar; + } + return isSimilar; } @@ -587,6 +597,7 @@ void BitmapImage::floodFill(BitmapImage* targetImage, BitmapImage* replaceImage = nullptr; QPoint tempPoint; QRgb newPlacedColor = 0; + QScopedPointer< QHash > cache(new QHash()); int xTemp = 0; bool spanLeft = false; @@ -610,12 +621,12 @@ void BitmapImage::floodFill(BitmapImage* targetImage, newPlacedColor = replaceImage->constScanLine(xTemp, point.y()); while (xTemp >= targetImage->topLeft().x() && - compareColor(targetImage->constScanLine(xTemp, point.y()), oldColor, tolerance)) xTemp--; + compareColor(targetImage->constScanLine(xTemp, point.y()), oldColor, tolerance, cache.data())) xTemp--; xTemp++; spanLeft = spanRight = false; while (xTemp <= targetImage->right() && - compareColor(targetImage->constScanLine(xTemp, point.y()), oldColor, tolerance) && + compareColor(targetImage->constScanLine(xTemp, point.y()), oldColor, tolerance, cache.data()) && newPlacedColor != newColor) { @@ -623,23 +634,23 @@ void BitmapImage::floodFill(BitmapImage* targetImage, replaceImage->scanLine(xTemp, point.y(), newColor); if (!spanLeft && (point.y() > targetImage->top()) && - compareColor(targetImage->constScanLine(xTemp, point.y() - 1), oldColor, tolerance)) { + compareColor(targetImage->constScanLine(xTemp, point.y() - 1), oldColor, tolerance, cache.data())) { queue.append(QPoint(xTemp, point.y() - 1)); spanLeft = true; } else if (spanLeft && (point.y() > targetImage->top()) && - !compareColor(targetImage->constScanLine(xTemp, point.y() - 1), oldColor, tolerance)) { + !compareColor(targetImage->constScanLine(xTemp, point.y() - 1), oldColor, tolerance, cache.data())) { spanLeft = false; } if (!spanRight && point.y() < targetImage->bottom() && - compareColor(targetImage->constScanLine(xTemp, point.y() + 1), oldColor, tolerance)) { + compareColor(targetImage->constScanLine(xTemp, point.y() + 1), oldColor, tolerance, cache.data())) { queue.append(QPoint(xTemp, point.y() + 1)); spanRight = true; } else if (spanRight && point.y() < targetImage->bottom() && - !compareColor(targetImage->constScanLine(xTemp, point.y() + 1), oldColor, tolerance)) { + !compareColor(targetImage->constScanLine(xTemp, point.y() + 1), oldColor, tolerance, cache.data())) { spanRight = false; } diff --git a/core_lib/src/graphics/bitmap/bitmapimage.h b/core_lib/src/graphics/bitmap/bitmapimage.h index 871762565..b72f6828e 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.h +++ b/core_lib/src/graphics/bitmap/bitmapimage.h @@ -74,7 +74,7 @@ class BitmapImage : public KeyFrame void clear(QRect rectangle); void clear(QRectF rectangle) { clear(rectangle.toRect()); } - static bool compareColor(QRgb newColor, QRgb oldColor, int tolerance); + static bool compareColor(QRgb newColor, QRgb oldColor, int tolerance, QHash *cache); static void floodFill(BitmapImage* targetImage, QRect cameraRect, QPoint point, QRgb newColor, int tolerance); void drawLine(QPointF P1, QPointF P2, QPen pen, QPainter::CompositionMode cm, bool antialiasing); From cd41d780705be498bf587b454b4414638b6d640b Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Thu, 31 May 2018 12:08:10 +1000 Subject: [PATCH 077/184] Add a missing header which causes compilation error with MinGW --- app/src/colorinspector.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/colorinspector.cpp b/app/src/colorinspector.cpp index 536e29b75..19904031b 100644 --- a/app/src/colorinspector.cpp +++ b/app/src/colorinspector.cpp @@ -20,6 +20,7 @@ GNU General Public License for more details. #include #include #include +#include #include "colorslider.h" #include "pencildef.h" From 7f6d3982afd9fcb51b67486842324f419f229561 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Thu, 31 May 2018 17:08:56 +1000 Subject: [PATCH 078/184] Add debug details when compressing the zip file --- core_lib/src/qminiz.cpp | 56 +++++++++++++++++---- core_lib/src/qminiz.h | 5 +- core_lib/src/structure/filemanager.cpp | 70 +++++++++++++++----------- core_lib/src/structure/layer.h | 8 +-- tests/src/test_filemanager.cpp | 3 +- 5 files changed, 94 insertions(+), 48 deletions(-) diff --git a/core_lib/src/qminiz.cpp b/core_lib/src/qminiz.cpp index 6ba54e189..c8776f836 100644 --- a/core_lib/src/qminiz.cpp +++ b/core_lib/src/qminiz.cpp @@ -38,19 +38,30 @@ bool MiniZ::isZip(const QString& sZipFilePath) return (num > 0); } -bool MiniZ::compressFolder(QString sZipFilePath, QString sSrcPath) +Status MiniZ::compressFolder(QString sZipFilePath, QString sSrcPath) { + DebugDetails dd; + dd << QString("Zip the folder %1 to %2").arg(sZipFilePath).arg(sSrcPath); + if (!sSrcPath.endsWith("/")) { sSrcPath.append("/"); } + sSrcPath = QDir::toNativeSeparators(sSrcPath); + sZipFilePath = QDir::toNativeSeparators(sZipFilePath); + mz_zip_archive* mz = new mz_zip_archive; OnScopeExit(delete mz); mz_zip_zero_struct(mz); mz_bool ok = mz_zip_writer_init_file(mz, sZipFilePath.toUtf8().data(), 0); + if (!ok) + { + dd << "Miniz writer init failed."; + } + QDirIterator it(sSrcPath, QDirIterator::Subdirectories); while (it.hasNext()) { @@ -64,24 +75,36 @@ bool MiniZ::compressFolder(QString sZipFilePath, QString sSrcPath) QString sRelativePath = sFullPath; sRelativePath.replace(sSrcPath, ""); + dd << QString("Add file to zip: ").append(sRelativePath); + ok = mz_zip_writer_add_file(mz, sRelativePath.toUtf8().data(), sFullPath.toUtf8().data(), "", 0, MZ_DEFAULT_COMPRESSION); if (!ok) - break; + { + dd << QString(" Cannot add %1 to zip").arg(sRelativePath); + } } ok &= mz_zip_writer_finalize_archive(mz); + if (!ok) + { + dd << "Miniz finalize archive failed"; + } + mz_zip_writer_end(mz); - return ok; + return Status::OK; } -bool MiniZ::uncompressFolder(QString sZipFilePath, QString sDestPath) +Status MiniZ::uncompressFolder(QString sZipFilePath, QString sDestPath) { + DebugDetails dd; + dd << QString("Unzip file %1 to folder %2").arg(sZipFilePath).arg(sDestPath); + if (!QFile::exists(sZipFilePath)) { - return false; + return Status::FILE_NOT_FOUND; } QString sBaseDir = QFileInfo(sDestPath).absolutePath(); @@ -99,7 +122,8 @@ bool MiniZ::uncompressFolder(QString sZipFilePath, QString sDestPath) mz_zip_zero_struct(mz); mz_bool ok = mz_zip_reader_init_file(mz, sZipFilePath.toUtf8().data(), 0); - if (!ok) return false; + if (!ok) + return Status(Status::FAIL, dd); int num = mz_zip_reader_get_num_files(mz); @@ -113,8 +137,12 @@ bool MiniZ::uncompressFolder(QString sZipFilePath, QString sDestPath) if (stat->m_is_directory) { QString sFolderPath = QString::fromUtf8(stat->m_filename); - bool b = baseDir.mkpath(sFolderPath); - Q_ASSERT(b); + dd << QString("Make Dir: ").append(sFolderPath); + + bool mkDirOK = baseDir.mkpath(sFolderPath); + Q_ASSERT(mkDirOK); + if (!mkDirOK) + dd << " Make Dir failed."; } } @@ -125,10 +153,16 @@ bool MiniZ::uncompressFolder(QString sZipFilePath, QString sDestPath) if (!stat->m_is_directory) { QString sFullPath = baseDir.filePath(QString::fromUtf8(stat->m_filename)); + dd << QString("Unzip file: ").append(sFullPath); bool b = QFileInfo(sFullPath).absoluteDir().mkpath("."); Q_ASSERT(b); - ok &= mz_zip_reader_extract_to_file(mz, i, sFullPath.toUtf8(), 0); + bool extractOK = mz_zip_reader_extract_to_file(mz, i, sFullPath.toUtf8(), 0); + if (!extractOK) + { + ok = false; + dd << " File extraction failed."; + } } } @@ -136,7 +170,7 @@ bool MiniZ::uncompressFolder(QString sZipFilePath, QString sDestPath) if (!ok) { - qDebug() << "Unzip error!"; + dd << "Unzip error!"; } - return ok; + return Status::OK; } diff --git a/core_lib/src/qminiz.h b/core_lib/src/qminiz.h index 17d3a53de..7a37389cc 100644 --- a/core_lib/src/qminiz.h +++ b/core_lib/src/qminiz.h @@ -17,11 +17,12 @@ GNU General Public License for more details. #define QMINIZ_H #include +#include "pencilerror.h" namespace MiniZ { bool isZip(const QString& sZipFilePath); - bool compressFolder(QString sZipFilePath, QString sSrcPath); - bool uncompressFolder(QString sZipFilePath, QString sDestPath); + Status compressFolder(QString sZipFilePath, QString sSrcPath); + Status uncompressFolder(QString sZipFilePath, QString sDestPath); } #endif diff --git a/core_lib/src/structure/filemanager.cpp b/core_lib/src/structure/filemanager.cpp index 7d0a57689..266a7db68 100644 --- a/core_lib/src/structure/filemanager.cpp +++ b/core_lib/src/structure/filemanager.cpp @@ -177,14 +177,14 @@ bool FileManager::isOldForamt(const QString& fileName) Status FileManager::save(Object* object, QString strFileName) { - DebugDetails debugDetails; - debugDetails << "FileManager::save"; - debugDetails << ("strFileName = " + strFileName); + DebugDetails dd; + dd << "FileManager::save"; + dd << ("strFileName = " + strFileName); if (object == nullptr) { - debugDetails << "object parameter is null"; - return Status(Status::INVALID_ARGUMENT, debugDetails); + dd << "object parameter is null"; + return Status(Status::INVALID_ARGUMENT, dd); } int totalCount = object->totalKeyFrameCount(); @@ -196,26 +196,26 @@ Status FileManager::save(Object* object, QString strFileName) QFileInfo fileInfo(strFileName); if (fileInfo.isDir()) { - debugDetails << "FileName points to a directory"; + dd << "FileName points to a directory"; return Status(Status::INVALID_ARGUMENT, - debugDetails, + dd, tr("Invalid Save Path"), tr("The path (\"%1\") points to a directory.").arg(fileInfo.absoluteFilePath())); } QFileInfo parentDirInfo(fileInfo.dir().absolutePath()); if (!parentDirInfo.exists()) { - debugDetails << "The parent directory of strFileName does not exist"; + dd << "The parent directory of strFileName does not exist"; return Status(Status::INVALID_ARGUMENT, - debugDetails, + dd, tr("Invalid Save Path"), tr("The directory (\"%1\") does not exist.").arg(parentDirInfo.absoluteFilePath())); } if ((fileInfo.exists() && !fileInfo.isWritable()) || !parentDirInfo.isWritable()) { - debugDetails << "Filename points to a location that is not writable"; + dd << "Filename points to a location that is not writable"; return Status(Status::INVALID_ARGUMENT, - debugDetails, + dd, tr("Invalid Save Path"), tr("The path (\"%1\") is not writable.").arg(fileInfo.absoluteFilePath())); } @@ -238,7 +238,7 @@ Status FileManager::save(Object* object, QString strFileName) strTempWorkingFolder = object->workingDir(); Q_ASSERT(QDir(strTempWorkingFolder).exists()); - debugDetails << QString("strTempWorkingFolder = ").append(strTempWorkingFolder); + dd << QString("strTempWorkingFolder = ").append(strTempWorkingFolder); qCDebug(mLog) << "Temp Folder=" << strTempWorkingFolder; strMainXMLFile = QDir(strTempWorkingFolder).filePath(PFF_XML_FILE_NAME); @@ -252,43 +252,48 @@ Status FileManager::save(Object* object, QString strFileName) if (!dir.mkpath(strDataFolder)) { - debugDetails << QString("dir.absolutePath() = %1").arg(dir.absolutePath()); + dd << QString("dir.absolutePath() = %1").arg(dir.absolutePath()); - return Status(Status::FAIL, debugDetails, + return Status(Status::FAIL, dd, tr("Cannot Create Data Directory"), tr("Failed to create directory \"%1\". Please make sure you have sufficient permissions.").arg(strDataFolder)); } } if (!dataInfo.isDir()) { - debugDetails << QString("dataInfo.absoluteFilePath() = ").append(dataInfo.absoluteFilePath()); + dd << QString("dataInfo.absoluteFilePath() = ").append(dataInfo.absoluteFilePath()); return Status(Status::FAIL, - debugDetails, + dd, tr("Cannot Create Data Directory"), tr("\"%1\" is a file. Please delete the file and try again.").arg(dataInfo.absoluteFilePath())); } // save data int layerCount = object->getLayerCount(); - debugDetails << QString("layerCount = %1").arg(layerCount); + dd << QString("layerCount = %1").arg(layerCount); bool saveLayerOK = true; for (int i = 0; i < layerCount; ++i) { Layer* layer = object->getLayer(i); - debugDetails << QString("layer[%1] = Layer[id=%2, name=%3, type=%4]").arg(i).arg(layer->id()).arg(layer->name()).arg(layer->type()); + dd << QString("layer[%1] = Layer[id=%2, name=%3, type=%4]").arg(i).arg(layer->id()).arg(layer->name()).arg(layer->type()); Status st = layer->save(strDataFolder, [this] { progressForward(); }); if (!st.ok()) { saveLayerOK = false; - debugDetails.collect(st.details()); - debugDetails << QString("- Layer[%1] failed to save").arg(i); + dd.collect(st.details()); + dd << QString(" !! Failed to save Layer[%1] %2 ").arg(i).arg(layer->name()); } } + dd << "All Layers saved"; // save palette - object->savePalette(strDataFolder); + bool bPaletteOK = object->savePalette(strDataFolder); + if (!bPaletteOK) + { + dd << "Failed to save palette"; + } progressForward(); @@ -315,6 +320,8 @@ Status FileManager::save(Object* object, QString strFileName) QDomElement objectElement = object->saveXML(xmlDoc); root.appendChild(objectElement); + dd << "Writing main xml file..."; + const int IndentSize = 2; QTextStream out(&file); @@ -322,18 +329,22 @@ Status FileManager::save(Object* object, QString strFileName) out.flush(); file.close(); + dd << "Done writing main xml file"; + progressForward(); if (!isOldFile) { - bool ok = MiniZ::compressFolder(strFileName, strTempWorkingFolder); - if (!ok) + dd << "Miniz"; + Status s = MiniZ::compressFolder(strFileName, strTempWorkingFolder); + if (!s.ok()) { - return Status(Status::ERROR_MINIZ_FAIL, debugDetails, - tr("MiniZ Error"), + dd.collect(s.details()); + return Status(Status::ERROR_MINIZ_FAIL, dd, + tr("Miniz Error"), tr("An internal error occurred. Your file may not be saved successfully.")); } - qCDebug(mLog) << "Compressed. File saved."; + dd << "Zip file saved successfully"; } object->setFilePath(strFileName); @@ -343,8 +354,7 @@ Status FileManager::save(Object* object, QString strFileName) if (!saveLayerOK) { - return Status(Status::FAIL, - debugDetails, + return Status(Status::FAIL, dd, tr("Internal Error"), tr("An internal error occurred. Your file may not be saved successfully.")); } @@ -522,8 +532,8 @@ void FileManager::unzip(const QString& strZipFile, const QString& strUnzipTarget // removes the previous directory first - better approach removePFFTmpDirectory(strUnzipTarget); - bool bOK = MiniZ::uncompressFolder(strZipFile, strUnzipTarget); - Q_ASSERT(bOK); + Status s = MiniZ::uncompressFolder(strZipFile, strUnzipTarget); + Q_ASSERT(s.ok()); mstrLastTempFolder = strUnzipTarget; } diff --git a/core_lib/src/structure/layer.h b/core_lib/src/structure/layer.h index f9506ef14..4e73198e6 100644 --- a/core_lib/src/structure/layer.h +++ b/core_lib/src/structure/layer.h @@ -64,14 +64,14 @@ class Layer : public QObject bool visible() const { return mVisible; } void setVisible(bool b) { mVisible = b; } - // KeyFrame interface - int getMaxKeyFramePosition() const; - int firstKeyFramePosition() const; - virtual Status saveKeyFrameFile(KeyFrame*, QString dataPath) = 0; virtual void loadDomElement(QDomElement element, QString dataDirPath, ProgressCallback progressForward) = 0; virtual QDomElement createDomElement(QDomDocument& doc) = 0; + // KeyFrame interface + int getMaxKeyFramePosition() const; + int firstKeyFramePosition() const; + bool keyExists(int position) const; int getPreviousKeyFramePosition(int position) const; int getNextKeyFramePosition(int position) const; diff --git a/tests/src/test_filemanager.cpp b/tests/src/test_filemanager.cpp index e5ea8da47..bb29c274c 100644 --- a/tests/src/test_filemanager.cpp +++ b/tests/src/test_filemanager.cpp @@ -248,7 +248,8 @@ TEST_CASE("FileManager Load-a-zip Test") REQUIRE(img.save(workDir.absolutePath() + "/" PFF_DATA_DIR "/005.001.png")); QString pclxFile = QDir(testDir.path()).filePath("test-animation.pclx"); - REQUIRE(MiniZ::compressFolder(pclxFile, workDir.absolutePath())); + Status s = MiniZ::compressFolder(pclxFile, workDir.absolutePath()); + REQUIRE(s.ok()); FileManager fm; Object* o = fm.load(pclxFile); From d06c1aa13d3d71908ce568a9e9b0d5d4945d79dc Mon Sep 17 00:00:00 2001 From: CandyFace Date: Thu, 31 May 2018 20:12:16 +0200 Subject: [PATCH 079/184] Refactor implementation --- app/src/colorpalettewidget.cpp | 48 ++++++++++++++-------- app/src/colorpalettewidget.h | 2 +- core_lib/src/graphics/vector/colourref.cpp | 2 +- core_lib/src/graphics/vector/colourref.h | 2 +- core_lib/src/structure/object.cpp | 26 +----------- core_lib/src/structure/object.h | 4 +- 6 files changed, 37 insertions(+), 47 deletions(-) diff --git a/app/src/colorpalettewidget.cpp b/app/src/colorpalettewidget.cpp index 2e544e986..464acf455 100644 --- a/app/src/colorpalettewidget.cpp +++ b/app/src/colorpalettewidget.cpp @@ -18,7 +18,7 @@ GNU General Public License for more details. #include "ui_colorpalette.h" // Standard libraries -#include "cmath" +#include // Qt #include @@ -27,6 +27,8 @@ GNU General Public License for more details. #include #include #include +#include +#include #include #include @@ -72,13 +74,6 @@ void ColorPaletteWidget::initUI() "QPushButton:pressed { border: 1px solid #ADADAD; border-radius: 2px; background-color: #D5D5D5; }" "QPushButton:checked { border: 1px solid #ADADAD; border-radius: 2px; background-color: #D5D5D5; }"; - - // color number need to be set to add new color to palette - // in cases where the last color was saved - // otherwise first color will be black. - editor()->color()->setColorNumber(0); - editor()->color()->setColor(editor()->color()->frontColor()); - ui->addColorButton->setStyleSheet(buttonStylesheet); ui->removeColorButton->setStyleSheet(buttonStylesheet); ui->colorDialogButton->setStyleSheet(buttonStylesheet); @@ -92,7 +87,6 @@ void ColorPaletteWidget::initUI() connect(ui->addColorButton, &QPushButton::clicked, this, &ColorPaletteWidget::clickAddColorButton); connect(ui->colorDialogButton, &QPushButton::clicked, this, &ColorPaletteWidget::clickColorDialogButton); connect(ui->removeColorButton, &QPushButton::clicked, this, &ColorPaletteWidget::clickRemoveColorButton); - connect(ui->colorListWidget, &QListWidget::itemSelectionChanged, this, &ColorPaletteWidget::selectedItems); connect(ui->colorListWidget, &QListWidget::customContextMenuRequested, this, &ColorPaletteWidget::showContextMenu); } @@ -162,10 +156,6 @@ void ColorPaletteWidget::setColor(QColor newColor, int colorIndex) } } -QList ColorPaletteWidget::selectedItems() const -{ - return ui->colorListWidget->selectedItems(); -} void ColorPaletteWidget::selectColorNumber(int colorNumber) { @@ -503,21 +493,43 @@ void ColorPaletteWidget::clickAddColorButton() void ColorPaletteWidget::clickRemoveColorButton() { - for (auto item : selectedItems()) + for (auto item : ui->colorListWidget->selectedItems()) { int index = ui->colorListWidget->row(item); // items are not deleted by qt, has to be done manually // delete should happen before removing the color from from palette // as the palette will be one ahead and crash otherwise - if (editor()->object()->shouldDeleteColor(index)) { - delete item; - editor()->object()->removeColour(index); - editor()->updateCurrentFrame(); + if (editor()->object()->isColourInUse(index)) + { + bool accepted = showPaletteWarning(); + if (accepted) + { + delete item; + editor()->object()->removeColour(index); + editor()->updateCurrentFrame(); + } } } } +bool ColorPaletteWidget::showPaletteWarning() +{ + QMessageBox msgBox; + msgBox.setText(tr("The color you are trying to delete is currently being used by one or multiple strokes, " + "if you wish to delete it anyway, you accept that the stroke(s) will be bound to the next available color")); + msgBox.addButton(tr("Cancel"), QMessageBox::RejectRole); + QPushButton* removeButton = msgBox.addButton(tr("Delete anyway"), QMessageBox::AcceptRole); + + msgBox.exec(); + if (msgBox.clickedButton() == removeButton) + { + return true; + } + return false; + +} + void ColorPaletteWidget::updateItemColor(int itemIndex, QColor newColor) { QPixmap colourSwatch(mIconSize); diff --git a/app/src/colorpalettewidget.h b/app/src/colorpalettewidget.h index bb45fb55e..71d61fedd 100644 --- a/app/src/colorpalettewidget.h +++ b/app/src/colorpalettewidget.h @@ -75,10 +75,10 @@ private slots: void setSwatchSizeSmall(); void setSwatchSizeMedium(); void setSwatchSizeLarge(); - QList selectedItems() const; void addItem(); void replaceItem(); void removeItem(); + bool showPaletteWarning(); private: void updateItemColor(int, QColor); diff --git a/core_lib/src/graphics/vector/colourref.cpp b/core_lib/src/graphics/vector/colourref.cpp index 3a44fa677..a13bb7a27 100644 --- a/core_lib/src/graphics/vector/colourref.cpp +++ b/core_lib/src/graphics/vector/colourref.cpp @@ -54,7 +54,7 @@ bool ColourRef::operator!=(ColourRef colourRef1) } } -QDebug operator<<(QDebug debug, const ColourRef& colourRef) +QDebug& operator<<(QDebug debug, const ColourRef& colourRef) { debug.nospace() << "ColourRef(" << colourRef.colour << " " << colourRef.name <<")"; return debug.maybeSpace(); diff --git a/core_lib/src/graphics/vector/colourref.h b/core_lib/src/graphics/vector/colourref.h index 80066d742..e2dc8c4d8 100644 --- a/core_lib/src/graphics/vector/colourref.h +++ b/core_lib/src/graphics/vector/colourref.h @@ -33,6 +33,6 @@ class ColourRef QString name; }; -QDebug operator<<(QDebug debug, const ColourRef &colourRef); +QDebug& operator<<(QDebug debug, const ColourRef &colourRef); #endif diff --git a/core_lib/src/structure/object.cpp b/core_lib/src/structure/object.cpp index 954ebacaf..5bf86a44e 100644 --- a/core_lib/src/structure/object.cpp +++ b/core_lib/src/structure/object.cpp @@ -20,8 +20,6 @@ GNU General Public License for more details. #include #include #include -#include -#include #include "layer.h" #include "layerbitmap.h" @@ -317,7 +315,7 @@ void Object::addColourAtIndex(int index, ColourRef newColour) mPalette.insert(index, newColour); } -bool Object::shouldDeleteColor(int index) +bool Object::isColourInUse(int index) { bool usesColor = false; for (int i = 0; i < getLayerCount(); i++) @@ -333,30 +331,11 @@ bool Object::shouldDeleteColor(int index) } } } - - if (usesColor) - { - QMessageBox msgBox; - msgBox.setText(tr("The color you are trying to delete is currently being used by one or multiple strokes, " - "if you wish to delete it anyway, you accept that the stroke(s) will be bound to the next available color")); - QPushButton* cancelButton = msgBox.addButton(tr("Cancel"), QMessageBox::RejectRole); - QPushButton* removeButton = msgBox.addButton(tr("Remove anyway"), QMessageBox::AcceptRole); - - msgBox.exec(); - if (msgBox.clickedButton() == cancelButton) - { - return false; - } - else if (msgBox.clickedButton() == removeButton) - { - return true; - } - } return true; } -bool Object::removeColour(int index) +void Object::removeColour(int index) { for (int i = 0; i < getLayerCount(); i++) { @@ -370,7 +349,6 @@ bool Object::removeColour(int index) mPalette.removeAt(index); - return true; // update the vector pictures using that colour ! } diff --git a/core_lib/src/structure/object.h b/core_lib/src/structure/object.h index 2cdb7170c..dac809832 100644 --- a/core_lib/src/structure/object.h +++ b/core_lib/src/structure/object.h @@ -90,8 +90,8 @@ class Object : public QObject void addColour( ColourRef newColour ) { mPalette.append( newColour ); } void addColourAtIndex(int index, ColourRef newColour); - bool removeColour( int index ); - bool shouldDeleteColor( int index ); + void removeColour( int index ); + bool isColourInUse( int index ); void renameColour( int i, QString text ); int getColourCount() { return mPalette.size(); } bool importPalette( QString filePath ); From 7d017a3eadcd5e08b9295718818e52abc8722906 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Wed, 30 May 2018 23:53:14 +1000 Subject: [PATCH 080/184] Don't skip the frame if a previous frame can be found --- core_lib/src/structure/object.cpp | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/core_lib/src/structure/object.cpp b/core_lib/src/structure/object.cpp index 689da25eb..6171c53cc 100644 --- a/core_lib/src/structure/object.cpp +++ b/core_lib/src/structure/object.cpp @@ -422,7 +422,7 @@ void Object::loadDefaultPalette() addColour(ColourRef(QColor(227, 177, 105), QString(tr("Dark Skin - shade")))); } -void Object::paintImage(QPainter& painter, int frameNumber, +void Object::paintImage(QPainter& painter,int frameNumber, bool background, bool antialiasing) const { @@ -452,30 +452,18 @@ void Object::paintImage(QPainter& painter, int frameNumber, { LayerBitmap* layerBitmap = (LayerBitmap*)layer; - // Make sure there's a key before painting anything - // otherwise return - if (!layer->keyExists(frameNumber)) { - return; - } - - layerBitmap->getLastBitmapImageAtFrame(frameNumber)->paintImage(painter); + BitmapImage* bitmap = layerBitmap->getLastBitmapImageAtFrame(frameNumber); + if (bitmap) + bitmap->paintImage(painter); } // paints the vector images if (layer->type() == Layer::VECTOR) { - - // Make sure there's a key before painting anything - // otherwise return - if (!layer->keyExists(frameNumber)) { - return; - } - LayerVector* layerVector = (LayerVector*)layer; - layerVector->getLastVectorImageAtFrame(frameNumber, 0)->paintImage(painter, - false, - false, - antialiasing); + VectorImage* vec = layerVector->getLastVectorImageAtFrame(frameNumber, 0); + if (vec) + vec->paintImage(painter, false, false, antialiasing); } } } From 665ec50e9c944a9f568d454179790bdc22b43f43 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Fri, 1 Jun 2018 10:37:03 +1000 Subject: [PATCH 081/184] google api python client spits an error ImportError: No module named 'oauth2client' when uploading nightly builds --- appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/appveyor.yml b/appveyor.yml index bd2855d3c..7cc36dab5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -38,6 +38,7 @@ install: - "%PYTHON3% -m pip install -r requirements.txt" - "%PYTHON3% -m pip install setuptools" - "%PYTHON3% -m pip install virtualenvwrapper" + - "%PYTHON3% -m pip install --upgrade oauth2client" - "%PYTHON3% -m pip install --upgrade google-api-python-client" - "%PYTHON3% -V" - set QTDIR=C:\Qt\%qt% From 02483612678fa8d74f850d7fdc68e3d1a9c70fb4 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 5 Jun 2018 16:26:47 +1000 Subject: [PATCH 082/184] Fix #907 file leaking by making a white-list for zipping pclx - plus many debug details during the saving process --- core_lib/src/qminiz.cpp | 47 ++++++-------- core_lib/src/qminiz.h | 4 +- core_lib/src/structure/filemanager.cpp | 89 +++++++++++++------------- core_lib/src/structure/filemanager.h | 4 +- core_lib/src/structure/layer.cpp | 49 ++++++-------- core_lib/src/structure/layer.h | 8 +-- core_lib/src/structure/layerbitmap.cpp | 17 ++--- core_lib/src/structure/layersound.cpp | 18 ++++-- core_lib/src/structure/layersound.h | 2 +- core_lib/src/structure/layervector.cpp | 20 +++--- core_lib/src/structure/object.cpp | 8 ++- core_lib/src/structure/object.h | 2 +- 12 files changed, 134 insertions(+), 134 deletions(-) diff --git a/core_lib/src/qminiz.cpp b/core_lib/src/qminiz.cpp index c8776f836..cc25cbfe5 100644 --- a/core_lib/src/qminiz.cpp +++ b/core_lib/src/qminiz.cpp @@ -38,76 +38,69 @@ bool MiniZ::isZip(const QString& sZipFilePath) return (num > 0); } -Status MiniZ::compressFolder(QString sZipFilePath, QString sSrcPath) +// ReSharper disable once CppInconsistentNaming +Status MiniZ::compressFolder(QString zipFilePath, QString srcFolderPath, const QStringList& fileList) { DebugDetails dd; - dd << QString("Zip the folder %1 to %2").arg(sZipFilePath).arg(sSrcPath); + dd << QString("Zip the folder %1 to %2").arg(zipFilePath).arg(srcFolderPath); - if (!sSrcPath.endsWith("/")) + if (!srcFolderPath.endsWith("/")) { - sSrcPath.append("/"); + srcFolderPath.append("/"); } - sSrcPath = QDir::toNativeSeparators(sSrcPath); - sZipFilePath = QDir::toNativeSeparators(sZipFilePath); mz_zip_archive* mz = new mz_zip_archive; OnScopeExit(delete mz); mz_zip_zero_struct(mz); - mz_bool ok = mz_zip_writer_init_file(mz, sZipFilePath.toUtf8().data(), 0); + mz_bool ok = mz_zip_writer_init_file(mz, zipFilePath.toUtf8().data(), 0); if (!ok) { dd << "Miniz writer init failed."; } - QDirIterator it(sSrcPath, QDirIterator::Subdirectories); - while (it.hasNext()) + qDebug() << "SrcFolder=" << srcFolderPath; + for (QString filePath : fileList) { - QString sFullPath = it.next(); - - if (it.fileInfo().isDir()) - { - continue; - } - - QString sRelativePath = sFullPath; - sRelativePath.replace(sSrcPath, ""); + QString sRelativePath = filePath; + sRelativePath.replace(srcFolderPath, ""); dd << QString("Add file to zip: ").append(sRelativePath); ok = mz_zip_writer_add_file(mz, sRelativePath.toUtf8().data(), - sFullPath.toUtf8().data(), + filePath.toUtf8().data(), "", 0, MZ_DEFAULT_COMPRESSION); + qDebug() << "Zip: " << filePath; if (!ok) { dd << QString(" Cannot add %1 to zip").arg(sRelativePath); } } ok &= mz_zip_writer_finalize_archive(mz); + mz_zip_writer_end(mz); + if (!ok) { dd << "Miniz finalize archive failed"; + return Status(Status::FAIL, dd); } - - mz_zip_writer_end(mz); - return Status::OK; } -Status MiniZ::uncompressFolder(QString sZipFilePath, QString sDestPath) +Status MiniZ::uncompressFolder(QString zipFilePath, QString destPath) { DebugDetails dd; - dd << QString("Unzip file %1 to folder %2").arg(sZipFilePath).arg(sDestPath); + dd << QString("Unzip file %1 to folder %2").arg(zipFilePath).arg(destPath); - if (!QFile::exists(sZipFilePath)) + if (!QFile::exists(zipFilePath)) { return Status::FILE_NOT_FOUND; } - QString sBaseDir = QFileInfo(sDestPath).absolutePath(); + QString sBaseDir = QFileInfo(destPath).absolutePath(); QDir baseDir(sBaseDir); if (!baseDir.exists()) { @@ -121,7 +114,7 @@ Status MiniZ::uncompressFolder(QString sZipFilePath, QString sDestPath) OnScopeExit(delete mz); mz_zip_zero_struct(mz); - mz_bool ok = mz_zip_reader_init_file(mz, sZipFilePath.toUtf8().data(), 0); + mz_bool ok = mz_zip_reader_init_file(mz, zipFilePath.toUtf8().data(), 0); if (!ok) return Status(Status::FAIL, dd); diff --git a/core_lib/src/qminiz.h b/core_lib/src/qminiz.h index 7a37389cc..3395264a9 100644 --- a/core_lib/src/qminiz.h +++ b/core_lib/src/qminiz.h @@ -22,7 +22,7 @@ GNU General Public License for more details. namespace MiniZ { bool isZip(const QString& sZipFilePath); - Status compressFolder(QString sZipFilePath, QString sSrcPath); - Status uncompressFolder(QString sZipFilePath, QString sDestPath); + Status compressFolder(QString zipFilePath, QString srcFolderPath, const QStringList& fileList); + Status uncompressFolder(QString zipFilePath, QString destPath); } #endif diff --git a/core_lib/src/structure/filemanager.cpp b/core_lib/src/structure/filemanager.cpp index ab39f9ec6..8ceedd3bd 100644 --- a/core_lib/src/structure/filemanager.cpp +++ b/core_lib/src/structure/filemanager.cpp @@ -234,9 +234,9 @@ bool FileManager::loadObjectOldWay(Object* object, const QDomElement& root) return object->loadXML(root, [this] { progressForward(); }); } -bool FileManager::isOldForamt(const QString& fileName) +bool FileManager::isOldForamt(const QString& fileName) const { - return (MiniZ::isZip(fileName) == false); + return !MiniZ::isZip(fileName); } Status FileManager::save(Object* object, QString strFileName) @@ -284,43 +284,42 @@ Status FileManager::save(Object* object, QString strFileName) tr("The path (\"%1\") is not writable.").arg(fileInfo.absoluteFilePath())); } - QString strTempWorkingFolder; - QString strMainXMLFile; - QString strDataFolder; + QString sTempWorkingFolder; + QString sMainXMLFile; + QString sDataFolder; - bool isOldFile = strFileName.endsWith(PFF_OLD_EXTENSION); - if (isOldFile) + bool isOldType = strFileName.endsWith(PFF_OLD_EXTENSION); + if (isOldType) { - qCDebug(mLog) << "Old Pencil File Format (*.pcl) !"; + dd << "Old Pencil File Format (*.pcl) !"; - strMainXMLFile = strFileName; - strDataFolder = strMainXMLFile + "." + PFF_OLD_DATA_DIR; + sMainXMLFile = strFileName; + sDataFolder = sMainXMLFile + "." + PFF_OLD_DATA_DIR; } else { - qCDebug(mLog) << "New zipped Pencil File Format (*.pclx) !"; + dd << "New zipped Pencil File Format (*.pclx) !"; - strTempWorkingFolder = object->workingDir(); - Q_ASSERT(QDir(strTempWorkingFolder).exists()); - dd << QString("strTempWorkingFolder = ").append(strTempWorkingFolder); + sTempWorkingFolder = object->workingDir(); + Q_ASSERT(QDir(sTempWorkingFolder).exists()); + dd << QString("TempWorkingFolder = ").append(sTempWorkingFolder); - qCDebug(mLog) << "Temp Folder=" << strTempWorkingFolder; - strMainXMLFile = QDir(strTempWorkingFolder).filePath(PFF_XML_FILE_NAME); - strDataFolder = QDir(strTempWorkingFolder).filePath(PFF_OLD_DATA_DIR); + sMainXMLFile = QDir(sTempWorkingFolder).filePath(PFF_XML_FILE_NAME); + sDataFolder = QDir(sTempWorkingFolder).filePath(PFF_OLD_DATA_DIR); } - QFileInfo dataInfo(strDataFolder); + QFileInfo dataInfo(sDataFolder); if (!dataInfo.exists()) { - QDir dir(strDataFolder); // the directory where all key frames will be saved + QDir dir(sDataFolder); // the directory where all key frames will be saved - if (!dir.mkpath(strDataFolder)) + if (!dir.mkpath(sDataFolder)) { dd << QString("dir.absolutePath() = %1").arg(dir.absolutePath()); return Status(Status::FAIL, dd, tr("Cannot Create Data Directory"), - tr("Failed to create directory \"%1\". Please make sure you have sufficient permissions.").arg(strDataFolder)); + tr("Failed to create directory \"%1\". Please make sure you have sufficient permissions.").arg(sDataFolder)); } } if (!dataInfo.isDir()) @@ -333,39 +332,41 @@ Status FileManager::save(Object* object, QString strFileName) } // save data - int layerCount = object->getLayerCount(); - dd << QString("layerCount = %1").arg(layerCount); + int numLayers = object->getLayerCount(); + dd << QString("Total %1 layers").arg(numLayers); + + QStringList attachedFiles; - bool saveLayerOK = true; - for (int i = 0; i < layerCount; ++i) + bool saveLayersOK = true; + for (int i = 0; i < numLayers; ++i) { Layer* layer = object->getLayer(i); - dd << QString("layer[%1] = Layer[id=%2, name=%3, type=%4]").arg(i).arg(layer->id()).arg(layer->name()).arg(layer->type()); + dd << QString("Layer[%1] = [id=%2, name=%3, type=%4]").arg(i).arg(layer->id()).arg(layer->name()).arg(layer->type()); - Status st = layer->save(strDataFolder, [this] { progressForward(); }); + Status st = layer->save(sDataFolder, attachedFiles, [this] { progressForward(); }); if (!st.ok()) { - saveLayerOK = false; + saveLayersOK = false; dd.collect(st.details()); - dd << QString(" !! Failed to save Layer[%1] %2 ").arg(i).arg(layer->name()); + dd << QString(" !! Failed to save Layer[%1] %2").arg(i).arg(layer->name()); } } dd << "All Layers saved"; // save palette - bool bPaletteOK = object->savePalette(strDataFolder); - if (!bPaletteOK) - { + QString sPaletteFile = object->savePalette(sDataFolder); + if (!sPaletteFile.isEmpty()) + attachedFiles.append(sPaletteFile); + else dd << "Failed to save palette"; - } - + progressForward(); // -------- save main XML file ----------- - QFile file(strMainXMLFile); + QFile file(sMainXMLFile); if (!file.open(QFile::WriteOnly | QFile::Text)) { - return Status::ERROR_FILE_CANNOT_OPEN; + return Status(Status::ERROR_FILE_CANNOT_OPEN, dd); } QDomDocument xmlDoc("PencilDocument"); @@ -377,8 +378,8 @@ Status FileManager::save(Object* object, QString strFileName) progressForward(); // save editor information - QDomElement projectDataElement = saveProjectData(object->data(), xmlDoc); - root.appendChild(projectDataElement); + QDomElement projDataXml = saveProjectData(object->data(), xmlDoc); + root.appendChild(projDataXml); // save object QDomElement objectElement = object->saveXML(xmlDoc); @@ -386,21 +387,23 @@ Status FileManager::save(Object* object, QString strFileName) dd << "Writing main xml file..."; - const int IndentSize = 2; + const int indentSize = 2; QTextStream out(&file); - xmlDoc.save(out, IndentSize); + xmlDoc.save(out, indentSize); out.flush(); file.close(); dd << "Done writing main xml file"; + attachedFiles.append(sMainXMLFile); + progressForward(); - if (!isOldFile) + if (!isOldType) { dd << "Miniz"; - Status s = MiniZ::compressFolder(strFileName, strTempWorkingFolder); + Status s = MiniZ::compressFolder(strFileName, sTempWorkingFolder, attachedFiles); if (!s.ok()) { dd.collect(s.details()); @@ -416,7 +419,7 @@ Status FileManager::save(Object* object, QString strFileName) progressForward(); - if (!saveLayerOK) + if (!saveLayersOK) { return Status(Status::FAIL, dd, tr("Internal Error"), diff --git a/core_lib/src/structure/filemanager.h b/core_lib/src/structure/filemanager.h index 4dbc0e6ef..bc27059b6 100644 --- a/core_lib/src/structure/filemanager.h +++ b/core_lib/src/structure/filemanager.h @@ -42,7 +42,7 @@ class FileManager : public QObject Status save(Object*, QString strFileName); QList loadPaletteFile(QString strFilename); - Status error() { return mError; } + Status error() const { return mError; } Status verifyObject(Object* obj); Q_SIGNALS: @@ -54,7 +54,7 @@ class FileManager : public QObject bool loadObject(Object*, const QDomElement& root); bool loadObjectOldWay(Object*, const QDomElement& root); - bool isOldForamt(const QString& fileName); + bool isOldForamt(const QString& fileName) const; bool loadPalette(Object*); ObjectData* loadProjectData(const QDomElement& element); diff --git a/core_lib/src/structure/layer.cpp b/core_lib/src/structure/layer.cpp index 6cd1b582b..fac674f12 100644 --- a/core_lib/src/structure/layer.cpp +++ b/core_lib/src/structure/layer.cpp @@ -277,30 +277,32 @@ bool Layer::loadKey(KeyFrame* pKey) return true; } -Status Layer::save(QString strDataFolder, ProgressCallback progressStep) +Status Layer::save(const QString& sDataFolder, QStringList& attachedFiles, ProgressCallback progressStep) { - DebugDetails debugInfo; - debugInfo << "Layer::save"; - debugInfo << ("strDataFolder = " + strDataFolder); + DebugDetails dd; + dd << __FUNCTION__; - bool isOkay = true; + bool ok = true; for (auto pair : mKeyFrames) { - KeyFrame* pKeyFrame = pair.second; - Status st = saveKeyFrameFile(pKeyFrame, strDataFolder); - if (!st.ok()) + KeyFrame* keyFrame = pair.second; + Status st = saveKeyFrameFile(keyFrame, sDataFolder); + if (st.ok()) { - isOkay = false; - - debugInfo.collect(st.details()); - debugInfo << QString("- Keyframe[%1] failed to save").arg(pKeyFrame->pos()); // << keyFrameDetails; + attachedFiles.append(keyFrame->fileName()); + } + else + { + ok = false; + dd.collect(st.details()); + dd << QString("- Keyframe[%1] failed to save").arg(keyFrame->pos()); // << keyFrameDetails; } progressStep(); } - if (!isOkay) + if (!ok) { - return Status(Status::FAIL, debugInfo); + return Status(Status::FAIL, dd); } return Status::OK; } @@ -441,7 +443,7 @@ void Layer::setModified(int position, bool modified) } } -bool Layer::isFrameSelected(int position) +bool Layer::isFrameSelected(int position) const { KeyFrame* keyFrame = getKeyFrameWhichCovers(position); if (keyFrame) @@ -636,20 +638,9 @@ bool Layer::moveSelectedFrames(int offset) return false; } -bool Layer::isPaintable() +bool Layer::isPaintable() const { - switch (type()) - { - case BITMAP: - case VECTOR: - return true; - case CAMERA: - case SOUND: - return false; - default: - break; - } - return false; + return (type() == BITMAP || type() == VECTOR); } bool Layer::keyExistsWhichCovers(int frameNumber) @@ -657,7 +648,7 @@ bool Layer::keyExistsWhichCovers(int frameNumber) return getKeyFrameWhichCovers(frameNumber) != nullptr; } -KeyFrame* Layer::getKeyFrameWhichCovers(int frameNumber) +KeyFrame* Layer::getKeyFrameWhichCovers(int frameNumber) const { auto keyFrame = getLastKeyFrameAtPosition(frameNumber); if (keyFrame != nullptr) diff --git a/core_lib/src/structure/layer.h b/core_lib/src/structure/layer.h index 4e73198e6..6f53dc07a 100644 --- a/core_lib/src/structure/layer.h +++ b/core_lib/src/structure/layer.h @@ -90,7 +90,7 @@ class Layer : public QObject KeyFrame* getKeyFrameAt(int position) const; KeyFrame* getLastKeyFrameAtPosition(int position) const; bool keyExistsWhichCovers(int frameNumber); - KeyFrame *getKeyFrameWhichCovers(int frameNumber); + KeyFrame *getKeyFrameWhichCovers(int frameNumber) const; bool getVisibility() { return mVisible; } void foreachKeyFrame(std::function); @@ -98,7 +98,7 @@ class Layer : public QObject void setModified(int position, bool isModified); // Handle selection - bool isFrameSelected(int position); + bool isFrameSelected(int position) const; void setFrameSelected(int position, bool isSelected); void toggleFrameSelected(int position, bool allowMultiple = false); void extendSelectionTo(int position); @@ -107,7 +107,7 @@ class Layer : public QObject bool moveSelectedFrames(int offset); - Status save(QString dataFolder, ProgressCallback progressStep); + Status save(const QString& sDataFolder, QStringList& attachedFiles, ProgressCallback progressStep); // graphic representation -- could be put in another class void paintTrack(QPainter& painter, TimeLineCells* cells, int x, int y, int width, int height, bool selected, int frameSize); @@ -118,7 +118,7 @@ class Layer : public QObject virtual void editProperties(); - bool isPaintable(); + bool isPaintable() const; protected: void setId(int LayerId) { mId = LayerId; } diff --git a/core_lib/src/structure/layerbitmap.cpp b/core_lib/src/structure/layerbitmap.cpp index 82b392023..9d8e09527 100644 --- a/core_lib/src/structure/layerbitmap.cpp +++ b/core_lib/src/structure/layerbitmap.cpp @@ -61,19 +61,20 @@ Status LayerBitmap::saveKeyFrameFile(KeyFrame* keyframe, QString path) { return Status::SAFE; } - //qDebug() << "write: " << strFilePath; BitmapImage* bitmapImage = static_cast(keyframe); Status st = bitmapImage->writeFile(strFilePath); if (!st.ok()) { - DebugDetails debugInfo; - debugInfo << "LayerBitmap::saveKeyFrame"; - debugInfo << QString(" KeyFrame.pos() = %1").arg(keyframe->pos()); - debugInfo << QString(" path = %1").arg(path); - debugInfo << QString(" strFilePath = %1").arg(strFilePath); - debugInfo << QString("BitmapImage could not be saved"); - return Status(Status::FAIL, debugInfo); + bitmapImage->setFileName(""); + + DebugDetails dd; + dd << "LayerBitmap::saveKeyFrame"; + dd << QString(" KeyFrame.pos() = %1").arg(keyframe->pos()); + dd << QString(" strFilePath = %1").arg(strFilePath); + dd << QString("BitmapImage could not be saved"); + dd.collect(st.details()); + return Status(Status::FAIL, dd); } bitmapImage->setFileName(strFilePath); diff --git a/core_lib/src/structure/layersound.cpp b/core_lib/src/structure/layersound.cpp index b727c8a56..7e203f1fa 100644 --- a/core_lib/src/structure/layersound.cpp +++ b/core_lib/src/structure/layersound.cpp @@ -145,11 +145,21 @@ Status LayerSound::saveKeyFrameFile(KeyFrame* key, QString path) if (sDestFileLocation != key->fileName()) { - bool bOK = QFile::copy(key->fileName(), sDestFileLocation); - Q_ASSERT(bOK); + if (QFile::exists(sDestFileLocation)) + QFile::remove(sDestFileLocation); - if (!bOK) return Status::FAIL; - + bool ok = QFile::copy(key->fileName(), sDestFileLocation); + if (!ok) + { + key->setFileName(""); + + DebugDetails dd; + dd << __FUNCTION__; + dd << QString(" KeyFrame.pos() = %1").arg(key->pos()); + dd << QString(" FilePath = %1").arg(sDestFileLocation); + dd << QString("Couldn't save the sound clip"); + return Status::FAIL; + } key->setFileName(sDestFileLocation); } return Status::OK; diff --git a/core_lib/src/structure/layersound.h b/core_lib/src/structure/layersound.h index cfead1ca3..86229e640 100644 --- a/core_lib/src/structure/layersound.h +++ b/core_lib/src/structure/layersound.h @@ -38,7 +38,7 @@ class LayerSound : public Layer SoundClip* getSoundClipWhichCovers(int frameNumber); protected: - Status saveKeyFrameFile( KeyFrame*, QString path ) override; + Status saveKeyFrameFile(KeyFrame*, QString path) override; KeyFrame* createKeyFrame(int position, Object*) override; }; diff --git a/core_lib/src/structure/layervector.cpp b/core_lib/src/structure/layervector.cpp index 5967a1ef3..1836c6df0 100644 --- a/core_lib/src/structure/layervector.cpp +++ b/core_lib/src/structure/layervector.cpp @@ -75,20 +75,18 @@ Status LayerVector::saveKeyFrameFile(KeyFrame* keyFrame, QString path) return Status::SAFE; } - qDebug() << "write: " << strFilePath; - Status st = vecImage->write(strFilePath, "VEC"); if (!st.ok()) { - DebugDetails debugInfo; - debugInfo << "LayerVector::saveKeyFrame"; - debugInfo << QString("pKeyFrame.pos() = %1").arg(keyFrame->pos()); - debugInfo << QString("path = ").append(path); - debugInfo << QString("strFilePath = ").append(strFilePath); - - debugInfo.collect(st.details()); - debugInfo << "- VectorImage failed to write"; - return Status(Status::FAIL, debugInfo); + vecImage->setFileName(""); + + DebugDetails dd; + dd << __FUNCTION__; + dd << QString("KeyFrame.pos() = %1").arg(keyFrame->pos()); + dd << QString("FilePath = ").append(strFilePath); + dd << "- VectorImage failed to write"; + dd.collect(st.details()); + return Status(Status::FAIL, dd); } vecImage->setFileName(strFilePath); diff --git a/core_lib/src/structure/object.cpp b/core_lib/src/structure/object.cpp index 6171c53cc..110fa96d2 100644 --- a/core_lib/src/structure/object.cpp +++ b/core_lib/src/structure/object.cpp @@ -323,9 +323,13 @@ void Object::renameColour(int i, QString text) mPalette[i].name = text; } -bool Object::savePalette(QString filePath) +QString Object::savePalette(QString dataFolder) { - return exportPalette(filePath + "/palette.xml"); + QString fullPath = QDir(dataFolder).filePath("/palette.xml"); + bool ok = exportPalette(fullPath); + if (ok) + return fullPath; + return ""; } bool Object::exportPalette(QString filePath) diff --git a/core_lib/src/structure/object.h b/core_lib/src/structure/object.h index dfc115080..c9868a1f7 100644 --- a/core_lib/src/structure/object.h +++ b/core_lib/src/structure/object.h @@ -91,7 +91,7 @@ class Object : public QObject int getColourCount() { return mPalette.size(); } bool importPalette( QString filePath ); bool exportPalette( QString filePath ); - bool savePalette( QString filePath ); + QString savePalette( QString dataFolder ); void loadDefaultPalette(); From 80358e68e369930ecaef9efbed5af99f1b3ea924 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 5 Jun 2018 16:27:25 +1000 Subject: [PATCH 083/184] Remove an inappropriate unit test --- tests/src/test_filemanager.cpp | 42 ---------------------------------- 1 file changed, 42 deletions(-) diff --git a/tests/src/test_filemanager.cpp b/tests/src/test_filemanager.cpp index bb29c274c..9db23867d 100644 --- a/tests/src/test_filemanager.cpp +++ b/tests/src/test_filemanager.cpp @@ -217,48 +217,6 @@ TEST_CASE("FileManager Load-a-zip Test") { SECTION("Load a PCLX zip file") { - QTemporaryDir testDir("PENCIL_TEST_XXXXXXXX"); - REQUIRE(testDir.isValid()); - - // manually build a working project - // and use filemanager to load it. - QString sWorkFolderPath = testDir.path() + "/project_x"; - QDir workDir(sWorkFolderPath); - REQUIRE(workDir.makeAbsolute()); - REQUIRE(workDir.mkpath(".")); - - QString strMainXMLPath = workDir.filePath(PFF_XML_FILE_NAME); - - QFile theXML(strMainXMLPath); - theXML.open(QIODevice::WriteOnly); - - QTextStream fout(&theXML); - fout << ""; - fout << " "; - fout << " "; - fout << " "; - fout << " "; - fout << " "; - fout << ""; - theXML.close(); - - REQUIRE(workDir.mkdir(PFF_DATA_DIR)); - - QImage img(10, 10, QImage::Format_ARGB32_Premultiplied); - REQUIRE(img.save(workDir.absolutePath() + "/" PFF_DATA_DIR "/005.001.png")); - - QString pclxFile = QDir(testDir.path()).filePath("test-animation.pclx"); - Status s = MiniZ::compressFolder(pclxFile, workDir.absolutePath()); - REQUIRE(s.ok()); - - FileManager fm; - Object* o = fm.load(pclxFile); - - REQUIRE(fm.error().ok()); - - Layer* layer = o->getLayer(0); - REQUIRE(layer->name() == "MyBitmapLayer"); - REQUIRE(layer->id() == 5); } } From da6df8e49ddb9d5bf27be4d350e258f7035c3e92 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 5 Jun 2018 20:57:47 +1000 Subject: [PATCH 084/184] avoid repeating the same error message --- core_lib/src/structure/filemanager.cpp | 81 ++++++++------------------ 1 file changed, 23 insertions(+), 58 deletions(-) diff --git a/core_lib/src/structure/filemanager.cpp b/core_lib/src/structure/filemanager.cpp index 8ceedd3bd..14e9a15d1 100644 --- a/core_lib/src/structure/filemanager.cpp +++ b/core_lib/src/structure/filemanager.cpp @@ -24,6 +24,19 @@ GNU General Public License for more details. #include "object.h" +QString openErrorTitle = QObject::tr("Could not open file"); +QString openErrorDesc = QObject::tr("There was an error processing your file. This usually means that your project has " + "been at least partially corrupted. You can try again with a newer version of Pencil2D, " + "or you can try to use a backup file if you have one. If you contact us through one of " + "our offical channels we may be able to help you. For reporting issues, " + "the best places to reach us are:"); +QString contactLinks = ""; + + FileManager::FileManager(QObject *parent) : QObject(parent), mLog("FileManager") { @@ -90,16 +103,7 @@ Object* FileManager::load(QString strFileName) if (!file.exists()) { dd << "Main XML file does not exist"; - return cleanUpWithErrorCode(Status(Status::ERROR_INVALID_XML_FILE, dd, tr("Could not open file"), - tr("There was an error processing your file. This usually means that your project has " - "been at least partially corrupted. You can try again with a newer version of Pencil2D, " - "or you can try to use a backup file if you have one. If you contact us through one of " - "our offical channels we may be able to further assist you. For reporting issues, " - "the best places to reach us are:").append(""))); + return cleanUpWithErrorCode(Status(Status::ERROR_INVALID_XML_FILE, dd, openErrorTitle, openErrorDesc.append(contactLinks))); } if (!file.open(QFile::ReadOnly)) { @@ -113,48 +117,21 @@ Object* FileManager::load(QString strFileName) { qCDebug(mLog) << "Couldn't open the main XML file."; dd << "Error parsing or opening the main XML file"; - return cleanUpWithErrorCode(Status(Status::ERROR_INVALID_XML_FILE, dd, tr("Could not open file"), - tr("There was an error processing your file. This usually means that your project has " - "been at least partially corrupted. You can try again with a newer version of Pencil2D, " - "or you can try to use a backup file if you have one. If you contact us through one of " - "our offical channels we may be able to further assist you. For reporting issues, " - "the best places to reach us are:").append(""))); + return cleanUpWithErrorCode(Status(Status::ERROR_INVALID_XML_FILE, dd, openErrorTitle, openErrorDesc.append(contactLinks))); } QDomDocumentType type = xmlDoc.doctype(); if (!(type.name() == "PencilDocument" || type.name() == "MyObject")) { dd << QString("Invalid main XML doctype: ").append(type.name()); - return cleanUpWithErrorCode(Status(Status::ERROR_INVALID_PENCIL_FILE, dd, tr("Could not open file"), - tr("There was an error processing your file. This usually means that your project has " - "been at least partially corrupted. You can try again with a newer version of Pencil2D, " - "or you can try to use a backup file if you have one. If you contact us through one of " - "our offical channels we may be able to further assist you. For reporting issues, " - "the best places to reach us are:").append(""))); + return cleanUpWithErrorCode(Status(Status::ERROR_INVALID_PENCIL_FILE, dd, openErrorTitle, openErrorDesc.append(contactLinks))); } QDomElement root = xmlDoc.documentElement(); if (root.isNull()) { dd << "Main XML root node is null"; - return cleanUpWithErrorCode(Status(Status::ERROR_INVALID_PENCIL_FILE, dd, tr("Could not open file"), - tr("There was an error processing your file. This usually means that your project has " - "been at least partially corrupted. You can try again with a newer version of Pencil2D, " - "or you can try to use a backup file if you have one. If you contact us through one of " - "our offical channels we may be able to further assist you. For reporting issues, " - "the best places to reach us are:").append(""))); + return cleanUpWithErrorCode(Status(Status::ERROR_INVALID_PENCIL_FILE, dd, openErrorTitle, openErrorDesc.append(contactLinks))); } loadPalette(obj); @@ -174,16 +151,7 @@ Object* FileManager::load(QString strFileName) { delete obj; dd << "Issue occurred during object loading"; - return cleanUpWithErrorCode(Status(Status::ERROR_INVALID_PENCIL_FILE, dd, tr("Could not open file"), - tr("There was an error processing your file. This usually means that your project has " - "been at least partially corrupted. You can try again with a newer version of Pencil2D, " - "or you can try to use a backup file if you have one. If you contact us through one of " - "our offical channels we may be able to further assist you. For reporting issues, " - "the best places to reach us are:").append(""))); + return cleanUpWithErrorCode(Status(Status::ERROR_INVALID_PENCIL_FILE, dd, "")); } verifyObject(obj); @@ -195,11 +163,9 @@ bool FileManager::loadObject(Object* object, const QDomElement& root) { QDomElement e = root.firstChildElement("object"); if (e.isNull()) - { return false; - } - bool isOK = true; + bool ok = true; for (QDomNode node = root.firstChild(); !node.isNull(); node = node.nextSibling()) { QDomElement element = node.toElement(); // try to convert the node to an element. @@ -210,9 +176,9 @@ bool FileManager::loadObject(Object* object, const QDomElement& root) if (element.tagName() == "object") { - isOK = object->loadXML(element, [this]{ progressForward(); }); + ok = object->loadXML(element, [this]{ progressForward(); }); - if (!isOK) qCDebug(mLog) << "Failed to Load object"; + if (!ok) qCDebug(mLog) << "Failed to Load object"; } else if (element.tagName() == "editor" || element.tagName() == "projectdata") @@ -225,8 +191,7 @@ bool FileManager::loadObject(Object* object, const QDomElement& root) Q_ASSERT(false); } } - - return isOK; + return ok; } bool FileManager::loadObjectOldWay(Object* object, const QDomElement& root) @@ -236,7 +201,7 @@ bool FileManager::loadObjectOldWay(Object* object, const QDomElement& root) bool FileManager::isOldForamt(const QString& fileName) const { - return !MiniZ::isZip(fileName); + return !(MiniZ::isZip(fileName)); } Status FileManager::save(Object* object, QString strFileName) From cf36dff04a2787180a62c5bfe57e901dbe274353 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 5 Jun 2018 21:42:02 +1000 Subject: [PATCH 085/184] Fix the wrong palette path --- core_lib/src/structure/object.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core_lib/src/structure/object.cpp b/core_lib/src/structure/object.cpp index 110fa96d2..fe339438f 100644 --- a/core_lib/src/structure/object.cpp +++ b/core_lib/src/structure/object.cpp @@ -325,7 +325,7 @@ void Object::renameColour(int i, QString text) QString Object::savePalette(QString dataFolder) { - QString fullPath = QDir(dataFolder).filePath("/palette.xml"); + QString fullPath = QDir(dataFolder).filePath("palette.xml"); bool ok = exportPalette(fullPath); if (ok) return fullPath; From 1d36664e5866e4df2a7abb58578f833acf570828 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 5 Jun 2018 21:42:38 +1000 Subject: [PATCH 086/184] Don't add an empty path to zipped file list - they are camera keys --- core_lib/src/structure/layer.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core_lib/src/structure/layer.cpp b/core_lib/src/structure/layer.cpp index fac674f12..ab2d6195e 100644 --- a/core_lib/src/structure/layer.cpp +++ b/core_lib/src/structure/layer.cpp @@ -290,13 +290,15 @@ Status Layer::save(const QString& sDataFolder, QStringList& attachedFiles, Progr Status st = saveKeyFrameFile(keyFrame, sDataFolder); if (st.ok()) { - attachedFiles.append(keyFrame->fileName()); + //qDebug() << "Layer [" << name() << "] FN=" << keyFrame->fileName(); + if (!keyFrame->fileName().isEmpty()) + attachedFiles.append(keyFrame->fileName()); } else { ok = false; dd.collect(st.details()); - dd << QString("- Keyframe[%1] failed to save").arg(keyFrame->pos()); // << keyFrameDetails; + dd << QString("- Keyframe[%1] failed to save").arg(keyFrame->pos()); } progressStep(); } From 439a2fa605bec727373d1f37bc0ff02d97e8d435 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 5 Jun 2018 21:45:48 +1000 Subject: [PATCH 087/184] clean up --- core_lib/src/structure/filemanager.cpp | 51 ++++++++++++-------------- core_lib/src/structure/filemanager.h | 4 +- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/core_lib/src/structure/filemanager.cpp b/core_lib/src/structure/filemanager.cpp index 14e9a15d1..3c4fc7b41 100644 --- a/core_lib/src/structure/filemanager.cpp +++ b/core_lib/src/structure/filemanager.cpp @@ -43,51 +43,48 @@ mLog("FileManager") ENABLE_DEBUG_LOG(mLog, false); } -Object* FileManager::load(QString strFileName) +Object* FileManager::load(QString sFileName) { DebugDetails dd; - dd << QString("File name: ").append(strFileName); - if (!QFile::exists(strFileName)) + dd << QString("File name: ").append(sFileName); + if (!QFile::exists(sFileName)) { qCDebug(mLog) << "ERROR - File doesn't exist."; return cleanUpWithErrorCode(Status(Status::FILE_NOT_FOUND, dd, tr("Could not open file"), - tr("The file you have selected does not exist, so we are unable to open it. Please check " - "to make sure that you've entered the correct path and that the file is accessible and try again."))); + tr("The file does not exist, so we are unable to open it. Please check " + "to make sure the path is correct and that the file is accessible and try again."))); } progressForward(); Object* obj = new Object; - obj->setFilePath(strFileName); + obj->setFilePath(sFileName); obj->createWorkingDir(); QString strMainXMLFile; QString strDataFolder; // Test file format: new zipped .pclx or old .pcl? - bool oldFormat = isOldForamt(strFileName); + bool oldFormat = isOldForamt(sFileName); dd << QString("Is old format: ").append(oldFormat ? "true" : "false"); if (oldFormat) { - qCDebug(mLog) << "Recognized Old Pencil File Format (*.pcl) !"; + dd << "Recognized Old Pencil File Format (*.pcl) !"; - strMainXMLFile = strFileName; + strMainXMLFile = sFileName; strDataFolder = strMainXMLFile + "." + PFF_OLD_DATA_DIR; } else { - qCDebug(mLog) << "Recognized New zipped Pencil File Format (*.pclx) !"; + dd << "Recognized New zipped Pencil File Format (*.pclx) !"; - unzip(strFileName, obj->workingDir()); + unzip(sFileName, obj->workingDir()); strMainXMLFile = QDir(obj->workingDir()).filePath(PFF_XML_FILE_NAME); strDataFolder = QDir(obj->workingDir()).filePath(PFF_DATA_DIR); } - qCDebug(mLog) << " XML=" << strMainXMLFile; - qCDebug(mLog) << " Data Folder=" << strDataFolder; - qCDebug(mLog) << " Working Folder=" << obj->workingDir(); dd << QString("XML file: ").append(strMainXMLFile) << QString("Data folder: ").append(strDataFolder) << QString("Working folder: ").append(obj->workingDir()); @@ -204,11 +201,11 @@ bool FileManager::isOldForamt(const QString& fileName) const return !(MiniZ::isZip(fileName)); } -Status FileManager::save(Object* object, QString strFileName) +Status FileManager::save(Object* object, QString sFileName) { DebugDetails dd; dd << "FileManager::save"; - dd << ("strFileName = " + strFileName); + dd << ("sFileName = " + sFileName); if (object == nullptr) { @@ -222,7 +219,7 @@ Status FileManager::save(Object* object, QString strFileName) progressForward(); - QFileInfo fileInfo(strFileName); + QFileInfo fileInfo(sFileName); if (fileInfo.isDir()) { dd << "FileName points to a directory"; @@ -234,7 +231,7 @@ Status FileManager::save(Object* object, QString strFileName) QFileInfo parentDirInfo(fileInfo.dir().absolutePath()); if (!parentDirInfo.exists()) { - dd << "The parent directory of strFileName does not exist"; + dd << "The parent directory of sFileName does not exist"; return Status(Status::INVALID_ARGUMENT, dd, tr("Invalid Save Path"), @@ -253,12 +250,12 @@ Status FileManager::save(Object* object, QString strFileName) QString sMainXMLFile; QString sDataFolder; - bool isOldType = strFileName.endsWith(PFF_OLD_EXTENSION); + bool isOldType = sFileName.endsWith(PFF_OLD_EXTENSION); if (isOldType) { dd << "Old Pencil File Format (*.pcl) !"; - sMainXMLFile = strFileName; + sMainXMLFile = sFileName; sDataFolder = sMainXMLFile + "." + PFF_OLD_DATA_DIR; } else @@ -300,7 +297,7 @@ Status FileManager::save(Object* object, QString strFileName) int numLayers = object->getLayerCount(); dd << QString("Total %1 layers").arg(numLayers); - QStringList attachedFiles; + QStringList zippedFiles; bool saveLayersOK = true; for (int i = 0; i < numLayers; ++i) @@ -308,7 +305,7 @@ Status FileManager::save(Object* object, QString strFileName) Layer* layer = object->getLayer(i); dd << QString("Layer[%1] = [id=%2, name=%3, type=%4]").arg(i).arg(layer->id()).arg(layer->name()).arg(layer->type()); - Status st = layer->save(sDataFolder, attachedFiles, [this] { progressForward(); }); + Status st = layer->save(sDataFolder, zippedFiles, [this] { progressForward(); }); if (!st.ok()) { saveLayersOK = false; @@ -321,9 +318,9 @@ Status FileManager::save(Object* object, QString strFileName) // save palette QString sPaletteFile = object->savePalette(sDataFolder); if (!sPaletteFile.isEmpty()) - attachedFiles.append(sPaletteFile); + zippedFiles.append(sPaletteFile); else - dd << "Failed to save palette"; + dd << "Failed to save the palette xml"; progressForward(); @@ -361,14 +358,14 @@ Status FileManager::save(Object* object, QString strFileName) dd << "Done writing main xml file"; - attachedFiles.append(sMainXMLFile); + zippedFiles.append(sMainXMLFile); progressForward(); if (!isOldType) { dd << "Miniz"; - Status s = MiniZ::compressFolder(strFileName, sTempWorkingFolder, attachedFiles); + Status s = MiniZ::compressFolder(sFileName, sTempWorkingFolder, zippedFiles); if (!s.ok()) { dd.collect(s.details()); @@ -379,7 +376,7 @@ Status FileManager::save(Object* object, QString strFileName) dd << "Zip file saved successfully"; } - object->setFilePath(strFileName); + object->setFilePath(sFileName); object->setModified(false); progressForward(); diff --git a/core_lib/src/structure/filemanager.h b/core_lib/src/structure/filemanager.h index bc27059b6..b25322565 100644 --- a/core_lib/src/structure/filemanager.h +++ b/core_lib/src/structure/filemanager.h @@ -38,8 +38,8 @@ class FileManager : public QObject public: FileManager(QObject* parent = 0); - Object* load(QString strFilenNme); - Status save(Object*, QString strFileName); + Object* load(QString sFilenNme); + Status save(Object*, QString sFileName); QList loadPaletteFile(QString strFilename); Status error() const { return mError; } From 539f7ad10e4487fb96adb3c7690ef62b571f2561 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 5 Jun 2018 22:07:07 +1000 Subject: [PATCH 088/184] #959 Update the macOS ffmpeg version from 3.2.4 to 3.4.2 --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7b9f6df48..cfdaae19e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -119,9 +119,9 @@ after_success: echo "Copying ffmpeg plugin"; mkdir Pencil2D.app/Contents/MacOS/plugins; - wget -P Pencil2D.app/Contents/MacOS/plugins https://evermeet.cx/ffmpeg/ffmpeg-3.2.4.7z; - 7z x Pencil2D.app/Contents/MacOS/plugins/ffmpeg-3.2.4.7z -o"Pencil2D.app/Contents/MacOS/plugins"; - rm Pencil2D.app/Contents/MacOs/plugins/ffmpeg-3.2.4.7z; + wget -P Pencil2D.app/Contents/MacOS/plugins https://evermeet.cx/pub/ffmpeg/ffmpeg-3.4.2.7z; + 7z x Pencil2D.app/Contents/MacOS/plugins/ffmpeg-3.4.2.7z -o"Pencil2D.app/Contents/MacOS/plugins"; + rm Pencil2D.app/Contents/MacOs/plugins/ffmpeg-3.4.2.7z; echo "Copying necessary Qt frameworks"; macdeployqt Pencil2D.app; From 1869344729827c54ae74d68206d336c8c6737104 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 5 Jun 2018 22:28:35 +1000 Subject: [PATCH 089/184] #938 backup project before saving --- core_lib/src/structure/filemanager.cpp | 35 ++++++++++++++++++++++++-- core_lib/src/structure/filemanager.h | 4 ++- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/core_lib/src/structure/filemanager.cpp b/core_lib/src/structure/filemanager.cpp index 3c4fc7b41..8ea8a1ed5 100644 --- a/core_lib/src/structure/filemanager.cpp +++ b/core_lib/src/structure/filemanager.cpp @@ -365,6 +365,9 @@ Status FileManager::save(Object* object, QString sFileName) if (!isOldType) { dd << "Miniz"; + + QString sBackupFile = backupPreviousFile(sFileName); + Status s = MiniZ::compressFolder(sFileName, sTempWorkingFolder, zippedFiles); if (!s.ok()) { @@ -374,6 +377,9 @@ Status FileManager::save(Object* object, QString sFileName) tr("An internal error occurred. Your file may not be saved successfully.")); } dd << "Zip file saved successfully"; + + if (s.ok() && saveLayersOK) + deleteBackupFile(sBackupFile); } object->setFilePath(sFileName); @@ -416,7 +422,6 @@ ObjectData* FileManager::loadProjectData(const QDomElement& docElem) return data; } - QDomElement FileManager::saveProjectData(ObjectData* data, QDomDocument& xmlDoc) { QDomElement rootTag = xmlDoc.createElement("projectdata"); @@ -538,6 +543,32 @@ Object* FileManager::cleanUpWithErrorCode(Status error) return nullptr; } +QString FileManager::backupPreviousFile(const QString& fileName) +{ + if (!QFile::exists(fileName)) + return ""; + + QFileInfo info(fileName); + QString sBackupFile = info.completeBaseName() + ".backup." + info.suffix(); + QString sBackupFileFullPath = QDir(info.absolutePath()).filePath(sBackupFile); + + bool ok = QFile::rename(info.absoluteFilePath(), sBackupFileFullPath); + if (!ok) + { + qDebug() << "Cannot backup the previous file."; + return ""; + } + return sBackupFileFullPath; +} + +void FileManager::deleteBackupFile(const QString& fileName) +{ + if (QFile::exists(fileName)) + { + QFile::remove(fileName); + } +} + void FileManager::progressForward() { mCurrentProgress++; @@ -548,7 +579,7 @@ bool FileManager::loadPalette(Object* obj) { qCDebug(mLog) << "Load Palette.."; - QString paletteFilePath = obj->dataDir() + "/" + PFF_PALETTE_FILE; + QString paletteFilePath = QDir(obj->dataDir()).filePath(PFF_PALETTE_FILE); if (!obj->importPalette(paletteFilePath)) { obj->loadDefaultPalette(); diff --git a/core_lib/src/structure/filemanager.h b/core_lib/src/structure/filemanager.h index b25322565..9ace6e863 100644 --- a/core_lib/src/structure/filemanager.h +++ b/core_lib/src/structure/filemanager.h @@ -61,9 +61,11 @@ class FileManager : public QObject QDomElement saveProjectData(ObjectData*, QDomDocument& xmlDoc); void extractProjectData(const QDomElement& element, ObjectData* data); - Object* cleanUpWithErrorCode(Status); + QString backupPreviousFile(const QString& fileName); + void deleteBackupFile(const QString& fileName); + void progressForward(); private: From 2520cd4d3249b49628b75e3e4caa97e55150bdd5 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Wed, 6 Jun 2018 09:46:59 +1000 Subject: [PATCH 090/184] Fix: No module named 'oauth2client' when uploading nightly builds to google drive --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index cfdaae19e..a0085aa0c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -65,7 +65,8 @@ before_install: install: - pip3 freeze > requirements.txt - pip3 install -r requirements.txt - - sudo pip3 install google-api-python-client + - sudo pip3 install --upgrade oauth2client + - sudo pip3 install --upgrade google-api-python-client - python3 -V - pip3 -V From 14a031b915521bddddb6adc68e5a9c063c7987b0 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Sun, 10 Jun 2018 23:21:18 -0600 Subject: [PATCH 091/184] Update version strings in Info.plist The 'd' suffix is for "development" and should be removed for the release --- app/data/Info.plist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/data/Info.plist b/app/data/Info.plist index edcb5b581..2a1bb953d 100644 --- a/app/data/Info.plist +++ b/app/data/Info.plist @@ -58,11 +58,11 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 0.6.0 + 0.6.2 CFBundleSignature PC2D CFBundleVersion - 0.6.0.0 + 0.6.2d LSApplicationCategoryType public.app-category.graphics-design NSHighResolutionCapable From e9a20f0717fbb95f3cef2b42d71ffbac377dd2cd Mon Sep 17 00:00:00 2001 From: CandyFace Date: Mon, 11 Jun 2018 19:57:08 +0200 Subject: [PATCH 092/184] reverse temp color solution and fix a bug. A warning will now be shown when the user tries to delete the last remaining swatch --- app/src/colorpalettewidget.cpp | 35 ++++++++++++++++++++------ app/src/colorpalettewidget.h | 4 +++ core_lib/src/managers/colormanager.cpp | 10 +------- core_lib/src/structure/object.cpp | 16 ++---------- core_lib/src/structure/object.h | 3 --- 5 files changed, 35 insertions(+), 33 deletions(-) diff --git a/app/src/colorpalettewidget.cpp b/app/src/colorpalettewidget.cpp index 464acf455..f419b808c 100644 --- a/app/src/colorpalettewidget.cpp +++ b/app/src/colorpalettewidget.cpp @@ -497,37 +497,58 @@ void ColorPaletteWidget::clickRemoveColorButton() { int index = ui->colorListWidget->row(item); - // items are not deleted by qt, has to be done manually + // items are not deleted by qt, it has to be done manually // delete should happen before removing the color from from palette // as the palette will be one ahead and crash otherwise if (editor()->object()->isColourInUse(index)) { - bool accepted = showPaletteWarning(); - if (accepted) + bool accepted = false; + if (!mMultipleSelected) + accepted = showPaletteWarning(); + + if ((accepted || mMultipleSelected) && editor()->object()->getColourCount() > 1) { delete item; editor()->object()->removeColour(index); - editor()->updateCurrentFrame(); } } + else if (editor()->object()->getColourCount() > 1) + { + delete item; + editor()->object()->removeColour(index); + } + else if (editor()->object()->getColourCount() == 1) + { + showPaletteReminder(); + } + editor()->updateCurrentFrame(); } + mMultipleSelected = false; } bool ColorPaletteWidget::showPaletteWarning() { QMessageBox msgBox; - msgBox.setText(tr("The color you are trying to delete is currently being used by one or multiple strokes, " - "if you wish to delete it anyway, you accept that the stroke(s) will be bound to the next available color")); + msgBox.setText(tr("The color(s) you are about to delete are currently being used by one or multiple strokes.")); msgBox.addButton(tr("Cancel"), QMessageBox::RejectRole); - QPushButton* removeButton = msgBox.addButton(tr("Delete anyway"), QMessageBox::AcceptRole); + QPushButton* removeButton = msgBox.addButton(tr("Delete"), QMessageBox::AcceptRole); msgBox.exec(); if (msgBox.clickedButton() == removeButton) { + if (ui->colorListWidget->selectedItems().size() > 1) + { + mMultipleSelected = true; + } return true; } return false; +} +void ColorPaletteWidget::showPaletteReminder() +{ + QMessageBox::warning(nullptr, tr("Palette Restriction"), + tr("The palette requires at least one swatch to remain functional")); } void ColorPaletteWidget::updateItemColor(int itemIndex, QColor newColor) diff --git a/app/src/colorpalettewidget.h b/app/src/colorpalettewidget.h index 71d61fedd..88ea0cc2e 100644 --- a/app/src/colorpalettewidget.h +++ b/app/src/colorpalettewidget.h @@ -41,6 +41,7 @@ class ColorPaletteWidget : public BaseDockWidget Q_OBJECT public: + explicit ColorPaletteWidget(QWidget* parent); ~ColorPaletteWidget(); @@ -78,6 +79,8 @@ private slots: void addItem(); void replaceItem(); void removeItem(); + void showPaletteReminder(); + bool showPaletteWarning(); private: @@ -103,6 +106,7 @@ private slots: QString buttonStylesheet; bool mIsColorDialog = false; + bool mMultipleSelected = false; }; diff --git a/core_lib/src/managers/colormanager.cpp b/core_lib/src/managers/colormanager.cpp index 8da6f2052..5ad12c5ec 100644 --- a/core_lib/src/managers/colormanager.cpp +++ b/core_lib/src/managers/colormanager.cpp @@ -62,15 +62,7 @@ QColor ColorManager::frontColor() { if (mIsWorkingOnVectorLayer) - if (object()->getColourCount() == 0) - { - object()->useAsTempPaletteColor(mCurrentFrontColor); - return mCurrentFrontColor; - } - else - { - return object()->getColour(mCurrentColorIndex).colour; - } + return object()->getColour(mCurrentColorIndex).colour; else return mCurrentFrontColor; } diff --git a/core_lib/src/structure/object.cpp b/core_lib/src/structure/object.cpp index 5bf86a44e..6638cbe4a 100644 --- a/core_lib/src/structure/object.cpp +++ b/core_lib/src/structure/object.cpp @@ -278,8 +278,6 @@ ColourRef Object::getColour(int index) const if (index > -1 && index < mPalette.size()) { result = mPalette.at(index); - } else { - return mFrontColor; } return result; } @@ -288,20 +286,11 @@ void Object::setColour(int index, QColor newColour) { Q_ASSERT(index >= 0); - // To allow a clean color palette, we return if it's empty - if (mPalette.isEmpty()) - { - return; - } mPalette[index].colour = newColour; } void Object::setColourRef(int index, ColourRef newColourRef) { - if (mPalette.isEmpty()) - { - return; - } mPalette[index] = newColourRef; } @@ -317,7 +306,6 @@ void Object::addColourAtIndex(int index, ColourRef newColour) bool Object::isColourInUse(int index) { - bool usesColor = false; for (int i = 0; i < getLayerCount(); i++) { Layer* layer = getLayer(i); @@ -327,11 +315,11 @@ bool Object::isColourInUse(int index) if (layerVector->usesColour(index)) { - usesColor = true; + return true; } } } - return true; + return false; } diff --git a/core_lib/src/structure/object.h b/core_lib/src/structure/object.h index dac809832..0ffcdb608 100644 --- a/core_lib/src/structure/object.h +++ b/core_lib/src/structure/object.h @@ -83,7 +83,6 @@ class Object : public QObject // Color palette ColourRef getColour( int index ) const; - void useAsTempPaletteColor(QColor color) { mFrontColor = ColourRef(color, "Front Color"); } void setColour(int index, QColor newColour); void setColourRef(int index, ColourRef newColourRef); void addColour( QColor ); @@ -155,8 +154,6 @@ class Object : public QObject QList mPalette; - ColourRef mFrontColor; - std::unique_ptr mData; }; From e99f6b44913337c778b5601c4eeda5b104c2e664 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Wed, 13 Jun 2018 10:43:39 +1000 Subject: [PATCH 093/184] Use the latest qt version for mac nightly builds --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a0085aa0c..c4c25149b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -58,7 +58,7 @@ before_install: brew upgrade python; fi brew install p7zip; - brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/13d52537d1e0e5f913de46390123436d220035f6/Formula/qt.rb; + brew install qt; brew link qt --force; fi From 596df98e27f4b9b7aaf127910ef4a0bd9e97ed75 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Wed, 13 Jun 2018 11:03:04 +1000 Subject: [PATCH 094/184] Unit test for BitmapImage::moveTopLeft() --- tests/src/test_bitmapimage.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/src/test_bitmapimage.cpp b/tests/src/test_bitmapimage.cpp index 0a298f52c..b1c561286 100644 --- a/tests/src/test_bitmapimage.cpp +++ b/tests/src/test_bitmapimage.cpp @@ -79,3 +79,16 @@ TEST_CASE("BitmapImage constructors") } } } + +TEST_CASE("BitmapImage functions") +{ + SECTION("moveTopLeft()") + { + auto b = std::make_shared(QRect(0, 0, 50, 50), Qt::red); + b->moveTopLeft(QPoint(20, 10)); + + REQUIRE(b->topLeft() == QPoint(20, 10)); + REQUIRE(b->width() == 50); + REQUIRE(b->height() == 50); + } +} From 3e9d7ea3234abf402813673ccc93a553cc8de2f0 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Wed, 13 Jun 2018 11:08:42 +1000 Subject: [PATCH 095/184] Unit test for BitmapImage::extend() --- core_lib/src/graphics/bitmap/bitmapimage.h | 1 + tests/src/test_bitmapimage.cpp | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/core_lib/src/graphics/bitmap/bitmapimage.h b/core_lib/src/graphics/bitmap/bitmapimage.h index b72f6828e..c214b3faf 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.h +++ b/core_lib/src/graphics/bitmap/bitmapimage.h @@ -92,6 +92,7 @@ class BitmapImage : public KeyFrame int bottom() { return mBounds.bottom(); } int width() { return mBounds.width(); } int height() { return mBounds.height(); } + QSize size() { return mBounds.size(); } QRect& bounds() { return mBounds; } diff --git a/tests/src/test_bitmapimage.cpp b/tests/src/test_bitmapimage.cpp index b1c561286..cc14de586 100644 --- a/tests/src/test_bitmapimage.cpp +++ b/tests/src/test_bitmapimage.cpp @@ -91,4 +91,19 @@ TEST_CASE("BitmapImage functions") REQUIRE(b->width() == 50); REQUIRE(b->height() == 50); } + + SECTION("extend()") + { + auto b = std::make_shared(QRect(0, 0, 50, 50), Qt::red); + + // before + REQUIRE(b->topLeft() == QPoint(0, 0)); + REQUIRE(b->size() == QSize(50, 50)); + + b->extend(QPoint(-10, -10)); + + // after + REQUIRE(b->topLeft() == QPoint(-10, -10)); + REQUIRE(b->size() == QSize(60, 60)); + } } From 999c05af9544706a9df72b39766704f30b378954 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Wed, 13 Jun 2018 15:28:41 +1000 Subject: [PATCH 096/184] Compile miniz in C name mangling - can't remember why I commented it out, but now it's ok to bring it back. --- core_lib/src/miniz.cpp | 4 ++-- core_lib/src/miniz.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core_lib/src/miniz.cpp b/core_lib/src/miniz.cpp index 4ed5a36b2..2355e4b61 100644 --- a/core_lib/src/miniz.cpp +++ b/core_lib/src/miniz.cpp @@ -31,7 +31,7 @@ typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1]; typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1]; #ifdef __cplusplus -//extern "C" { +extern "C" { #endif /* ------------------- zlib-style API's */ @@ -571,7 +571,7 @@ const char *mz_error(int err) #endif /*MINIZ_NO_ZLIB_APIS */ #ifdef __cplusplus -//} +} #endif /* diff --git a/core_lib/src/miniz.h b/core_lib/src/miniz.h index 48c7f03dc..86fac4c32 100644 --- a/core_lib/src/miniz.h +++ b/core_lib/src/miniz.h @@ -185,7 +185,7 @@ #endif #ifdef __cplusplus -//extern "C" { +extern "C" { #endif /* ------------------- zlib-style API Definitions. */ @@ -465,7 +465,7 @@ typedef void *const voidpc; #endif /* MINIZ_NO_ZLIB_APIS */ #ifdef __cplusplus -//} +} #endif #pragma once #include From 772d04d62f92b1b1f5e52bf1279d5027f32b9a10 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Wed, 13 Jun 2018 08:53:52 -0600 Subject: [PATCH 097/184] Lock zoom when using certain tools This prevents various strange errors that may arise from for example zooming out while drawing. --- core_lib/src/interface/scribblearea.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index 947218f52..1bc9f9f8b 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -372,6 +372,9 @@ void ScribbleArea::keyReleaseEvent(QKeyEvent *event) // mouse and tablet event handlers void ScribbleArea::wheelEvent(QWheelEvent* event) { + // Don't change view if tool is in use + if(mEditor->tools()->currentTool()->isActive()) return; + const QPoint pixels = event->pixelDelta(); const QPoint angle = event->angleDelta(); //qDebug() <<"angle"< Date: Thu, 14 Jun 2018 09:19:40 +1000 Subject: [PATCH 098/184] Fix a compiler error from a5cf2e2b7 --- core_lib/src/interface/scribblearea.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index 1bc9f9f8b..23b1b8a1a 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -373,7 +373,7 @@ void ScribbleArea::keyReleaseEvent(QKeyEvent *event) void ScribbleArea::wheelEvent(QWheelEvent* event) { // Don't change view if tool is in use - if(mEditor->tools()->currentTool()->isActive()) return; + if(mMouseInUse) return; const QPoint pixels = event->pixelDelta(); const QPoint angle = event->angleDelta(); From 52db352d2bc25e650448f5b0e9c92aba14e11a64 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Sat, 16 Jun 2018 11:45:26 +1000 Subject: [PATCH 099/184] Fix #994: Incorrectly assigned swatch name variables - the item users want to rename is not always at the current row. (if the user clicked on another item) --- app/src/colorpalettewidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/colorpalettewidget.cpp b/app/src/colorpalettewidget.cpp index a1497a705..93b9be3b4 100644 --- a/app/src/colorpalettewidget.cpp +++ b/app/src/colorpalettewidget.cpp @@ -240,7 +240,7 @@ void ColorPaletteWidget::changeColourName(QListWidgetItem* item) void ColorPaletteWidget::onItemChanged(QListWidgetItem* item) { - int index = ui->colorListWidget->currentRow(); + int index = ui->colorListWidget->row(item); QString newColorName = item->text(); editor()->object()->renameColour(index, newColorName); } From e8ec9625054be96241796f4596f59a0be59c3932 Mon Sep 17 00:00:00 2001 From: CandyFace Date: Sat, 16 Jun 2018 13:37:21 +0200 Subject: [PATCH 100/184] Add support for Gimp Palette (GPL) # Conflicts: # core_lib/src/structure/object.h --- app/src/filedialogex.cpp | 4 +- core_lib/src/structure/object.cpp | 134 +++++++++++++++++++++++++++--- core_lib/src/structure/object.h | 7 +- 3 files changed, 132 insertions(+), 13 deletions(-) diff --git a/app/src/filedialogex.cpp b/app/src/filedialogex.cpp index 4d481e7c1..db07f573b 100644 --- a/app/src/filedialogex.cpp +++ b/app/src/filedialogex.cpp @@ -164,7 +164,7 @@ QString FileDialog::openFileFilters( FileType fileType ) case FileType::IMAGE_SEQUENCE: return PENCIL_IMAGE_FILTER; case FileType::MOVIE: { Q_ASSERT(false); return PENCIL_MOVIE_EXT; } // currently not supported case FileType::SOUND: return tr( "Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3)" ); - case FileType::PALETTE: return tr( "Palette (*.xml)" ); + case FileType::PALETTE: return tr( "Pencil2D Palette (*.xml);; Gimp Palette (*.gpl)" ); default: Q_ASSERT( false ); } return ""; @@ -179,7 +179,7 @@ QString FileDialog::saveFileFilters( FileType fileType ) case FileType::IMAGE_SEQUENCE: return ""; case FileType::MOVIE: return tr( "MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng)" ); case FileType::SOUND: return ""; - case FileType::PALETTE: return tr( "Palette (*.xml)" ); + case FileType::PALETTE: return tr( "Pencil2D Palette (*.xml);; Gimp Palette (*.gpl)" ); default: Q_ASSERT( false ); } return ""; diff --git a/core_lib/src/structure/object.cpp b/core_lib/src/structure/object.cpp index b315cb6c5..1ff310af4 100644 --- a/core_lib/src/structure/object.cpp +++ b/core_lib/src/structure/object.cpp @@ -354,14 +354,28 @@ QString Object::savePalette(QString dataFolder) return ""; } -bool Object::exportPalette(QString filePath) +void Object::exportPaletteGPL(QFile& file) { - QFile file(filePath); - if (!file.open(QFile::WriteOnly | QFile::Text)) + + QString fileName = QFileInfo(file).baseName(); + QTextStream out(&file); + + out << "GIMP Palette" << "\n"; + out << "Name: " << fileName << "\n"; + out << "#" << "\n"; + + for (int i = 0; i < mPalette.size(); i++) { - qDebug("Error: cannot export palette"); - return false; + ColourRef ref = mPalette.at(i); + + QColor toRgb = ref.colour.toRgb(); + out << QString("%1 %2 %3").arg(toRgb.red()).arg(toRgb.green()).arg(toRgb.blue()); + out << " " << ref.name << "\n"; } +} + +void Object::exportPalettePencil(QFile& file) +{ QTextStream out(&file); QDomDocument doc("PencilPalette"); @@ -378,22 +392,105 @@ bool Object::exportPalette(QString filePath) tag.setAttribute("alpha", ref.colour.alpha()); root.appendChild(tag); } - int IndentSize = 2; doc.save(out, IndentSize); +} + +bool Object::exportPalette(QString filePath) +{ + QFile file(filePath); + if (!file.open(QFile::WriteOnly | QFile::Text)) + { + qDebug("Error: cannot export palette"); + return false; + } + + if (file.fileName().endsWith(".gpl", Qt::CaseInsensitive)) + { + exportPaletteGPL(file); + } else { + exportPalettePencil(file); + } file.close(); return true; } -bool Object::importPalette(QString filePath) +void Object::importPaletteGPL(QFile& file) { - QFile file(filePath); - if (!file.open(QFile::ReadOnly)) + + QTextStream in(&file); + QString line; + + bool hashFound = false; + bool colorFound = false; + while (in.readLineInto(&line)) { - return false; + quint8 red = 0; + quint8 green = 0; + quint8 blue = 0; + + int countInLine = 0; + QString name; + + if (!colorFound) + { + hashFound = (line == "#") ? true : false; + } + + if (!hashFound) + { + continue; + } + else if (!colorFound) + { + colorFound = true; + continue; + } + + for (QString snip : line.split(" ")) + { + if (countInLine == 0) // assume red + { + red = snip.toInt(); + } + else if (countInLine == 1) // assume green + { + green = snip.toInt(); + } + else if (countInLine == 2) // assume blue + { + blue = snip.toInt(); + } + else + { + + // assume last bit of line is a name + // gimp interprets as untitled + if (snip == "---") + { + name = "untitled"; + } + else + { + name += snip + " "; + } + } + countInLine++; + } + + // trim additional spaces + name = name.trimmed(); + + if (QColor(red, green, blue).isValid()) + { + mPalette.append(ColourRef(QColor(red,green,blue), name)); + } } +} +void Object::importPalettePencil(QFile& file) +{ QDomDocument doc; doc.setContent(&file); @@ -414,6 +511,23 @@ bool Object::importPalette(QString filePath) } tag = tag.nextSibling(); } +} + +bool Object::importPalette(QString filePath) +{ + QFile file(filePath); + + if (!file.open(QFile::ReadOnly)) + { + return false; + } + + if (file.fileName().endsWith(".gpl", Qt::CaseInsensitive)) + { + importPaletteGPL(file); + } else { + importPalettePencil(file); + } file.close(); return true; } diff --git a/core_lib/src/structure/object.h b/core_lib/src/structure/object.h index ac8bca0a9..7a34e0fe1 100644 --- a/core_lib/src/structure/object.h +++ b/core_lib/src/structure/object.h @@ -94,8 +94,13 @@ class Object : public QObject void renameColour( int i, QString text ); int getColourCount() { return mPalette.size(); } bool importPalette( QString filePath ); + void importPaletteGPL(QFile& file); + void importPalettePencil(QFile& file); + bool exportPalette( QString filePath ); - QString savePalette( QString dataFolder ); + void exportPaletteGPL(QFile& file); + void exportPalettePencil(QFile& file); + bool savePalette( QString filePath ); void loadDefaultPalette(); From 65d6f027a2c139859776d21564f59441e6a247bb Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Sat, 16 Jun 2018 22:31:41 +1000 Subject: [PATCH 101/184] Fix a compiler error --- core_lib/src/structure/object.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core_lib/src/structure/object.h b/core_lib/src/structure/object.h index 7a34e0fe1..3916dc035 100644 --- a/core_lib/src/structure/object.h +++ b/core_lib/src/structure/object.h @@ -100,7 +100,7 @@ class Object : public QObject bool exportPalette( QString filePath ); void exportPaletteGPL(QFile& file); void exportPalettePencil(QFile& file); - bool savePalette( QString filePath ); + QString savePalette( QString filePath ); void loadDefaultPalette(); From 89d7beae2862f9aa5fb52b9e852ea2cd58ad5c29 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Sat, 16 Jun 2018 20:49:18 +1000 Subject: [PATCH 102/184] Fix: vector layers shows only on the top-left quarter of canvas. --- app/src/colorpalettewidget.cpp | 6 +++--- core_lib/src/canvaspainter.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/colorpalettewidget.cpp b/app/src/colorpalettewidget.cpp index 93b9be3b4..90705b12e 100644 --- a/app/src/colorpalettewidget.cpp +++ b/app/src/colorpalettewidget.cpp @@ -267,9 +267,9 @@ void ColorPaletteWidget::palettePreferences() mSeparator->setSeparator(true); buttonStylesheet = "::menu-indicator{ image: none; }" - "QToolButton { border: 0px; }" - "QToolButton:pressed { border: 1px solid #ADADAD; border-radius: 2px; background-color: #D5D5D5; }" - "QToolButton:checked { border: 1px solid #ADADAD; border-radius: 2px; background-color: #D5D5D5; }"; + "QToolButton { border: 0px; }" + "QToolButton:pressed { border: 1px solid #ADADAD; border-radius: 2px; background-color: #D5D5D5; }" + "QToolButton:checked { border: 1px solid #ADADAD; border-radius: 2px; background-color: #D5D5D5; }"; // Add to UI diff --git a/core_lib/src/canvaspainter.cpp b/core_lib/src/canvaspainter.cpp index dd7ce883c..4131bf6e6 100644 --- a/core_lib/src/canvaspainter.cpp +++ b/core_lib/src/canvaspainter.cpp @@ -90,7 +90,7 @@ void CanvasPainter::paint(const Object* object, int layer, int frame, QRect rect paintBackground(); paintOnionSkin(painter); - painter.setClipRect(aligned); + //painter.setClipRect(aligned); // this aligned rect is valid only for bitmap images. paintCurrentFrame(painter); paintCameraBorder(painter); From 3cf4eb76bef569703e80f77b89ec829c96ea8480 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Sat, 16 Jun 2018 21:52:17 +1000 Subject: [PATCH 103/184] Format pentool.h/.cpp --- core_lib/src/tool/pentool.cpp | 168 +++++++++++++++++----------------- core_lib/src/tool/pentool.h | 18 ++-- 2 files changed, 93 insertions(+), 93 deletions(-) diff --git a/core_lib/src/tool/pentool.cpp b/core_lib/src/tool/pentool.cpp index 61298f698..7380c4ef2 100644 --- a/core_lib/src/tool/pentool.cpp +++ b/core_lib/src/tool/pentool.cpp @@ -29,7 +29,7 @@ GNU General Public License for more details. #include "blitrect.h" -PenTool::PenTool( QObject *parent ) : StrokeTool( parent ) +PenTool::PenTool(QObject* parent) : StrokeTool(parent) { } @@ -41,17 +41,17 @@ void PenTool::loadSettings() m_enabledProperties[ANTI_ALIASING] = true; m_enabledProperties[STABILIZATION] = true; - QSettings settings( PENCIL2D, PENCIL2D ); + QSettings settings(PENCIL2D, PENCIL2D); - properties.width = settings.value( "penWidth" ).toDouble(); - properties.pressure = settings.value( "penPressure" ).toBool(); + properties.width = settings.value("penWidth").toDouble(); + properties.pressure = settings.value("penPressure").toBool(); properties.invisibility = OFF; properties.preserveAlpha = OFF; - properties.useAA = settings.value( "brushAA").toBool(); + properties.useAA = settings.value("brushAA").toBool(); properties.stabilizerLevel = settings.value("stabilizerLevel").toInt(); // First run - if ( properties.width <= 0 ) + if (properties.width <= 0) { setWidth(1.5); setPressure(true); @@ -66,29 +66,29 @@ void PenTool::setWidth(const qreal width) properties.width = width; // Update settings - QSettings settings( PENCIL2D, PENCIL2D ); + QSettings settings(PENCIL2D, PENCIL2D); settings.setValue("penWidth", width); settings.sync(); } -void PenTool::setPressure( const bool pressure ) +void PenTool::setPressure(const bool pressure) { // Set current property properties.pressure = pressure; // Update settings - QSettings settings( PENCIL2D, PENCIL2D ); + QSettings settings(PENCIL2D, PENCIL2D); settings.setValue("penPressure", pressure); settings.sync(); } -void PenTool::setAA(const int AA ) +void PenTool::setAA(const int AA) { // Set current property properties.useAA = AA; // Update settings - QSettings settings( PENCIL2D, PENCIL2D ); + QSettings settings(PENCIL2D, PENCIL2D); settings.setValue("brushAA", AA); settings.sync(); } @@ -97,25 +97,25 @@ void PenTool::setStabilizerLevel(const int level) { properties.stabilizerLevel = level; - QSettings settings( PENCIL2D, PENCIL2D); + QSettings settings(PENCIL2D, PENCIL2D); settings.setValue("stabilizerLevel", level); settings.sync(); } QCursor PenTool::cursor() { - if ( mEditor->preference()->isOn( SETTING::TOOL_CURSOR ) ) + if (mEditor->preference()->isOn(SETTING::TOOL_CURSOR)) { - return QCursor( QPixmap( ":icons/pen.png" ), -5, 0 ); + return QCursor(QPixmap(":icons/pen.png"), -5, 0); } return Qt::CrossCursor; } -void PenTool::adjustPressureSensitiveProperties( qreal pressure, bool mouseDevice ) +void PenTool::adjustPressureSensitiveProperties(qreal pressure, bool mouseDevice) { mCurrentWidth = properties.width; - if ( properties.pressure && !mouseDevice ) + if (properties.pressure && !mouseDevice) { mCurrentPressure = pressure; } @@ -125,9 +125,9 @@ void PenTool::adjustPressureSensitiveProperties( qreal pressure, bool mouseDevic } } -void PenTool::mousePressEvent( QMouseEvent *event ) +void PenTool::mousePressEvent(QMouseEvent* event) { - if ( event->button() == Qt::LeftButton ) + if (event->button() == Qt::LeftButton) { mScribbleArea->setAllDirty(); } @@ -138,16 +138,16 @@ void PenTool::mousePressEvent( QMouseEvent *event ) startStroke(); } -void PenTool::mouseReleaseEvent( QMouseEvent *event ) +void PenTool::mouseReleaseEvent(QMouseEvent* event) { - if ( event->button() == Qt::LeftButton ) + if (event->button() == Qt::LeftButton) { mEditor->backup(typeName()); Layer* layer = mEditor->layers()->currentLayer(); - if ( mScribbleArea->isLayerPaintable() ) + if (mScribbleArea->isLayerPaintable()) { - qreal distance = QLineF( getCurrentPoint(), mMouseDownPoint ).length(); + qreal distance = QLineF(getCurrentPoint(), mMouseDownPoint).length(); if (distance < 1) { paintAt(mMouseDownPoint); @@ -158,36 +158,36 @@ void PenTool::mouseReleaseEvent( QMouseEvent *event ) } } - if ( layer->type() == Layer::BITMAP ) + if (layer->type() == Layer::BITMAP) paintBitmapStroke(); - else if (layer->type() == Layer::VECTOR ) - paintVectorStroke( layer ); + else if (layer->type() == Layer::VECTOR) + paintVectorStroke(layer); } endStroke(); } -void PenTool::mouseMoveEvent( QMouseEvent *event ) +void PenTool::mouseMoveEvent(QMouseEvent* event) { Layer* layer = mEditor->layers()->currentLayer(); - if ( layer->type() == Layer::BITMAP || layer->type() == Layer::VECTOR ) + if (layer->type() == Layer::BITMAP || layer->type() == Layer::VECTOR) { - if ( event->buttons() & Qt::LeftButton ) + if (event->buttons() & Qt::LeftButton) { drawStroke(); if (properties.stabilizerLevel != m_pStrokeManager->getStabilizerLevel()) { m_pStrokeManager->setStabilizerLevel(properties.stabilizerLevel); } - //qDebug() << "DrawStroke" << event->pos() ; + //qDebug() << "DrawStroke" << event->pos() ; } } } // draw a single paint dab at the given location -void PenTool::paintAt( QPointF point ) +void PenTool::paintAt(QPointF point) { qDebug() << "Made a single dab at " << point; Layer* layer = mEditor->layers()->currentLayer(); - if ( layer->type() == Layer::BITMAP ) + if (layer->type() == Layer::BITMAP) { mCurrentWidth = properties.width; if (properties.pressure == true) @@ -198,15 +198,15 @@ void PenTool::paintAt( QPointF point ) BlitRect rect; - rect.extend( point.toPoint() ); - mScribbleArea->drawPen( point, - brushWidth, - mEditor->color()->frontColor(), - properties.useAA); + rect.extend(point.toPoint()); + mScribbleArea->drawPen(point, + brushWidth, + mEditor->color()->frontColor(), + properties.useAA); - int rad = qRound( brushWidth ) / 2 + 2; + int rad = qRound(brushWidth) / 2 + 2; - mScribbleArea->refreshBitmap( rect, rad ); + mScribbleArea->refreshBitmap(rect, rad); } } @@ -217,11 +217,11 @@ void PenTool::drawStroke() Layer* layer = mEditor->layers()->currentLayer(); - if ( layer->type() == Layer::BITMAP ) + if (layer->type() == Layer::BITMAP) { - for ( int i = 0; i < p.size(); i++ ) + for (int i = 0; i < p.size(); i++) { - p[ i ] = mEditor->view()->mapScreenToCanvas( p[ i ] ); + p[i] = mEditor->view()->mapScreenToCanvas(p[i]); } mCurrentWidth = properties.width; @@ -233,61 +233,60 @@ void PenTool::drawStroke() // TODO: Make popup widget for less important properties, // Eg. stepsize should be a slider.. will have fixed (0.3) value for now. - qreal brushStep = ( 0.5 * brushWidth ); - brushStep = qMax( 1.0, brushStep ); + qreal brushStep = (0.5 * brushWidth); + brushStep = qMax(1.0, brushStep); BlitRect rect; QPointF a = mLastBrushPoint; QPointF b = getCurrentPoint(); - qreal distance = 4 * QLineF( b, a ).length(); - int steps = qRound( distance / brushStep ); + qreal distance = 4 * QLineF(b, a).length(); + int steps = qRound(distance / brushStep); - for ( int i = 0; i < steps; i++ ) + for (int i = 0; i < steps; i++) { - QPointF point = mLastBrushPoint + ( i + 1 ) * brushStep * ( getCurrentPoint() - mLastBrushPoint ) / distance; - rect.extend( point.toPoint() ); - mScribbleArea->drawPen( point, - brushWidth, - mEditor->color()->frontColor(), - properties.useAA ); - - if ( i == ( steps - 1 ) ) + QPointF point = mLastBrushPoint + (i + 1) * brushStep * (getCurrentPoint() - mLastBrushPoint) / distance; + rect.extend(point.toPoint()); + mScribbleArea->drawPen(point, + brushWidth, + mEditor->color()->frontColor(), + properties.useAA); + + if (i == (steps - 1)) { mLastBrushPoint = getCurrentPoint(); } } - int rad = qRound( brushWidth ) / 2 + 2; + int rad = qRound(brushWidth) / 2 + 2; - mScribbleArea->paintBitmapBufferRect( rect ); - mScribbleArea->refreshBitmap( rect, rad ); + mScribbleArea->paintBitmapBufferRect(rect); + mScribbleArea->refreshBitmap(rect, rad); } - else if ( layer->type() == Layer::VECTOR ) + else if (layer->type() == Layer::VECTOR) { qreal brushWidth = 0; brushWidth = properties.width; - if (properties.pressure == true) { + if (properties.pressure == true) + { brushWidth = properties.width * mCurrentPressure; } - int rad = qRound( ( brushWidth / 2 + 2 ) * mEditor->view()->scaling() ); + int rad = qRound((brushWidth / 2 + 2) * mEditor->view()->scaling()); - QPen pen( mEditor->color()->frontColor(), - brushWidth * mEditor->view()->scaling(), - Qt::SolidLine, - Qt::RoundCap, - Qt::RoundJoin ); + QPen pen(mEditor->color()->frontColor(), + brushWidth * mEditor->view()->scaling(), + Qt::SolidLine, + Qt::RoundCap, + Qt::RoundJoin); - if ( p.size() == 4 ) + if (p.size() == 4) { - QPainterPath path( p[ 0 ] ); - path.cubicTo( p[ 1 ], - p[ 2 ], - p[ 3 ] ); - mScribbleArea->drawPath( path, pen, Qt::NoBrush, QPainter::CompositionMode_Source ); - mScribbleArea->refreshVector( path.boundingRect().toRect(), rad ); + QPainterPath path(p[0]); + path.cubicTo(p[1], p[2], p[3]); + mScribbleArea->drawPath(path, pen, Qt::NoBrush, QPainter::CompositionMode_Source); + mScribbleArea->refreshVector(path.boundingRect().toRect(), rad); } } } @@ -305,25 +304,26 @@ void PenTool::paintVectorStroke(Layer* layer) mScribbleArea->clearBitmapBuffer(); qreal tol = mScribbleArea->getCurveSmoothing() / mEditor->view()->scaling(); - BezierCurve curve( mStrokePoints, mStrokePressures, tol ); - curve.setWidth( properties.width ); - curve.setFeather( properties.feather ); - curve.setFilled( false ); - curve.setInvisibility( properties.invisibility ); - curve.setVariableWidth( properties.pressure ); - curve.setColourNumber( mEditor->color()->frontColorNumber() ); + BezierCurve curve(mStrokePoints, mStrokePressures, tol); + curve.setWidth(properties.width); + curve.setFeather(properties.feather); + curve.setFilled(false); + curve.setInvisibility(properties.invisibility); + curve.setVariableWidth(properties.pressure); + curve.setColourNumber(mEditor->color()->frontColorNumber()); - auto pLayerVector = static_cast< LayerVector* >( layer ); - VectorImage* vectorImage = pLayerVector->getLastVectorImageAtFrame( mEditor->currentFrame(), 0 ); - vectorImage->addCurve( curve, mEditor->view()->scaling(), false ); + auto pLayerVector = static_cast(layer); + VectorImage* vectorImage = pLayerVector->getLastVectorImageAtFrame(mEditor->currentFrame(), 0); + vectorImage->addCurve(curve, mEditor->view()->scaling(), false); - if (vectorImage->isAnyCurveSelected() || mScribbleArea->somethingSelected) { + if (vectorImage->isAnyCurveSelected() || mScribbleArea->somethingSelected) + { mScribbleArea->deselectAll(); } vectorImage->setSelected(vectorImage->getLastCurveNumber(), true); mScribbleArea->somethingSelected = true; - mScribbleArea->setModified( mEditor->layers()->currentLayerIndex(), mEditor->currentFrame() ); + mScribbleArea->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame()); mScribbleArea->setAllDirty(); } diff --git a/core_lib/src/tool/pentool.h b/core_lib/src/tool/pentool.h index 459856cb6..aa62a3fa0 100644 --- a/core_lib/src/tool/pentool.h +++ b/core_lib/src/tool/pentool.h @@ -26,25 +26,25 @@ class PenTool : public StrokeTool { Q_OBJECT public: - PenTool( QObject *parent = 0 ); + PenTool(QObject *parent = 0); ToolType type() override { return PEN; } void loadSettings() override; QCursor cursor() override; - void mousePressEvent( QMouseEvent* ) override; - void mouseMoveEvent( QMouseEvent* ) override; - void mouseReleaseEvent( QMouseEvent* ) override; + void mousePressEvent(QMouseEvent*) override; + void mouseMoveEvent(QMouseEvent*) override; + void mouseReleaseEvent(QMouseEvent*) override; void drawStroke(); - void paintAt( QPointF point ); + void paintAt(QPointF point); void paintVectorStroke(Layer *layer); void paintBitmapStroke(); - void adjustPressureSensitiveProperties( qreal pressure, bool mouseDevice ) override; + void adjustPressureSensitiveProperties(qreal pressure, bool mouseDevice) override; - void setWidth( const qreal width ) override; - void setPressure( const bool pressure ) override; - void setAA( const int AA ) override; + void setWidth(const qreal width) override; + void setPressure(const bool pressure) override; + void setAA(const int AA) override; void setStabilizerLevel(const int level) override; private: From 6cfa012e1fdd8ac142a9b7ad977decaf83bd41ad Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Sun, 17 Jun 2018 16:15:21 +1000 Subject: [PATCH 104/184] Format documents --- core_lib/src/canvaspainter.cpp | 6 +- core_lib/src/managers/layermanager.cpp | 100 ++++++++++++------------- 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/core_lib/src/canvaspainter.cpp b/core_lib/src/canvaspainter.cpp index 4131bf6e6..88682cc8a 100644 --- a/core_lib/src/canvaspainter.cpp +++ b/core_lib/src/canvaspainter.cpp @@ -191,7 +191,7 @@ void CanvasPainter::paintBitmapFrame(QPainter& painter, LayerBitmap* bitmapLayer = static_cast(layer); #endif - qCDebug(mLog) << "Paint Onion skin bitmap, Frame = " << nFrame; + //qCDebug(mLog) << "Paint Onion skin bitmap, Frame = " << nFrame; BitmapImage* paintedImage = nullptr; if (useLastKeyFrame) { @@ -208,7 +208,7 @@ void CanvasPainter::paintBitmapFrame(QPainter& painter, } paintedImage->loadFile(); // Critical! force the BitmapImage to load the image - qCDebug(mLog) << "Paint Image Size:" << paintedImage->image()->size(); + //qCDebug(mLog) << "Paint Image Size:" << paintedImage->image()->size(); BitmapImage paintToImage; paintToImage.paste(paintedImage); @@ -271,7 +271,7 @@ void CanvasPainter::prescale(BitmapImage* bitmapImage) } void CanvasPainter::paintVectorFrame(QPainter& painter, - Layer* layer, + Layer* layer, int nFrame, bool colorize, bool useLastKeyFrame) diff --git a/core_lib/src/managers/layermanager.cpp b/core_lib/src/managers/layermanager.cpp index 4e15539ca..9bebe10da 100644 --- a/core_lib/src/managers/layermanager.cpp +++ b/core_lib/src/managers/layermanager.cpp @@ -48,8 +48,8 @@ Status LayerManager::load(Object* o) Status LayerManager::save(Object* o) { - o->data()->setCurrentLayer(editor()->currentLayerIndex()); - return Status::OK; + o->data()->setCurrentLayer(editor()->currentLayerIndex()); + return Status::OK; } Layer* LayerManager::getLastCameraLayer() @@ -59,7 +59,7 @@ Layer* LayerManager::getLastCameraLayer() { return layer; } - + // it's not a camera layer std::vector camLayers = object()->getLayersByType(); if (camLayers.size() > 0) @@ -74,13 +74,13 @@ Layer* LayerManager::currentLayer() return currentLayer(0); } -Layer* LayerManager::currentLayer( int incr ) +Layer* LayerManager::currentLayer(int incr) { - Q_ASSERT( object() != NULL ); + Q_ASSERT(object() != NULL); return object()->getLayer(editor()->currentLayerIndex() + incr); } -Layer* LayerManager::getLayer( int index ) +Layer* LayerManager::getLayer(int index) { Q_ASSERT(object() != NULL); return object()->getLayer(index); @@ -96,14 +96,14 @@ int LayerManager::currentLayerIndex() return editor()->currentLayerIndex(); } -void LayerManager::setCurrentLayer( int layerIndex ) +void LayerManager::setCurrentLayer(int layerIndex) { Q_ASSERT(layerIndex >= 0); Object* o = object(); if (layerIndex >= o->getLayerCount()) { - Q_ASSERT( false ); + Q_ASSERT(false); return; } @@ -113,9 +113,9 @@ void LayerManager::setCurrentLayer( int layerIndex ) Q_EMIT currentLayerChanged(layerIndex); } - if ( object() ) + if (object()) { - if ( object()->getLayer( layerIndex )->type() == Layer::CAMERA ) + if (object()->getLayer(layerIndex)->type() == Layer::CAMERA) { mLastCameraLayerIdx = layerIndex; } @@ -129,71 +129,71 @@ void LayerManager::setCurrentLayer(Layer* layer) void LayerManager::gotoNextLayer() { - if (editor()->currentLayerIndex() < object()->getLayerCount() - 1 ) + if (editor()->currentLayerIndex() < object()->getLayerCount() - 1) { editor()->setCurrentLayerIndex(editor()->currentLayerIndex() + 1); - Q_EMIT currentLayerChanged(editor()->currentLayerIndex()); + Q_EMIT currentLayerChanged(editor()->currentLayerIndex()); } } void LayerManager::gotoPreviouslayer() { - if (editor()->currentLayerIndex() > 0 ) + if (editor()->currentLayerIndex() > 0) { - editor()->setCurrentLayerIndex(editor()->currentLayerIndex() - 1); - Q_EMIT currentLayerChanged(editor()->currentLayerIndex()); + editor()->setCurrentLayerIndex(editor()->currentLayerIndex() - 1); + Q_EMIT currentLayerChanged(editor()->currentLayerIndex()); } } -LayerBitmap* LayerManager::createBitmapLayer( const QString& strLayerName ) +LayerBitmap* LayerManager::createBitmapLayer(const QString& strLayerName) { LayerBitmap* layer = object()->addNewBitmapLayer(); - layer->setName( strLayerName ); - - Q_EMIT layerCountChanged( count() ); - + layer->setName(strLayerName); + + Q_EMIT layerCountChanged(count()); + return layer; } -LayerVector* LayerManager::createVectorLayer( const QString& strLayerName ) +LayerVector* LayerManager::createVectorLayer(const QString& strLayerName) { LayerVector* layer = object()->addNewVectorLayer(); - layer->setName( strLayerName ); - - Q_EMIT layerCountChanged( count() ); - + layer->setName(strLayerName); + + Q_EMIT layerCountChanged(count()); + return layer; } -LayerCamera* LayerManager::createCameraLayer( const QString& strLayerName ) +LayerCamera* LayerManager::createCameraLayer(const QString& strLayerName) { LayerCamera* layer = object()->addNewCameraLayer(); - layer->setName( strLayerName ); - - Q_EMIT layerCountChanged( count() ); - + layer->setName(strLayerName); + + Q_EMIT layerCountChanged(count()); + return layer; } -LayerSound* LayerManager::createSoundLayer( const QString& strLayerName ) +LayerSound* LayerManager::createSoundLayer(const QString& strLayerName) { LayerSound* layer = object()->addNewSoundLayer(); - layer->setName( strLayerName ); - - Q_EMIT layerCountChanged( count() ); + layer->setName(strLayerName); + + Q_EMIT layerCountChanged(count()); return layer; } -int LayerManager::LastFrameAtFrame( int frameIndex ) +int LayerManager::LastFrameAtFrame(int frameIndex) { Object* o = object(); - for ( int i = frameIndex; i >= 0; i -= 1 ) + for (int i = frameIndex; i >= 0; i -= 1) { - for ( int layerIndex = 0; layerIndex < o->getLayerCount(); ++layerIndex ) + for (int layerIndex = 0; layerIndex < o->getLayerCount(); ++layerIndex) { - auto pLayer = o->getLayer( layerIndex ); - if ( pLayer->keyExists( i ) ) + auto pLayer = o->getLayer(layerIndex); + if (pLayer->keyExists(i)) { return i; } @@ -207,12 +207,12 @@ int LayerManager::firstKeyFrameIndex() int minPosition = INT_MAX; Object* o = object(); - for ( int i = 0; i < o->getLayerCount(); ++i ) + for (int i = 0; i < o->getLayerCount(); ++i) { - Layer* pLayer = o->getLayer( i ); + Layer* pLayer = o->getLayer(i); int position = pLayer->firstKeyFramePosition(); - if ( position < minPosition ) + if (position < minPosition) { minPosition = position; } @@ -224,12 +224,12 @@ int LayerManager::lastKeyFrameIndex() { int maxPosition = 0; - for ( int i = 0; i < object()->getLayerCount(); ++i ) + for (int i = 0; i < object()->getLayerCount(); ++i) { - Layer* pLayer = object()->getLayer( i ); + Layer* pLayer = object()->getLayer(i); int position = pLayer->getMaxKeyFramePosition(); - if ( position > maxPosition ) + if (position > maxPosition) { maxPosition = position; } @@ -248,20 +248,20 @@ Status LayerManager::deleteLayer(int index) if (layer->type() == Layer::CAMERA) { std::vector camLayers = object()->getLayersByType(); - if ( camLayers.size() == 1 ) + if (camLayers.size() == 1) return Status::ERROR_NEED_AT_LEAST_ONE_CAMERA_LAYER; } - object()->deleteLayer( layer ); + object()->deleteLayer(layer); // current layer is the last layer && we are deleting it if (index == object()->getLayerCount() && index == currentLayerIndex()) { - setCurrentLayer( currentLayerIndex() - 1 ); + setCurrentLayer(currentLayerIndex() - 1); } - Q_EMIT layerCountChanged( count() ); + Q_EMIT layerCountChanged(count()); return Status::OK; } @@ -289,7 +289,7 @@ int LayerManager::animationLength(bool includeSounds) int maxFrame = -1; Object* o = object(); - for ( int i = 0; i < o->getLayerCount(); i++ ) + for (int i = 0; i < o->getLayerCount(); i++) { if (o->getLayer(i)->type() == Layer::SOUND) { From 149f6c0b141cb356b88b27f2b776c5b805255023 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Sun, 17 Jun 2018 16:18:52 +1000 Subject: [PATCH 105/184] Fix #920: Bitmap layer doesn't refresh after deleting the layer --- app/src/mainwindow2.cpp | 1 + core_lib/src/managers/layermanager.cpp | 1 + core_lib/src/managers/layermanager.h | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index b79103d59..de2f64b57 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -1119,6 +1119,7 @@ void MainWindow2::makeConnections(Editor* editor, ScribbleArea* scribbleArea) connect(editor->tools(), &ToolManager::toolChanged, scribbleArea, &ScribbleArea::setCurrentTool); connect(editor->tools(), &ToolManager::toolPropertyChanged, scribbleArea, &ScribbleArea::updateToolCursor); connect(editor->layers(), &LayerManager::currentLayerChanged, scribbleArea, &ScribbleArea::updateAllFrames); + connect(editor->layers(), &LayerManager::layerDeleted, scribbleArea, &ScribbleArea::updateAllFrames); connect(editor, &Editor::currentFrameChanged, scribbleArea, &ScribbleArea::updateFrame); diff --git a/core_lib/src/managers/layermanager.cpp b/core_lib/src/managers/layermanager.cpp index 9bebe10da..a94130beb 100644 --- a/core_lib/src/managers/layermanager.cpp +++ b/core_lib/src/managers/layermanager.cpp @@ -261,6 +261,7 @@ Status LayerManager::deleteLayer(int index) setCurrentLayer(currentLayerIndex() - 1); } + Q_EMIT layerDeleted(index); Q_EMIT layerCountChanged(count()); return Status::OK; diff --git a/core_lib/src/managers/layermanager.h b/core_lib/src/managers/layermanager.h index 87f6cf82c..886818536 100644 --- a/core_lib/src/managers/layermanager.h +++ b/core_lib/src/managers/layermanager.h @@ -70,9 +70,10 @@ class LayerManager : public BaseManager void notifyAnimationLengthChanged(); Q_SIGNALS: - void currentLayerChanged(int n); + void currentLayerChanged(int index); void layerCountChanged(int count); void animationLengthChanged(int length); + void layerDeleted(int index); private: int getIndex(Layer*) const; From d27125d5b4916d901ae0d5ab3e1ef24aad3b79f8 Mon Sep 17 00:00:00 2001 From: CandyFace Date: Sun, 17 Jun 2018 21:10:50 +0200 Subject: [PATCH 106/184] Add range to export image sequence --- app/src/actioncommands.cpp | 11 ++- app/src/exportimagedialog.cpp | 32 +++++++++ app/src/exportimagedialog.h | 9 +++ app/ui/exportimageoptions.ui | 127 +++++++++++++++++++++++++++++++++- 4 files changed, 175 insertions(+), 4 deletions(-) diff --git a/app/src/actioncommands.cpp b/app/src/actioncommands.cpp index 4a697f704..2343a1891 100644 --- a/app/src/actioncommands.cpp +++ b/app/src/actioncommands.cpp @@ -266,6 +266,11 @@ Status ActionCommands::exportImageSequence() } dialog->setCamerasInfo(camerasInfo); + int lengthWithSounds = mEditor->layers()->animationLength(true); + int length = mEditor->layers()->animationLength(false); + + dialog->setDefaultRange(1, length, lengthWithSounds); + dialog->exec(); if (dialog->result() == QDialog::Rejected) @@ -277,8 +282,8 @@ Status ActionCommands::exportImageSequence() QSize exportSize = dialog->getExportSize(); QString exportFormat = dialog->getExportFormat(); bool useTranparency = dialog->getTransparency(); - - int totalLength = mEditor->layers()->animationLength(); + int startFrame = dialog->getStartFrame(); + int endFrame = dialog->getEndFrame(); QString sCameraLayerName = dialog->getCameraLayerName(); LayerCamera* cameraLayer = (LayerCamera*)mEditor->layers()->findLayerByName(sCameraLayerName, Layer::CAMERA); @@ -289,7 +294,7 @@ Status ActionCommands::exportImageSequence() progress.setWindowModality(Qt::WindowModal); progress.show(); - mEditor->object()->exportFrames(1, totalLength, + mEditor->object()->exportFrames(startFrame, endFrame, cameraLayer, exportSize, strFilePath, diff --git a/app/src/exportimagedialog.cpp b/app/src/exportimagedialog.cpp index 8fbb72c1d..47287dcd4 100644 --- a/app/src/exportimagedialog.cpp +++ b/app/src/exportimagedialog.cpp @@ -17,6 +17,7 @@ GNU General Public License for more details. #include "exportimagedialog.h" #include "ui_exportimageoptions.h" +#include "util.h" ExportImageDialog::ExportImageDialog(QWidget* parent, FileType eFileType) : ImportExportDialog(parent, ImportExportDialog::Export, eFileType), @@ -30,6 +31,7 @@ ExportImageDialog::ExportImageDialog(QWidget* parent, FileType eFileType) : else { setWindowTitle(tr("Export image")); + ui->frameRangeGroupBox->hide(); } connect(ui->formatComboBox, &QComboBox::currentTextChanged, this, &ExportImageDialog::formatChanged); @@ -57,6 +59,36 @@ void ExportImageDialog::setCamerasInfo(const std::vectorstartSpinBox ); + SignalBlocker b2( ui->endSpinBox ); + + ui->startSpinBox->setValue( startFrame ); + ui->endSpinBox->setValue( endFrame ); + + connect(ui->frameCheckBox, &QCheckBox::clicked, this, &ExportImageDialog::frameCheckboxClicked); +} + +int ExportImageDialog::getStartFrame() const +{ + return ui->startSpinBox->value(); +} + +int ExportImageDialog::getEndFrame() const +{ + return ui->endSpinBox->value(); +} + +void ExportImageDialog::frameCheckboxClicked(bool checked) +{ + int e = (checked) ? mEndFrameWithSounds : mEndFrame; + ui->endSpinBox->setValue(e); +} + void ExportImageDialog::setExportSize(QSize size) { ui->imgWidthSpinBox->setValue(size.width()); diff --git a/app/src/exportimagedialog.h b/app/src/exportimagedialog.h index 4a626bdb8..4c885baf5 100644 --- a/app/src/exportimagedialog.h +++ b/app/src/exportimagedialog.h @@ -33,6 +33,7 @@ class ExportImageDialog : public ImportExportDialog ~ExportImageDialog(); void setCamerasInfo(const std::vector>& camInfo); + void setDefaultRange( int startFrame, int endFrame, int endFrameWithSounds ); void setExportSize( QSize size ); QSize getExportSize() const; @@ -40,12 +41,20 @@ class ExportImageDialog : public ImportExportDialog QString getExportFormat() const; QString getCameraLayerName() const; + int getStartFrame() const; + int getEndFrame() const; + private slots: + void frameCheckboxClicked(bool checked); void formatChanged(const QString& format); void cameraComboChanged(int index); + private: Ui::ExportImageOptions* ui = nullptr; + + int mEndFrameWithSounds = 0; + int mEndFrame = 0; }; #endif // EXPORTIMAGEDIALOG_H diff --git a/app/ui/exportimageoptions.ui b/app/ui/exportimageoptions.ui index 73e6198b0..f6015893c 100644 --- a/app/ui/exportimageoptions.ui +++ b/app/ui/exportimageoptions.ui @@ -7,7 +7,7 @@ 0 0 380 - 259 + 470 @@ -105,6 +105,131 @@ + + + + Range + + + + 9 + + + 9 + + + 9 + + + 9 + + + 3 + + + + + 1 + + + 99999 + + + 1 + + + + + + + + 0 + 0 + + + + + 80 + 35 + + + + The last frame you want to include in the exported movie + + + End Frame + + + + + + + + 0 + 0 + + + + + 80 + 35 + + + + The first frame you want to include in the exported movie + + + Start Frame + + + + + + + + 0 + 0 + + + + + 50 + 35 + + + + + 0 + 0 + + + + <html><head/><body><p>End frame is set to last paintable keyframe (Useful when you only want to export to the last animated frame)</p></body></html> + + + + + + To the end of sound clips + + + + + + + 1 + + + 999999 + + + 10 + + + + + + From 96b36b2a7f35076251dfbd3d682bc482c99f342e Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 19 Jun 2018 10:14:51 +1000 Subject: [PATCH 107/184] Enable high dpi pixmap for mac os --- app/src/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main.cpp b/app/src/main.cpp index 1c5b12da1..3de339111 100644 --- a/app/src/main.cpp +++ b/app/src/main.cpp @@ -310,6 +310,9 @@ int main(int argc, char* argv[]) Q_INIT_RESOURCE(core_lib); QSettings settings(PENCIL2D, PENCIL2D); +#ifdef Q_OS_MACOS + QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); +#endif if (settings.value("EnableHighDpiScaling", "true").toBool()) { // Enable auto screen scaling on high dpi display, for example, a 4k monitor From 75e4f5a51f41a2cf0ccc7d4c0674ee82bd8d29fe Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Thu, 21 Jun 2018 16:29:50 -0600 Subject: [PATCH 108/184] Update view when camera resolution changes --- core_lib/src/interface/editor.cpp | 2 ++ core_lib/src/structure/layercamera.cpp | 2 +- core_lib/src/structure/layercamera.h | 3 +++ core_lib/src/structure/object.cpp | 2 ++ core_lib/src/structure/object.h | 3 +++ 5 files changed, 11 insertions(+), 1 deletion(-) diff --git a/core_lib/src/interface/editor.cpp b/core_lib/src/interface/editor.cpp index 4cac70766..28752aeb0 100644 --- a/core_lib/src/interface/editor.cpp +++ b/core_lib/src/interface/editor.cpp @@ -649,6 +649,8 @@ Status Editor::setObject(Object* newObject) updateObject(); + connect(newObject, &Object::layerViewChanged, mViewManager, &ViewManager::viewChanged); + emit objectLoaded(); return Status::OK; diff --git a/core_lib/src/structure/layercamera.cpp b/core_lib/src/structure/layercamera.cpp index 066ffde9d..6fdd13c22 100644 --- a/core_lib/src/structure/layercamera.cpp +++ b/core_lib/src/structure/layercamera.cpp @@ -245,7 +245,7 @@ void LayerCamera::editProperties() setName( dialog->getName() ); viewRect = QRect(-dialog->getWidth()/2, -dialog->getHeight()/2, dialog->getWidth(), dialog->getHeight()); - //setUpdated(); + emit resolutionChanged(); } } diff --git a/core_lib/src/structure/layercamera.h b/core_lib/src/structure/layercamera.h index 7d4d9db10..315dd478b 100644 --- a/core_lib/src/structure/layercamera.h +++ b/core_lib/src/structure/layercamera.h @@ -67,6 +67,9 @@ class LayerCamera : public Layer QRect getViewRect(); QSize getViewSize(); +signals: + void resolutionChanged(); + protected: Status saveKeyFrameFile(KeyFrame*, QString path) override; KeyFrame* createKeyFrame(int position, Object*) override; diff --git a/core_lib/src/structure/object.cpp b/core_lib/src/structure/object.cpp index 1ff310af4..c54d2e629 100644 --- a/core_lib/src/structure/object.cpp +++ b/core_lib/src/structure/object.cpp @@ -142,6 +142,8 @@ LayerCamera* Object::addNewCameraLayer() layerCamera->addNewKeyFrameAt(1); + connect(layerCamera, &LayerCamera::resolutionChanged, this, &Object::layerViewChanged); + return layerCamera; } diff --git a/core_lib/src/structure/object.h b/core_lib/src/structure/object.h index 3916dc035..a69bb0871 100644 --- a/core_lib/src/structure/object.h +++ b/core_lib/src/structure/object.h @@ -146,6 +146,9 @@ class Object : public QObject int totalKeyFrameCount(); +signals: + void layerViewChanged(); + private: int getMaxLayerID(); From c4729f1f52a23aa27836832bbd93b6782f09eb5c Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Thu, 21 Jun 2018 18:05:11 -0600 Subject: [PATCH 109/184] Fix layermanager test --- core_lib/src/interface/editor.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core_lib/src/interface/editor.cpp b/core_lib/src/interface/editor.cpp index 28752aeb0..b08e3e78c 100644 --- a/core_lib/src/interface/editor.cpp +++ b/core_lib/src/interface/editor.cpp @@ -649,7 +649,10 @@ Status Editor::setObject(Object* newObject) updateObject(); - connect(newObject, &Object::layerViewChanged, mViewManager, &ViewManager::viewChanged); + if (mViewManager) + { + connect(newObject, &Object::layerViewChanged, mViewManager, &ViewManager::viewChanged); + } emit objectLoaded(); From b260cb6d3fea2c512384d5932acf2857397d4c25 Mon Sep 17 00:00:00 2001 From: CandyFace Date: Mon, 25 Jun 2018 18:52:35 +0200 Subject: [PATCH 110/184] Add new selection cursor files and do initial implementation --- app/data/app.qrc | 5 +++ app/data/icons/new/arrow-diagonalleft.png | Bin 0 -> 714 bytes app/data/icons/new/arrow-diagonalright.png | Bin 0 -> 721 bytes app/data/icons/new/arrow-horizontal.png | Bin 0 -> 611 bytes app/data/icons/new/arrow-selectmove.png | Bin 0 -> 1070 bytes app/data/icons/new/arrow-vertical.png | Bin 0 -> 650 bytes core_lib/src/interface/scribblearea.h | 6 +-- core_lib/src/tool/basetool.cpp | 49 +++++++++++++++++++++ core_lib/src/tool/basetool.h | 2 + core_lib/src/util/movemode.h | 16 +++++++ 10 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 app/data/icons/new/arrow-diagonalleft.png create mode 100644 app/data/icons/new/arrow-diagonalright.png create mode 100644 app/data/icons/new/arrow-horizontal.png create mode 100644 app/data/icons/new/arrow-selectmove.png create mode 100644 app/data/icons/new/arrow-vertical.png create mode 100644 core_lib/src/util/movemode.h diff --git a/app/data/app.qrc b/app/data/app.qrc index 2ac121f46..78158697e 100644 --- a/app/data/app.qrc +++ b/app/data/app.qrc @@ -51,6 +51,11 @@ icons/new/svg/smudge_detailed.svg icons/new/svg/trash_detailed.svg icons/new/checkerboard_smaller + icons/new/arrow-diagonalleft.png + icons/new/arrow-diagonalright.png + icons/new/arrow-horizontal.png + icons/new/arrow-selectmove.png + icons/new/arrow-vertical.png icons/onion-blue.png diff --git a/app/data/icons/new/arrow-diagonalleft.png b/app/data/icons/new/arrow-diagonalleft.png new file mode 100644 index 0000000000000000000000000000000000000000..7044dd58309c1951fb9d84d78ea502f3bfe3d30e GIT binary patch literal 714 zcmV;*0yX`KP)drtSB3+`}IPub-? zkVRl(4)U zUn-f^fA6DS;)$harX{wCw_+1wlptQl8DW?Jy$r}4piBDGEh|do_x$8fvMjl}%qBT3 zmWY!eL#L=&sUDMPh#r%XB&YiSx39L*=g(L71fk;5abDY@Y7@RT9OvV}alQ_r>;cZx zh5Y4x=zkM^qoDcrpkWP8FA7?88_w3D<=)gR?MEsTcN+%097A0Mny#Q`KHsz7eU9!R zyeeOH2|K&cA?F(wz5$9=XZDK4i9`SZ010qNS#tmY3ljhU3ljkVnw%H_008buL_t(2 zk;Rg+ZG=D&MZXW+!_`1~PAI}e$iaogh|t<-iAgD75n9QKb6TK+)wV#e4IsmOCm=cT z2?EO#ea-0o`6CVR?&s;Ur0(Z{LiT5E<7XsxAljwIC~m}Isr%NNPsIme$=|Cw#76}0Dy5E0pRWE w=1fFp?>&t%R7#zTzM0%eHv1Qzg8!tx0ql^sWGw6i6#xJL07*qoM6N<$f)cYt8~^|S literal 0 HcmV?d00001 diff --git a/app/data/icons/new/arrow-diagonalright.png b/app/data/icons/new/arrow-diagonalright.png new file mode 100644 index 0000000000000000000000000000000000000000..08bd6ca1e15c9be8a3b26fb5abb234dc8af3e5f0 GIT binary patch literal 721 zcmV;?0xtcDP)drtSB3+`}IPub-? zkVRl(4)U zUn-f^fA6DS;)$harX{wCw_+1wlptQl8DW?Jy$r}4piBDGEh|do_x$8fvMjl}%qBT3 zmWY!eL#L=&sUDMPh#r%XB&YiSx39L*=g(L71fk;5abDY@Y7@RT9OvV}alQ_r>;cZx zh5Y4x=zkM^qoDcrpkWP8FA7?88_w3D<=)gR?MEsTcN+%097A0Mny#Q`KHsz7eU9!R zyeeOH2|K&cA?F(wz5$9=XZDK4i9`SZ010qNS#tmY3ljhU3ljkVnw%H_008w#L_t(2 zkC5afgzKy0jlZIgnKOf z$*V>>J>|XmlJDFL{Ogd+Nj{0lCL-HW=p-VW_nzZ8vS}J#!dEd^L|*&8zn$+kX28hUg4E}i) z$%kcGV2pv*8d;XTDWz_IRR%u$ipWOtkz{@d`m=lh19YmdrtSB3+`}IPub-? zkVRl(4)U zUn-f^fA6DS;)$harX{wCw_+1wlptQl8DW?Jy$r}4piBDGEh|do_x$8fvMjl}%qBT3 zmWY!eL#L=&sUDMPh#r%XB&YiSx39L*=g(L71fk;5abDY@Y7@RT9OvV}alQ_r>;cZx zh5Y4x=zkM^qoDcrpkWP8FA7?88_w3D<=)gR?MEsTcN+%097A0Mny#Q`KHsz7eU9!R zyeeOH2|K&cA?F(wz5$9=XZDK4i9`SZ010qNS#tmY3ljhU3ljkVnw%H_004(cL_t(2 zk?oMN4TLZd1UDe~hr|lCduW8ExW&x9FL%HP*o`++_fEsB0^PV3n$rk0Hzq@oKpG*)>`45 xd$m1;001bZz-n*TA>HIW;5GqpB!1xXLdi zxhgx^GDXSWj?1RP3TQxXYDuC(MQ%=Bu~mhw64+cTAR8pCucQE0Qj%?}6yY17;GAES zs$i;Ts%M~N$E9FXl#*r@k>g7FXt#Bv$C=6)S^`fSBQuTAW;zSx}OhpQivaGchT@w8U0PNgrg1KGYVVbM@iw z1#;j%PR#>)vk2%PDX-P9fWg$1>FgX(9OUk#;OXjYW@u?@}aP7M*JC+Swb={f}wesVGe) zRc`IZi;vfN&L{(0Sd+vU~gS)&yes`b9A^H_FiSN*BQIxON-Z;59WJXkXO z+k~u)$9D6lcYUk$pDLPPy*6s<`M=p;wFRA9S6MwY4845$(B(t-zHUkT*jLak#lMzg zKIiurMUD@xz4^s|UVRiXalh_0=6{?UOgXhT#>@OWnib>Eb^3Iny0GNd68YDvyc4hd znRA5iqZ!X1pNEc#ZJufpX$^rh+h3+mu!{^-+`oT<{pndxRvBfdT#Qt8n`2_TC~ZlV zOH#;}jvkiC)&J{%XSuYqbzhaXc~D_?_PgJTyKOb+O!oKr7}xWBQ{Uk;_49SU#3#;Q zVj_#>8?uGZtv?l2A+EP=!Ph|UmkXOx#J9UH{!qr%>zJ{R@p;h3^rf|aata$1<4bv~ ze_v329(&r}WJmh>vbZDDfhm)-z$3Dlfq`2Xgc%uT&5-~`k+!FcV~EDYrNO&%4;zTs zu!uc4#k`})cUoNQ6P9&MJ3Oa)U10J`K49GueYOwaR1Dywl4cg=rqW=uvjBT5IWxz3M05Y2If# z;2qUi{O;YH-OM{8vl$sK-k)@*g}v~|#>`o<9E=PCP7aq%tQn5auX^VZmo(GV^IPrt z4y%3fO6z@=M^(R{`TXY%Vb8km&o=Vu0h8{mVb~Lu{r%j|m6H-B(jE&ibuDVR_Uo*~ z=bcOiX2&!%pWch=7GT<>Gn*w-r=`J=E$9?K!}I@N=e)C&JCJziV@6drtSB3+`}IPub-? zkVRl(4)U zUn-f^fA6DS;)$harX{wCw_+1wlptQl8DW?Jy$r}4piBDGEh|do_x$8fvMjl}%qBT3 zmWY!eL#L=&sUDMPh#r%XB&YiSx39L*=g(L71fk;5abDY@Y7@RT9OvV}alQ_r>;cZx zh5Y4x=zkM^qoDcrpkWP8FA7?88_w3D<=)gR?MEsTcN+%097A0Mny#Q`KHsz7eU9!R zyeeOH2|K&cA?F(wz5$9=XZDK4i9`SZ010qNS#tmY3ljhU3ljkVnw%H_006E@L_t(2 zk)@Nd5riNVM3*bTLZAUVFf*bGE4U^sL_4qp3jkVi#^hask#dLLn_)_Z56?+GCQ^jEr9!9UFNEJ@1yP-O<%7-N@Gk|d>+6l3gwwzljM zVBdE#w{vgadw{K^DP^wWFY_gjGXw3><74GspI-Y^wlQXP&MnqjNs_fz&bh@Hv)0~T kHDTWlcsASF{PS0R04WcoLBF8VxBvhE07*qoM6N<$g8MKZ-~a#s literal 0 HcmV?d00001 diff --git a/core_lib/src/interface/scribblearea.h b/core_lib/src/interface/scribblearea.h index af9dff91f..3e229ac7d 100644 --- a/core_lib/src/interface/scribblearea.h +++ b/core_lib/src/interface/scribblearea.h @@ -30,6 +30,7 @@ GNU General Public License for more details. #include #include +#include "movemode.h" #include "log.h" #include "pencildef.h" #include "bitmapimage.h" @@ -85,9 +86,8 @@ class ScribbleArea : public QWidget bool usePressure() const { return mUsePressure; } bool makeInvisible() const { return mMakeInvisible; } - enum MoveMode { MIDDLE, TOPLEFT, TOPRIGHT, BOTTOMLEFT, BOTTOMRIGHT, ROTATION, SYMMETRY, NONE }; - MoveMode getMoveMode() const { return mMoveMode; } void setMoveMode( MoveMode moveMode ) { mMoveMode = moveMode; } + MoveMode getMoveMode() const { return mMoveMode; } QRectF getCameraRect(); QPointF getCentralPoint(); @@ -189,7 +189,7 @@ public slots: void drawCanvas( int frame, QRect rect ); void settingUpdated(SETTING setting); - MoveMode mMoveMode = MIDDLE; + MoveMode mMoveMode = MoveMode::NONE; ToolType mPrevTemporalToolType = ERASER; ToolType mPrevToolType = PEN; // previous tool (except temporal) diff --git a/core_lib/src/tool/basetool.cpp b/core_lib/src/tool/basetool.cpp index 6b051ef01..01c60ceb0 100644 --- a/core_lib/src/tool/basetool.cpp +++ b/core_lib/src/tool/basetool.cpp @@ -183,6 +183,55 @@ QPixmap BaseTool::canvasCursor(float width, float feather, bool useFeather, floa return cursorPixmap; } +QCursor BaseTool::selectMoveCursor(MoveMode mode, ToolType type) +{ + QPixmap cursorPixmap = QPixmap(24, 24); + if (!cursorPixmap.isNull()) + { + cursorPixmap.fill(QColor(255, 255, 255, 0)); + QPainter cursorPainter(&cursorPixmap); + cursorPainter.setRenderHint(QPainter::HighQualityAntialiasing); + + switch(mode) { + case MoveMode::MIDDLE: + { + if (type == SELECT) { + cursorPainter.drawImage(QPoint(6,6),QImage("://icons/new/arrow-selectmove.png")); + } else { + return Qt::ArrowCursor; + } + break; + } + case MoveMode::TOPLEFT: + case MoveMode::BOTTOMRIGHT: + { + cursorPainter.drawImage(QPoint(6,6),QImage("://icons/new/arrow-diagonalleft.png")); + break; + } + case MoveMode::TOPRIGHT: + case MoveMode::BOTTOMLEFT: + { + cursorPainter.drawImage(QPoint(6,6),QImage("://icons/new/arrow-diagonalright.png")); + break; + } + default: + if (type == SELECT) { + return Qt::CrossCursor; + } + else + { + return Qt::ArrowCursor; + } + break; + } + + + cursorPainter.end(); + } + return QCursor(cursorPixmap); + +} + /** * @brief precision circular cursor: used for drawing stroke size while adjusting * @return QPixmap diff --git a/core_lib/src/tool/basetool.h b/core_lib/src/tool/basetool.h index af6de240b..fbf0c62ab 100644 --- a/core_lib/src/tool/basetool.h +++ b/core_lib/src/tool/basetool.h @@ -24,6 +24,7 @@ GNU General Public License for more details. #include #include #include +#include "movemode.h" #include "pencildef.h" class Editor; @@ -95,6 +96,7 @@ class BaseTool : public QObject static bool isAdjusting; static QPixmap canvasCursor(float brushWidth, float brushFeather, bool useFeather, float scalingFac, int windowWidth); static QPixmap quickSizeCursor(float brushWidth, float brushFeather, float scalingFac); + static QCursor selectMoveCursor(MoveMode mode, ToolType type); virtual void setWidth(const qreal width); virtual void setFeather(const qreal feather); diff --git a/core_lib/src/util/movemode.h b/core_lib/src/util/movemode.h new file mode 100644 index 000000000..7b8332f1d --- /dev/null +++ b/core_lib/src/util/movemode.h @@ -0,0 +1,16 @@ +#ifndef MOVEMODE_H +#define MOVEMODE_H + + +enum class MoveMode { + MIDDLE, + TOPLEFT, + TOPRIGHT, + BOTTOMLEFT, + BOTTOMRIGHT, + ROTATION, + SYMMETRY, + NONE +}; + +#endif // MOVEMODE_H From 5a7a1d24941b36016bef769b45a7e311affa8c69 Mon Sep 17 00:00:00 2001 From: CandyFace Date: Mon, 25 Jun 2018 18:55:00 +0200 Subject: [PATCH 111/184] forgot file refactor --- core_lib/core_lib.pro | 1 + 1 file changed, 1 insertion(+) diff --git a/core_lib/core_lib.pro b/core_lib/core_lib.pro index 93c078674..331689e28 100644 --- a/core_lib/core_lib.pro +++ b/core_lib/core_lib.pro @@ -87,6 +87,7 @@ HEADERS += \ src/util/pencilsettings.h \ src/util/util.h \ src/util/log.h \ + src/util/movemode.h \ src/canvaspainter.h \ src/soundplayer.h \ src/movieexporter.h \ From eafd5e919567368d07d0b25e24e21059a85bc63b Mon Sep 17 00:00:00 2001 From: CandyFace Date: Mon, 25 Jun 2018 18:59:44 +0200 Subject: [PATCH 112/184] Add UI/UX to apply transformation --- app/src/toolbox.cpp | 32 +++++++++++ app/src/toolbox.h | 1 + core_lib/src/interface/timelinecells.cpp | 5 +- core_lib/src/managers/toolmanager.cpp | 8 ++- core_lib/src/managers/toolmanager.h | 1 + core_lib/src/tool/basetool.h | 4 +- core_lib/src/tool/movetool.cpp | 69 +++++++++++++++++++++--- core_lib/src/tool/movetool.h | 6 ++- 8 files changed, 112 insertions(+), 14 deletions(-) diff --git a/app/src/toolbox.cpp b/app/src/toolbox.cpp index 87f864843..c6202fc8f 100644 --- a/app/src/toolbox.cpp +++ b/app/src/toolbox.cpp @@ -166,6 +166,8 @@ void ToolBoxWidget::updateUI() void ToolBoxWidget::pencilOn() { + if (!leavingTool(ui->pencilButton)) { return; } + editor()->tools()->setCurrentTool(PENCIL); deselectAllTools(); @@ -174,6 +176,8 @@ void ToolBoxWidget::pencilOn() void ToolBoxWidget::eraserOn() { + if (!leavingTool(ui->eraserButton)) { return; } + editor()->tools()->setCurrentTool(ERASER); deselectAllTools(); @@ -182,6 +186,8 @@ void ToolBoxWidget::eraserOn() void ToolBoxWidget::selectOn() { + if (!leavingTool(ui->selectButton)) { return; } + editor()->tools()->setCurrentTool(SELECT); deselectAllTools(); @@ -190,6 +196,8 @@ void ToolBoxWidget::selectOn() void ToolBoxWidget::moveOn() { + if (!leavingTool(ui->moveButton)) { return; } + editor()->tools()->setCurrentTool(MOVE); deselectAllTools(); @@ -198,6 +206,8 @@ void ToolBoxWidget::moveOn() void ToolBoxWidget::penOn() { + if (!leavingTool(ui->penButton)) { return; } + editor()->tools()->setCurrentTool(PEN); deselectAllTools(); @@ -206,6 +216,8 @@ void ToolBoxWidget::penOn() void ToolBoxWidget::handOn() { + if (!leavingTool(ui->handButton)) { return; } + editor()->tools()->setCurrentTool( HAND ); deselectAllTools(); @@ -214,6 +226,8 @@ void ToolBoxWidget::handOn() void ToolBoxWidget::polylineOn() { + if (!leavingTool(ui->polylineButton)) { return; } + editor()->tools()->setCurrentTool(POLYLINE); deselectAllTools(); @@ -222,6 +236,8 @@ void ToolBoxWidget::polylineOn() void ToolBoxWidget::bucketOn() { + if (!leavingTool(ui->bucketButton)) { return; } + editor()->tools()->setCurrentTool(BUCKET); deselectAllTools(); @@ -230,6 +246,7 @@ void ToolBoxWidget::bucketOn() void ToolBoxWidget::eyedropperOn() { + if (!leavingTool(ui->eyedropperButton)) { return; } editor()->tools()->setCurrentTool(EYEDROPPER); deselectAllTools(); @@ -238,6 +255,8 @@ void ToolBoxWidget::eyedropperOn() void ToolBoxWidget::brushOn() { + if (!leavingTool(ui->brushButton)) { return; } + editor()->tools()->setCurrentTool( BRUSH ); deselectAllTools(); @@ -246,6 +265,7 @@ void ToolBoxWidget::brushOn() void ToolBoxWidget::smudgeOn() { + if (!leavingTool(ui->smudgeButton)) { return; } editor()->tools()->setCurrentTool(SMUDGE); deselectAllTools(); @@ -266,3 +286,15 @@ void ToolBoxWidget::deselectAllTools() ui->brushButton->setChecked(false); ui->smudgeButton->setChecked(false); } + +bool ToolBoxWidget::leavingTool(QToolButton* toolButton) +{ + if (!editor()->tools()->leavingThisTool()) + { + if (toolButton->isChecked()) { + toolButton->setChecked(false); + } + return false; + } + return true; +} diff --git a/app/src/toolbox.h b/app/src/toolbox.h index 52cc5f7b9..ea7adcd42 100644 --- a/app/src/toolbox.h +++ b/app/src/toolbox.h @@ -61,6 +61,7 @@ public slots: private: void deselectAllTools(); + bool leavingTool(QToolButton*); Ui::ToolBoxWidget* ui = nullptr; }; diff --git a/core_lib/src/interface/timelinecells.cpp b/core_lib/src/interface/timelinecells.cpp index e84929bf3..166d0d2cf 100644 --- a/core_lib/src/interface/timelinecells.cpp +++ b/core_lib/src/interface/timelinecells.cpp @@ -418,7 +418,6 @@ void TimeLineCells::resizeEvent(QResizeEvent* event) void TimeLineCells::mousePressEvent(QMouseEvent* event) { - if (primaryButton != Qt::NoButton) return; int frameNumber = getFrameNumber(event->pos().x()); int layerNumber = getLayerNumber(event->pos().y()); @@ -439,7 +438,9 @@ void TimeLineCells::mousePressEvent(QMouseEvent* event) primaryButton = event->button(); - mEditor->tools()->currentTool()->switchingLayers(); + bool switchLayer = mEditor->tools()->currentTool()->switchingLayer(); + if (!switchLayer) { return; } + switch (mType) { case TIMELINE_CELL_TYPE::Layers: diff --git a/core_lib/src/managers/toolmanager.cpp b/core_lib/src/managers/toolmanager.cpp index 2fdb9d7b4..92aca6853 100644 --- a/core_lib/src/managers/toolmanager.cpp +++ b/core_lib/src/managers/toolmanager.cpp @@ -90,12 +90,18 @@ void ToolManager::setCurrentTool(ToolType eToolType) { if (mCurrentTool != NULL) { - mCurrentTool->leavingThisTool(); + leavingThisTool(); } + mCurrentTool = getTool(eToolType); Q_EMIT toolChanged(eToolType); } +bool ToolManager::leavingThisTool() +{ + return mCurrentTool->leavingThisTool(); +} + void ToolManager::cleanupAllToolsData() { foreach(BaseTool* pTool, mToolSetHash.values()) diff --git a/core_lib/src/managers/toolmanager.h b/core_lib/src/managers/toolmanager.h index 9923e872c..cf2c5cbcb 100644 --- a/core_lib/src/managers/toolmanager.h +++ b/core_lib/src/managers/toolmanager.h @@ -40,6 +40,7 @@ class ToolManager : public BaseManager void setDefaultTool(); void setCurrentTool(ToolType eToolType); void cleanupAllToolsData(); + bool leavingThisTool(); void tabletSwitchToEraser(); void tabletRestorePrevTool(); diff --git a/core_lib/src/tool/basetool.h b/core_lib/src/tool/basetool.h index fbf0c62ab..68cef6dcb 100644 --- a/core_lib/src/tool/basetool.h +++ b/core_lib/src/tool/basetool.h @@ -111,8 +111,8 @@ class BaseTool : public QObject virtual void setTolerance(const int tolerance); virtual void setUseFillContour(const bool useFillContour); - virtual void leavingThisTool() {} - virtual void switchingLayers() {} + virtual bool leavingThisTool() { return true; } + virtual bool switchingLayer() { return true; } // default state should be true Properties properties; diff --git a/core_lib/src/tool/movetool.cpp b/core_lib/src/tool/movetool.cpp index aedf63e1e..8ea2931f7 100644 --- a/core_lib/src/tool/movetool.cpp +++ b/core_lib/src/tool/movetool.cpp @@ -18,6 +18,7 @@ GNU General Public License for more details. #include "movetool.h" #include +#include #include "editor.h" #include "toolmanager.h" @@ -400,17 +401,71 @@ void MoveTool::paintTransformedSelection() mScribbleArea->paintTransformedSelection(); } -void MoveTool::leavingThisTool() +bool MoveTool::leavingThisTool() { - // make sure correct transformation is applied - // before leaving - mScribbleArea->calculateSelectionTransformation(); - applyChanges(); + if (mScribbleArea->isTemporaryTool()) { return true; } + if (!transformHasBeenModified()) { return true; } + + int returnValue = QMessageBox::warning(nullptr, + tr("Transform", "Windows title of layer switch pop-up."), + tr("You are about to switch tool, do you want to apply the transformation?"), + QMessageBox::No | QMessageBox::Cancel | QMessageBox::Yes, + QMessageBox::Yes); + + if (returnValue == QMessageBox::Yes) + { + if (mCurrentLayer->type() == Layer::BITMAP) + { + applyChanges(); + } + applyAllChangesTo(mScribbleArea->mySelection); + + } + else if (returnValue == QMessageBox::No) + { + cancelChanges(); + } + else if (returnValue == QMessageBox::Cancel) { + return false; + } + return true; } +bool MoveTool::switchingLayer() +{ + if (!transformHasBeenModified()) + { + mScribbleArea->deselectAll(); + return true; + } + + int returnValue = showTransformWarning(); -void MoveTool::switchingLayers() + if (returnValue == QMessageBox::Yes) + { + + applyAllChangesTo(mScribbleArea->mySelection); + mScribbleArea->deselectAll(); + return true; + } + else if (returnValue == QMessageBox::No) + { + cancelChanges(); + return true; + } + else if (returnValue == QMessageBox::Cancel) { + return false; + } + return true; +} + +int MoveTool::showTransformWarning() { - applyChanges(); + int returnValue = QMessageBox::warning(nullptr, + tr("Layer switch", "Windows title of layer switch pop-up."), + tr("You are about to switch layer, do you want to apply the transformation?"), + QMessageBox::No | QMessageBox::Cancel | QMessageBox::Yes, + QMessageBox::Yes); + return returnValue; } void MoveTool::resetSelectionProperties() diff --git a/core_lib/src/tool/movetool.h b/core_lib/src/tool/movetool.h index ecc733bd4..5df021b55 100644 --- a/core_lib/src/tool/movetool.h +++ b/core_lib/src/tool/movetool.h @@ -19,6 +19,7 @@ GNU General Public License for more details. #define MOVETOOL_H #include "basetool.h" +#include "movemode.h" class Layer; @@ -36,14 +37,15 @@ class MoveTool : public BaseTool void mouseReleaseEvent(QMouseEvent *) override; void mouseMoveEvent(QMouseEvent *) override; - void leavingThisTool() override; - void switchingLayers() override; + bool leavingThisTool() override; + bool switchingLayer() override; private: void cancelChanges(); void applyChanges(); void resetSelectionProperties(); void paintTransformedSelection(); + int showTransformWarning(); /// @brief Selects which corner-point of the selection to move, if /// one is range of the last click. From cf2c6b29a9742441efaee9ff63da226efb12a576 Mon Sep 17 00:00:00 2001 From: CandyFace Date: Mon, 25 Jun 2018 19:18:35 +0200 Subject: [PATCH 113/184] Refactor and do bug fixing --- core_lib/src/interface/editor.cpp | 20 +- core_lib/src/interface/scribblearea.cpp | 419 ++++++++++++++++++------ core_lib/src/interface/scribblearea.h | 24 +- core_lib/src/tool/brushtool.cpp | 3 +- core_lib/src/tool/movetool.cpp | 383 +++++++++------------- core_lib/src/tool/movetool.h | 26 +- core_lib/src/tool/penciltool.cpp | 5 +- core_lib/src/tool/pentool.cpp | 3 +- core_lib/src/tool/selecttool.cpp | 206 +++++++----- core_lib/src/tool/selecttool.h | 19 +- 10 files changed, 660 insertions(+), 448 deletions(-) diff --git a/core_lib/src/interface/editor.cpp b/core_lib/src/interface/editor.cpp index 4cac70766..90a84cbc9 100644 --- a/core_lib/src/interface/editor.cpp +++ b/core_lib/src/interface/editor.cpp @@ -245,7 +245,7 @@ void Editor::backup(int backupLayer, int backupFrame, QString undoText) element->layer = backupLayer; element->frame = backupFrame; element->undoText = undoText; - element->somethingSelected = getScribbleArea()->somethingSelected; + element->somethingSelected = getScribbleArea()->isSomethingSelected(); element->mySelection = getScribbleArea()->mySelection; element->myTransformedSelection = getScribbleArea()->myTransformedSelection; element->myTempTransformedSelection = getScribbleArea()->myTempTransformedSelection; @@ -262,7 +262,7 @@ void Editor::backup(int backupLayer, int backupFrame, QString undoText) element->layer = backupLayer; element->frame = backupFrame; element->undoText = undoText; - element->somethingSelected = getScribbleArea()->somethingSelected; + element->somethingSelected = getScribbleArea()->isSomethingSelected(); element->mySelection = getScribbleArea()->mySelection; element->myTransformedSelection = getScribbleArea()->myTransformedSelection; element->myTempTransformedSelection = getScribbleArea()->myTempTransformedSelection; @@ -355,10 +355,7 @@ void Editor::restoreKey() void BackupBitmapElement::restore(Editor* editor) { Layer* layer = editor->object()->getLayer(this->layer); - editor->getScribbleArea()->somethingSelected = this->somethingSelected; - editor->getScribbleArea()->mySelection = this->mySelection; - editor->getScribbleArea()->myTransformedSelection = this->myTransformedSelection; - editor->getScribbleArea()->myTempTransformedSelection = this->myTempTransformedSelection; + editor->getScribbleArea()->setSelection(mySelection); editor->updateFrame(this->frame); editor->scrubTo(this->frame); @@ -383,10 +380,7 @@ void BackupBitmapElement::restore(Editor* editor) void BackupVectorElement::restore(Editor* editor) { Layer* layer = editor->object()->getLayer(this->layer); - editor->getScribbleArea()->somethingSelected = this->somethingSelected; - editor->getScribbleArea()->mySelection = this->mySelection; - editor->getScribbleArea()->myTransformedSelection = this->myTransformedSelection; - editor->getScribbleArea()->myTempTransformedSelection = this->myTempTransformedSelection; + editor->getScribbleArea()->setSelection(mySelection); editor->updateFrameAndVector(this->frame); editor->scrubTo(this->frame); @@ -519,7 +513,7 @@ void Editor::copy() { if (layer->type() == Layer::BITMAP) { - if (mScribbleArea->somethingSelected) + if (mScribbleArea->isSomethingSelected()) { g_clipboardBitmapImage = ((LayerBitmap*)layer)->getLastBitmapImageAtFrame(currentFrame(), 0)->copy(mScribbleArea->getSelection().toRect()); // copy part of the image } @@ -549,7 +543,7 @@ void Editor::paste() BitmapImage tobePasted = g_clipboardBitmapImage.copy(); qDebug() << "to be pasted --->" << tobePasted.image()->size(); - if (mScribbleArea->somethingSelected) + if (mScribbleArea->isSomethingSelected()) { QRectF selection = mScribbleArea->getSelection(); if (g_clipboardBitmapImage.width() <= selection.width() && g_clipboardBitmapImage.height() <= selection.height()) @@ -570,7 +564,7 @@ void Editor::paste() mScribbleArea->deselectAll(); VectorImage* vectorImage = ((LayerVector*)layer)->getLastVectorImageAtFrame(currentFrame(), 0); vectorImage->paste(g_clipboardVectorImage); // paste the clipboard - mScribbleArea->setSelection(vectorImage->getSelectionRect(), true); + mScribbleArea->setSelection(vectorImage->getSelectionRect()); } } mScribbleArea->updateCurrentFrame(); diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index 23b1b8a1a..e04b0f3d2 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -66,7 +66,7 @@ bool ScribbleArea::init() mQuickSizing = mPrefs->isOn(SETTING::QUICK_SIZING); mMakeInvisible = false; - somethingSelected = false; + mSomethingSelected = false; mIsSimplified = mPrefs->isOn(SETTING::OUTLINES); mMultiLayerOnionSkin = mPrefs->isOn(SETTING::MULTILAYER_ONION); @@ -254,7 +254,7 @@ void ScribbleArea::keyPressEvent(QKeyEvent *event) switch (event->key()) { case Qt::Key_Right: - if (somethingSelected) + if (mSomethingSelected) { myTempTransformedSelection.translate(1, 0); myTransformedSelection = myTempTransformedSelection; @@ -268,7 +268,7 @@ void ScribbleArea::keyPressEvent(QKeyEvent *event) } break; case Qt::Key_Left: - if (somethingSelected) + if (mSomethingSelected) { myTempTransformedSelection.translate(-1, 0); myTransformedSelection = myTempTransformedSelection; @@ -282,7 +282,7 @@ void ScribbleArea::keyPressEvent(QKeyEvent *event) } break; case Qt::Key_Up: - if (somethingSelected) + if (mSomethingSelected) { myTempTransformedSelection.translate(0, -1); myTransformedSelection = myTempTransformedSelection; @@ -296,7 +296,7 @@ void ScribbleArea::keyPressEvent(QKeyEvent *event) } break; case Qt::Key_Down: - if (somethingSelected) + if (mSomethingSelected) { myTempTransformedSelection.translate(0, 1); myTransformedSelection = myTempTransformedSelection; @@ -310,7 +310,7 @@ void ScribbleArea::keyPressEvent(QKeyEvent *event) } break; case Qt::Key_Return: - if (somethingSelected) + if (mSomethingSelected) { applyTransformedSelection(); paintTransformedSelection(); @@ -322,14 +322,14 @@ void ScribbleArea::keyPressEvent(QKeyEvent *event) } break; case Qt::Key_Escape: - if (somethingSelected) + if (mSomethingSelected) { deselectAll(); applyTransformedSelection(); } break; case Qt::Key_Backspace: - if (somethingSelected) + if (mSomethingSelected) { deleteSelection(); deselectAll(); @@ -697,7 +697,6 @@ void ScribbleArea::paintBitmapBuffer() targetImage->paste(mBufferImg, cm); } - //qCDebug( mLog ) << "Paste Rect" << mBufferImg->bounds(); QRect rect = mEditor->view()->mapCanvasToScreen(mBufferImg->bounds()).toRect(); drawCanvas(frameNumber, rect.adjusted(-1, -1, 1, 1)); @@ -1040,38 +1039,9 @@ void ScribbleArea::paintEvent(QPaintEvent* event) mCanvasPainter.renderGrid(painter); // paints the selection outline - if (somethingSelected && (myTempTransformedSelection.isValid() || mMoveMode == ROTATION)) // @revise + if (mSomethingSelected && !myTempTransformedSelection.isNull()) { - // outline of the transformed selection - painter.setWorldMatrixEnabled(false); - painter.setOpacity(1.0); - QPolygon tempRect = mEditor->view()->getView().mapToPolygon(myTempTransformedSelection.normalized().toRect()); - - Layer* layer = mEditor->layers()->currentLayer(); - if (layer != NULL) - { - if (layer->type() == Layer::BITMAP) - { - painter.setBrush(Qt::NoBrush); - painter.setPen(Qt::DashLine); - } - if (layer->type() == Layer::VECTOR) - { - painter.setBrush(QColor(0, 0, 0, 20)); - painter.setPen(Qt::gray); - } - painter.drawPolygon(tempRect); - - if (layer->type() != Layer::VECTOR || currentTool()->type() != SELECT) - { - painter.setPen(Qt::SolidLine); - painter.setBrush(QBrush(Qt::gray)); - painter.drawRect(tempRect.point(0).x() - 3, tempRect.point(0).y() - 3, 6, 6); - painter.drawRect(tempRect.point(1).x() - 3, tempRect.point(1).y() - 3, 6, 6); - painter.drawRect(tempRect.point(2).x() - 3, tempRect.point(2).y() - 3, 6, 6); - painter.drawRect(tempRect.point(3).x() - 3, tempRect.point(3).y() - 3, 6, 6); - } - } + paintSelectionVisuals(painter); } } @@ -1086,6 +1056,83 @@ void ScribbleArea::paintEvent(QPaintEvent* event) event->accept(); } +void ScribbleArea::paintSelectionVisuals(QPainter& painter) +{ + // outline of the transformed selection + painter.setWorldMatrixEnabled(false); + painter.setOpacity(1.0); + mCurrentTransformSelection = mEditor->view()->getView().mapToPolygon(myTempTransformedSelection.toAlignedRect()); + mLastTransformSelection = mEditor->view()->getView().mapToPolygon(myTransformedSelection.toAlignedRect()); + + Layer* layer = mEditor->layers()->currentLayer(); + if (layer != NULL) + { + if (layer->type() == Layer::BITMAP) + { + painter.setBrush(Qt::NoBrush); + + QPen pen = QPen(Qt::DashLine); + painter.setPen(pen); + + // Draw previous selection + painter.drawPolygon(mLastTransformSelection.toPolygon()); + + // Draw current selection + painter.drawPolygon(mCurrentTransformSelection.toPolygon()); + + } + if (layer->type() == Layer::VECTOR) + { + painter.setBrush(QColor(0, 0, 0, 20)); + painter.setPen(Qt::gray); + painter.drawPolygon(mCurrentTransformSelection); + } + + if (layer->type() != Layer::VECTOR || currentTool()->type() != SELECT) + { + painter.setPen(Qt::SolidLine); + painter.setBrush(QBrush(Qt::gray)); + int width = 6; + int radius = width/2; + + QRectF topLeftCorner = QRectF(mCurrentTransformSelection[0].x() - radius, + mCurrentTransformSelection[0].y() - radius, + width, width); + + QRectF topRightCorner = QRectF(mCurrentTransformSelection[1].x() - radius, + mCurrentTransformSelection[1].y() - radius, + width, width); + + QRectF bottomRightCorner = QRectF(mCurrentTransformSelection[2].x() - radius, + mCurrentTransformSelection[2].y() - radius, + width, width); + + QRectF bottomLeftCorner = QRectF(mCurrentTransformSelection[3].x() - radius, + mCurrentTransformSelection[3].y() - radius, + width, width); + + painter.drawRect(topLeftCorner.x(), + topLeftCorner.y(), + width, width); + + painter.drawRect(topRightCorner.x(), + topRightCorner.y(), + width, width); + + painter.drawRect(bottomRightCorner.x(), + bottomRightCorner.y(), + width, width); + + painter.drawRect(bottomLeftCorner.x(), + bottomLeftCorner.y(), + width, width); + + painter.setBrush(QColor(0, 255, 0, 50)); + painter.setPen(Qt::green); + } + } +} + void ScribbleArea::drawCanvas(int frame, QRect rect) { Object* object = mEditor->object(); @@ -1307,8 +1354,187 @@ void ScribbleArea::calculateSelectionRect() { VectorImage *vectorImage = ((LayerVector *)layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0); vectorImage->calculateSelectionRect(); - setSelection(vectorImage->getSelectionRect(), true); + setSelection(vectorImage->getSelectionRect()); + } +} + +bool ScribbleArea::isSomethingSelected() const +{ + return mSomethingSelected; +} + +void ScribbleArea::findMoveModeOfCornerInRange() +{ + const double marginInPixels = 15; + const double scale = mEditor->view()->getView().inverted().m11(); + const double scaledMargin = fabs(marginInPixels * scale); + + // MAYBE: if this is broken, use myTransformedSelection + QRectF transformRect = myTempTransformedSelection; + QPointF lastPoint = currentTool()->getLastPoint(); + + MoveMode mode; + if (QLineF(lastPoint, transformRect.topLeft()).length() < scaledMargin) + { + mode = MoveMode::TOPLEFT; + } + else if (QLineF(lastPoint, transformRect.topRight()).length() < scaledMargin) + { + mode = MoveMode::TOPRIGHT; + } + else if (QLineF(lastPoint, transformRect.bottomLeft()).length() < scaledMargin) + { + mode = MoveMode::BOTTOMLEFT; + + } + else if (QLineF(lastPoint, transformRect.bottomRight()).length() < scaledMargin) + { + mode = MoveMode::BOTTOMRIGHT; + } + else if (myTransformedSelection.translated(mOffset).contains(lastPoint)) + { + mode = MoveMode::MIDDLE; } + else { + mode = MoveMode::NONE; + } + mMoveMode = mode; +} + +MoveMode ScribbleArea::getMoveModeForSelectionAnchor() +{ + + const double marginInPixels = 15; + const double radius = marginInPixels/2; + const double scale = mEditor->view()->getView().inverted().m11(); + const double scaledMargin = fabs(marginInPixels * scale); + + if (mCurrentTransformSelection.isEmpty()) { return MoveMode::NONE; } + + QRectF topLeftCorner = mEditor->view()->mapScreenToCanvas(QRectF(mCurrentTransformSelection[0].x() - radius, + mCurrentTransformSelection[0].y() - radius, + marginInPixels, marginInPixels)); + + QRectF topRightCorner = mEditor->view()->mapScreenToCanvas(QRectF(mCurrentTransformSelection[1].x() - radius, + mCurrentTransformSelection[1].y() - radius, + marginInPixels, marginInPixels)); + + QRectF bottomRightCorner = mEditor->view()->mapScreenToCanvas(QRectF(mCurrentTransformSelection[2].x() - radius, + mCurrentTransformSelection[2].y() - radius, + marginInPixels, marginInPixels)); + + QRectF bottomLeftCorner = mEditor->view()->mapScreenToCanvas(QRectF(mCurrentTransformSelection[3].x() - radius, + mCurrentTransformSelection[3].y() - radius, + marginInPixels, marginInPixels)); + + QPointF currentPos = currentTool()->getCurrentPoint(); + + if (QLineF(currentPos, topLeftCorner.center()).length() < scaledMargin) + { + return MoveMode::TOPLEFT; + } + else if (QLineF(currentPos, topRightCorner.center()).length() < scaledMargin) + { + return MoveMode::TOPRIGHT; + } + else if (QLineF(currentPos, bottomLeftCorner.center()).length() < scaledMargin) + { + return MoveMode::BOTTOMLEFT; + + } + else if (QLineF(currentPos, bottomRightCorner.center()).length() < scaledMargin) + { + return MoveMode::BOTTOMRIGHT; + } + else if (myTempTransformedSelection.contains(currentPos)) + { + return MoveMode::MIDDLE; + } + + return MoveMode::NONE; +} + +QPointF ScribbleArea::whichAnchorPoint(QPointF anchorPoint) +{ + MoveMode mode = getMoveModeForSelectionAnchor(); + if (mode == MoveMode::TOPLEFT) + { + anchorPoint = mySelection.bottomRight(); + } + else if (mode == MoveMode::TOPRIGHT) + { + anchorPoint = mySelection.bottomLeft(); + } + else if (mode == MoveMode::BOTTOMLEFT) + { + anchorPoint = mySelection.topRight(); + } + else if (mode == MoveMode::BOTTOMRIGHT) + { + anchorPoint = mySelection.topLeft(); + } + return anchorPoint; +} + +void ScribbleArea::adjustSelection(float offsetX, float offsetY) +{ + QRectF& transformedSelection = myTransformedSelection; + + switch (mMoveMode) + { + case MoveMode::MIDDLE: + { + // if close enough to old selection, snap to origin. + if (QLineF(currentTool()->getLastPressPixel(), currentTool()->getCurrentPixel()).length() < 4) + { + myTempTransformedSelection = myTransformedSelection; + } + else + { + myTempTransformedSelection = + transformedSelection.translated(QPointF(offsetX, offsetY)); + } + break; + } + case MoveMode::TOPRIGHT: + { + myTempTransformedSelection = + transformedSelection.adjusted(0, offsetY, offsetX, 0); + + break; + } + case MoveMode::TOPLEFT: + { + myTempTransformedSelection = + transformedSelection.adjusted(offsetX, offsetY, 0, 0); + + break; + } + case MoveMode::BOTTOMLEFT: + { + myTempTransformedSelection = + transformedSelection.adjusted(offsetX, 0, 0, offsetY); + break; + } + case MoveMode::BOTTOMRIGHT: + { + myTempTransformedSelection = + transformedSelection.adjusted(0, 0, offsetX, offsetY); + break; + + } + case MoveMode::ROTATION: + { + myTempTransformedSelection = + transformedSelection; // @ necessary? + myRotatedAngle = currentTool()->getCurrentPixel().x() - + currentTool()->getLastPressPixel().x(); + break; + } + default: + break; + } + update(); } /** @@ -1323,46 +1549,34 @@ QVector ScribbleArea::calcSelectionCenterPoints() tempSelectionCenterX, tempSelectionCenterY; - tempSelectionCenterX = 0.5 * (myTempTransformedSelection.left() + - myTempTransformedSelection.right()); - tempSelectionCenterY = 0.5 * (myTempTransformedSelection.top() + - myTempTransformedSelection.bottom()); - selectionCenterX = 0.5 * (mySelection.left() + mySelection.right()); - selectionCenterY = 0.5 * (mySelection.top() + mySelection.bottom()); + tempSelectionCenterX = myTempTransformedSelection.center().x(); + tempSelectionCenterY = myTempTransformedSelection.center().y(); + selectionCenterX = mySelection.center().x(); + selectionCenterY = mySelection.center().y(); centerPoints.append(QPoint(tempSelectionCenterX, tempSelectionCenterY)); centerPoints.append(QPoint(selectionCenterX, selectionCenterY)); return centerPoints; } -void ScribbleArea::calculateSelectionTransformation() // Vector layer transform +void ScribbleArea::calculateSelectionTransformation() { float scaleX, scaleY; + QVector centerPoints = calcSelectionCenterPoints(); - if (mySelection.width() == 0) - { - scaleX = 1.0; - } - else - { - scaleX = myTempTransformedSelection.width() / mySelection.width(); - } + selectionTransformation.reset(); - if (mySelection.height() == 0) - { - scaleY = 1.0; - } - else - { - scaleY = myTempTransformedSelection.height() / mySelection.height(); - } + scaleX = myTempTransformedSelection.width() / mySelection.width(); - selectionTransformation.reset(); + scaleY = myTempTransformedSelection.height() / mySelection.height(); selectionTransformation.translate(centerPoints[0].x(), centerPoints[0].y()); selectionTransformation.rotate(myRotatedAngle); + selectionTransformation.scale(scaleX, scaleY); + selectionTransformation.translate(-centerPoints[1].x(), -centerPoints[1].y()); + } @@ -1374,11 +1588,11 @@ void ScribbleArea::paintTransformedSelection() return; } - if (somethingSelected) // there is something selected + if (mSomethingSelected) // there is something selected { if (layer->type() == Layer::BITMAP) { - mCanvasPainter.setTransformedSelection(mySelection.toRect(), selectionTransformation); + mCanvasPainter.setTransformedSelection(mySelection.toAlignedRect(), selectionTransformation); } else if (layer->type() == Layer::VECTOR) { @@ -1393,6 +1607,34 @@ void ScribbleArea::paintTransformedSelection() update(); } +void ScribbleArea::applyAllSelectionChangesTo(QRectF& selectionRect) +{ + // because we've applied some changes already, paint the transformation + // and make sure it's modified + paintTransformedSelection(); + + // we've painted the current selection but it has not been applied yet + // we make sure that the selection is correct + // by setting the temp (editing) selection + selectionRect = myTempTransformedSelection; + + // Calculate the new transformation based on the new selection + calculateSelectionTransformation(); + + // apply the transformation to make the selection "stick" to the image + // we only want to do this when we're absolutely sure the transformation + // is final, othewise we will dirty the image upon further editing + applyTransformedSelection(); + + // finally set the transformation again + // normalize if below zero + if (!myTempTransformedSelection.isValid()) + { + myTempTransformedSelection = myTempTransformedSelection.normalized(); + } + setSelection(myTempTransformedSelection); +} + void ScribbleArea::applyTransformedSelection() { mCanvasPainter.ignoreTransformedSelection(); @@ -1403,23 +1645,23 @@ void ScribbleArea::applyTransformedSelection() return; } - if (somethingSelected) // there is something selected + if (mSomethingSelected) // there is something selected { + if (mySelection.isEmpty()) { return; } + if (layer->type() == Layer::BITMAP) { - if (!mySelection.isEmpty()) - { BitmapImage* bitmapImage = dynamic_cast(layer)->getLastBitmapImageAtFrame(mEditor->currentFrame(), 0); BitmapImage transformedImage = bitmapImage->transformed(mySelection.toRect(), selectionTransformation, true); bitmapImage->clear(mySelection); bitmapImage->paste(&transformedImage, QPainter::CompositionMode_SourceOver); - } } else if (layer->type() == Layer::VECTOR) { VectorImage *vectorImage = ((LayerVector *)layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0); - vectorImage->applySelectionTransformation(); + vectorImage->applySelectionTransformation(); + } setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame()); @@ -1432,7 +1674,7 @@ void ScribbleArea::cancelTransformedSelection() { mCanvasPainter.ignoreTransformedSelection(); - if (somethingSelected) { + if (mSomethingSelected) { Layer* layer = mEditor->layers()->currentLayer(); if (layer == NULL) @@ -1446,7 +1688,7 @@ void ScribbleArea::cancelTransformedSelection() vectorImage->setSelectionTransformation(QTransform()); } - setSelection(mySelection, true); + setSelection(mySelection); selectionTransformation.reset(); @@ -1457,13 +1699,17 @@ void ScribbleArea::cancelTransformedSelection() } } -void ScribbleArea::setSelection(QRectF rect, bool trueOrFalse) +void ScribbleArea::setSelection(QRectF rect) { + Layer* layer = mEditor->layers()->currentLayer(); + if (layer->type() == Layer::BITMAP) { + rect = rect.toAlignedRect(); + } mySelection = rect; myTransformedSelection = rect; myTempTransformedSelection = rect; - somethingSelected = trueOrFalse; + mSomethingSelected = (mySelection.isNull() ? false : true); // Temporary disabled this as it breaks selection rotate key (ctrl) event. @@ -1480,18 +1726,12 @@ void ScribbleArea::manageSelectionOrigin(QPointF currentPoint, QPointF originPoi int mouseY = currentPoint.y(); QRectF selectRect; - if (currentTool()->type() == ToolType::SELECT) { - selectRect = mySelection; - } - else // MOVE - { - selectRect = myTempTransformedSelection; - } if (mouseX <= originPoint.x()) { selectRect.setLeft(mouseX); selectRect.setRight(originPoint.x()); + } else { @@ -1511,10 +1751,6 @@ void ScribbleArea::manageSelectionOrigin(QPointF currentPoint, QPointF originPoi } if (currentTool()->type() == ToolType::SELECT) { - mySelection = selectRect; - } - else // MOVE - { myTempTransformedSelection = selectRect; } @@ -1568,7 +1804,7 @@ void ScribbleArea::selectAll() // as the drawing area is not limited // BitmapImage *bitmapImage = ((LayerBitmap *)layer)->getLastBitmapImageAtFrame(mEditor->currentFrame(), 0); - setSelection(bitmapImage->bounds(), true); + setSelection(bitmapImage->bounds()); } @@ -1576,7 +1812,7 @@ void ScribbleArea::selectAll() { VectorImage *vectorImage = ((LayerVector *)layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0); vectorImage->selectAll(); - setSelection(vectorImage->getSelectionRect(), true); + setSelection(vectorImage->getSelectionRect()); } updateCurrentFrame(); } @@ -1606,8 +1842,7 @@ void ScribbleArea::deselectAll() { ((LayerVector *)layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0)->deselectAll(); } - somethingSelected = false; - isTransforming = false; + mSomethingSelected = false; mBufferImg->clear(); @@ -1701,7 +1936,7 @@ void ScribbleArea::setTemporaryTool(ToolType eToolMode) void ScribbleArea::deleteSelection() { - if (somethingSelected) // there is something selected + if (mSomethingSelected) // there is something selected { Layer* layer = mEditor->layers()->currentLayer(); if (layer == NULL) { return; } diff --git a/core_lib/src/interface/scribblearea.h b/core_lib/src/interface/scribblearea.h index 3e229ac7d..996f3f5f0 100644 --- a/core_lib/src/interface/scribblearea.h +++ b/core_lib/src/interface/scribblearea.h @@ -62,11 +62,14 @@ class ScribbleArea : public QWidget void setCore( Editor* pCore ) { mEditor = pCore; } void deleteSelection(); - void setSelection( QRectF rect, bool ); + void setSelection( QRectF rect ); + void adjustSelection(float offsetX, float offsetY); + void applyAllSelectionChangesTo(QRectF& modifiedRect); void displaySelectionProperties(); void resetSelectionProperties(); + + bool isSomethingSelected() const; QRectF getSelection() const { return mySelection; } - bool somethingSelected = false; QRectF mySelection, myTransformedSelection, myTempTransformedSelection; qreal myRotatedAngle = 0.0; QList mClosestCurves; @@ -88,6 +91,10 @@ class ScribbleArea : public QWidget void setMoveMode( MoveMode moveMode ) { mMoveMode = moveMode; } MoveMode getMoveMode() const { return mMoveMode; } + void findMoveModeOfCornerInRange(); + MoveMode getMoveModeForSelectionAnchor(); + + QPointF whichAnchorPoint(QPointF anchorPoint); QRectF getCameraRect(); QPointF getCentralPoint(); @@ -114,6 +121,7 @@ class ScribbleArea : public QWidget void floodFillError( int errorType ); bool isMouseInUse() const { return mMouseInUse; } + bool isTemporaryTool() const { return instantTool; } void manageSelectionOrigin(QPointF currentPoint, QPointF originPoint); @@ -132,6 +140,10 @@ public slots: void cancelTransformedSelection(); void setModified( int layerNumber, int frameNumber ); + inline bool transformHasBeenModified() { + return mySelection != myTempTransformedSelection; + } + void selectAll(); void deselectAll(); @@ -185,16 +197,18 @@ public slots: QPixmap mCursorImg; QPixmap mTransCursImg; + QPointF getTransformOffset() { return mOffset; } + private: void drawCanvas( int frame, QRect rect ); void settingUpdated(SETTING setting); + void paintSelectionVisuals(QPainter& painter); MoveMode mMoveMode = MoveMode::NONE; ToolType mPrevTemporalToolType = ERASER; ToolType mPrevToolType = PEN; // previous tool (except temporal) BitmapImage mBitmapSelection; // used to temporary store a transformed portion of a bitmap image - bool isTransforming = false; std::unique_ptr< StrokeManager > mStrokeManager; @@ -232,6 +246,7 @@ public slots: //instant tool (temporal eg. eraser) bool instantTool = false; //whether or not using temporal tool + bool mSomethingSelected = false; VectorSelection vectorSelection; QTransform selectionTransformation; @@ -248,6 +263,9 @@ public slots: QRectF mDebugRect; QLoggingCategory mLog; std::deque< clock_t > mDebugTimeQue; + + QPolygonF mCurrentTransformSelection; + QPolygonF mLastTransformSelection; }; #endif diff --git a/core_lib/src/tool/brushtool.cpp b/core_lib/src/tool/brushtool.cpp index f4b24cd74..3daf3bbd2 100644 --- a/core_lib/src/tool/brushtool.cpp +++ b/core_lib/src/tool/brushtool.cpp @@ -417,12 +417,11 @@ void BrushTool::paintVectorStroke() VectorImage* vectorImage = pLayerVector->getLastVectorImageAtFrame( mEditor->currentFrame(), 0 ); vectorImage->addCurve( curve, mEditor->view()->scaling(), false ); - if (vectorImage->isAnyCurveSelected() || mScribbleArea->somethingSelected) { + if (vectorImage->isAnyCurveSelected() || mScribbleArea->isSomethingSelected()) { mScribbleArea->deselectAll(); } vectorImage->setSelected(vectorImage->getLastCurveNumber(), true); - mScribbleArea->somethingSelected = true; mScribbleArea->setModified( mEditor->layers()->currentLayerIndex(), mEditor->currentFrame() ); mScribbleArea->setAllDirty(); diff --git a/core_lib/src/tool/movetool.cpp b/core_lib/src/tool/movetool.cpp index 8ea2931f7..b6dae72c6 100644 --- a/core_lib/src/tool/movetool.cpp +++ b/core_lib/src/tool/movetool.cpp @@ -50,316 +50,206 @@ void MoveTool::loadSettings() QCursor MoveTool::cursor() { - return Qt::ArrowCursor; + MoveMode mode = mScribbleArea->getMoveModeForSelectionAnchor(); + return mScribbleArea->currentTool()->selectMoveCursor(mode, type()); } void MoveTool::mousePressEvent(QMouseEvent* event) { - Layer* layer = mEditor->layers()->currentLayer(); - if (layer == NULL) { return; } + mCurrentLayer = mEditor->layers()->currentLayer(); + if (mCurrentLayer == NULL) { return; } + if (!mCurrentLayer->isPaintable()) { return; } + if (event->button() != Qt::LeftButton) { return; } + + beginInteraction(event); - if (event->button() == Qt::LeftButton) - { - pressOperation(event, layer); - } } void MoveTool::mouseReleaseEvent(QMouseEvent*) { - if (!mScribbleArea->somethingSelected) + if (!mScribbleArea->isSomethingSelected()) return; - // update selection position - mScribbleArea->myTransformedSelection = mScribbleArea->myTempTransformedSelection; - - // make sure transform is correct - mScribbleArea->calculateSelectionTransformation(); + updateTransformation(); - // paint and apply - paintTransformedSelection(); - applyChanges(); - - // set selection again to avoid scaling issues. - mScribbleArea->setSelection(mScribbleArea->myTransformedSelection, true); - resetSelectionProperties(); + mScribbleArea->updateToolCursor(); + mScribbleArea->updateCurrentFrame(); } void MoveTool::mouseMoveEvent(QMouseEvent* event) { - Layer* layer = mEditor->layers()->currentLayer(); - if (layer == NULL) { return; } - if (!layer->isPaintable()) { return; } + mCurrentLayer = mEditor->layers()->currentLayer(); + if (mCurrentLayer == NULL) { return; } + if (!mCurrentLayer->isPaintable()) { return; } if (event->buttons() & Qt::LeftButton) // the user is also pressing the mouse (dragging) { - if (mScribbleArea->somethingSelected) - { - QPointF offset = QPointF(mScribbleArea->mOffset.x(), - mScribbleArea->mOffset.y()); - - if (event->modifiers() == Qt::ShiftModifier) // maintain aspect ratio - { - offset = maintainAspectRatio(offset.x(), offset.y()); - } - - transformSelection(offset.x(), offset.y()); - - mScribbleArea->calculateSelectionTransformation(); - paintTransformedSelection(); - } - else // there is nothing selected - { - mScribbleArea->deselectAll(); - mScribbleArea->mMoveMode = ScribbleArea::NONE; - } + transformSelection(event); } else // the user is moving the mouse without pressing it { - if (layer->type() == Layer::VECTOR) + // update cursor to reflect selection corner interaction + mScribbleArea->updateToolCursor(); + + if (mCurrentLayer->type() == Layer::VECTOR) { storeClosestVectorCurve(); } - mScribbleArea->update(); } + mScribbleArea->updateCurrentFrame(); } -void MoveTool::pressOperation(QMouseEvent* event, Layer* layer) +void MoveTool::updateTransformation() { - if (layer->isPaintable()) - { - mScribbleArea->setMoveMode(ScribbleArea::MIDDLE); // was MIDDLE - - QRectF selectionRect = mScribbleArea->myTransformedSelection; - if (!selectionRect.isEmpty()) - { - // Hack to "carry over" the selected part of the drawing. - // Commented out for now, since it doesn't work right for - // vector layers. - -// bool onEmptyFrame = layer->getKeyFrameAt(mEditor->currentFrame()) == nullptr; -// bool preferCreateNewKey = mEditor->preference()->getInt(SETTING::DRAW_ON_EMPTY_FRAME_ACTION) == CREATE_NEW_KEY; -// bool preferDuplicate = mEditor->preference()->getInt(SETTING::DRAW_ON_EMPTY_FRAME_ACTION) == DUPLICATE_PREVIOUS_KEY; - -// if(onEmptyFrame) -// { -// if(preferCreateNewKey) -// { -// mEditor->copy(); -// mScribbleArea->deleteSelection(); -// } -// else if(preferDuplicate) -// { -// mEditor->copy(); -// } -// } - -// mScribbleArea->handleDrawingOnEmptyFrame(); - mEditor->backup(typeName()); - - // Hack to "carry over" the selected part of the drawing. -// if(onEmptyFrame) -// { -// if(preferCreateNewKey || preferDuplicate) -// { -// mEditor->paste(); -// } -// } - } - - if (mScribbleArea->somethingSelected) // there is an area selection - { - // Below will return true if a corner point was in range of the click. - bool cornerPointInRange = whichTransformationPoint(); + // update the transformed selection + mScribbleArea->myTransformedSelection = mScribbleArea->myTempTransformedSelection; - if (event->modifiers() != Qt::ShiftModifier && !selectionRect.contains(getCurrentPoint()) - && !cornerPointInRange) - mScribbleArea->deselectAll(); + // make sure transform is correct + mScribbleArea->calculateSelectionTransformation(); - // calculate new transformation in case click only - mScribbleArea->calculateSelectionTransformation(); + // paint the transformation + paintTransformedSelection(); - paintTransformedSelection(); - applyChanges(); +} - mScribbleArea->setSelection(mScribbleArea->myTransformedSelection, true); - resetSelectionProperties(); +void MoveTool::transformSelection(QMouseEvent* event) +{ + if (mScribbleArea->isSomethingSelected()) + { + QPointF offset; + if (mCurrentLayer->type() == Layer::VECTOR) { + offset = mScribbleArea->getTransformOffset(); } else { - anchorOriginPoint = getLastPoint(); + offset = QPointF(mScribbleArea->getTransformOffset().x(), + mScribbleArea->getTransformOffset().y()).toPoint(); } - if (mScribbleArea->getMoveMode() == ScribbleArea::MIDDLE) + // maintain aspect ratio + if (event->modifiers() == Qt::ShiftModifier) { - if (event->modifiers() == Qt::ControlModifier) // --- rotation - { - mScribbleArea->setMoveMode(ScribbleArea::ROTATION); - } - else if (event->modifiers() == Qt::AltModifier) // --- symmetry - { - mScribbleArea->setMoveMode(ScribbleArea::SYMMETRY); - } - - if (layer->type() == Layer::VECTOR) - { - actionOnVector(event, layer); - } - if (!(mScribbleArea->myTransformedSelection.isEmpty()) - && !(mScribbleArea->myTransformedSelection.contains(getLastPoint()))) // click is outside the transformed selection with the MOVE tool - { - applyChanges(); - } + offset = maintainAspectRatio(offset.x(), offset.y()); } + + mScribbleArea->adjustSelection(offset.x(),offset.y()); + + mScribbleArea->calculateSelectionTransformation(); + paintTransformedSelection(); + + } + else // there is nothing selected + { + mScribbleArea->setMoveMode(MoveMode::NONE); } } -void MoveTool::actionOnVector(QMouseEvent* event, Layer* layer) +void MoveTool::beginInteraction(QMouseEvent* event) { - VectorImage* vectorImage = ((LayerVector*)layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0); - if (mScribbleArea->mClosestCurves.size() > 0) // the user clicks near a curve + if (event->buttons() & Qt::LeftButton) { - if (!vectorImage->isSelected(mScribbleArea->mClosestCurves)) + setAnchorToLastPoint(); + } + + QRectF selectionRect = mScribbleArea->myTransformedSelection; + if (!selectionRect.isNull()) + { + mEditor->backup(typeName()); + } + + mScribbleArea->findMoveModeOfCornerInRange(); + + if (event->modifiers() != Qt::ShiftModifier) + { + if (shouldDeselect()) { - if (event->modifiers() != Qt::ShiftModifier) - { - applyChanges(); - } - vectorImage->setSelected(mScribbleArea->mClosestCurves, true); - mScribbleArea->setSelection(vectorImage->getSelectionRect(), true); - mScribbleArea->update(); + applyChanges(); + mScribbleArea->deselectAll(); } } - else + + + if (mScribbleArea->getMoveMode() == MoveMode::MIDDLE) { - int areaNumber = vectorImage->getLastAreaNumber(getLastPoint()); - if (areaNumber != -1) // the user clicks on an area + if (event->modifiers() == Qt::ControlModifier) // --- rotation { - if (!vectorImage->isAreaSelected(areaNumber)) - { - if (event->modifiers() != Qt::ShiftModifier) - { - applyChanges(); - } - vectorImage->setAreaSelected(areaNumber, true); - mScribbleArea->setSelection(QRectF(0, 0, 0, 0), true); - mScribbleArea->update(); - } + mScribbleArea->setMoveMode(MoveMode::ROTATION); } + + } + + if (mCurrentLayer->type() == Layer::VECTOR) + { + createVectorSelection(event); } } -bool MoveTool::whichTransformationPoint() +bool MoveTool::shouldDeselect() { - QRectF transformPoint = mScribbleArea->myTransformedSelection; + return (!mScribbleArea->myTransformedSelection.contains(getCurrentPoint()) + && mScribbleArea->getMoveMode() == MoveMode::NONE); +} - // Give the user a margin to select a corner point. - bool cornerInRange = false; - const double marginInPixels = 12; - const double scale = mEditor->view()->getView().inverted().m11(); - const double scaledMargin = fabs(marginInPixels * scale); +/** + * @brief MoveTool::createVectorSelection + * In vector the selection rectangle is based on the bounding box of the curves + * We can therefore create a selection just by clicking near/on a curve + */ +void MoveTool::createVectorSelection(QMouseEvent* event) +{ + VectorImage* vectorImage = static_cast(mCurrentLayer)-> + getLastVectorImageAtFrame(mEditor->currentFrame(), 0); - if (QLineF(getLastPoint(), transformPoint.topLeft()).length() < scaledMargin) - { - mScribbleArea->setMoveMode(ScribbleArea::TOPLEFT); - anchorOriginPoint = mScribbleArea->mySelection.bottomRight(); - cornerInRange = true; - } - if (QLineF(getLastPoint(), transformPoint.topRight()).length() < scaledMargin) - { - mScribbleArea->setMoveMode(ScribbleArea::TOPRIGHT); - anchorOriginPoint = mScribbleArea->mySelection.bottomLeft(); - cornerInRange = true; - } - if (QLineF(getLastPoint(), transformPoint.bottomLeft()).length() < scaledMargin) + if (mScribbleArea->mClosestCurves.size() > 0) // the user clicks near a curve { - mScribbleArea->setMoveMode(ScribbleArea::BOTTOMLEFT); - anchorOriginPoint = mScribbleArea->mySelection.topRight(); - cornerInRange = true; + setCurveSelected(vectorImage, event); } - if (QLineF(getLastPoint(), transformPoint.bottomRight()).length() < scaledMargin) + else if (vectorImage->getLastAreaNumber(getLastPoint()) > -1) { - mScribbleArea->setMoveMode(ScribbleArea::BOTTOMRIGHT); - anchorOriginPoint = mScribbleArea->mySelection.topLeft(); - cornerInRange = true; + setAreaSelected(vectorImage, event); } - return cornerInRange; + mScribbleArea->update(); } -void MoveTool::transformSelection(qreal offsetX, qreal offsetY) +void MoveTool::setCurveSelected(VectorImage* vectorImage, QMouseEvent* event) { - QRectF& transformedSelection = mScribbleArea->myTransformedSelection; - switch (mScribbleArea->mMoveMode) + if (!vectorImage->isSelected(mScribbleArea->mClosestCurves)) { - case ScribbleArea::MIDDLE: - if (QLineF(getLastPressPixel(), getCurrentPixel()).length() > 4) + if (event->modifiers() != Qt::ShiftModifier) { - mScribbleArea->myTempTransformedSelection = - transformedSelection.translated(QPointF(offsetX, offsetY)); + applyChanges(); } - break; - - case ScribbleArea::TOPRIGHT: - { - mScribbleArea->myTempTransformedSelection = - transformedSelection.adjusted(0, offsetY, offsetX, 0); - - mScribbleArea->manageSelectionOrigin(QPointF(transformedSelection.topRight().x()+offsetX, - transformedSelection.topRight().y()+offsetY), anchorOriginPoint); - break; + vectorImage->setSelected(mScribbleArea->mClosestCurves, true); + mScribbleArea->setSelection(vectorImage->getSelectionRect()); } - case ScribbleArea::TOPLEFT: - { - mScribbleArea->myTempTransformedSelection = - transformedSelection.adjusted(offsetX, offsetY, 0, 0); - - mScribbleArea->manageSelectionOrigin(QPointF(transformedSelection.x()+offsetX, - transformedSelection.y()+offsetY), anchorOriginPoint); - break; - } - case ScribbleArea::BOTTOMLEFT: - { - mScribbleArea->myTempTransformedSelection = - transformedSelection.adjusted(offsetX, 0, 0, offsetY); - - mScribbleArea->manageSelectionOrigin(QPointF(transformedSelection.bottomLeft().x()+offsetX, - transformedSelection.bottomLeft().y()+offsetY), anchorOriginPoint); - break; - } - case ScribbleArea::BOTTOMRIGHT: - { - mScribbleArea->myTempTransformedSelection = - transformedSelection.adjusted(0, 0, offsetX, offsetY); - - mScribbleArea->manageSelectionOrigin(QPointF(transformedSelection.bottomRight().x()+offsetX, - transformedSelection.bottomRight().y()+offsetY), anchorOriginPoint); - break; +} - } - case ScribbleArea::ROTATION: +void MoveTool::setAreaSelected(VectorImage* vectorImage, QMouseEvent* event) +{ + int areaNumber = vectorImage->getLastAreaNumber(getLastPoint()); + if (!vectorImage->isAreaSelected(areaNumber)) { - mScribbleArea->myTempTransformedSelection = - transformedSelection; // @ necessary? - mScribbleArea->myRotatedAngle = getCurrentPixel().x() - getLastPressPixel().x(); - break; - } - default: - break; + if (event->modifiers() != Qt::ShiftModifier) + { + applyChanges(); + } + vectorImage->setAreaSelected(areaNumber, true); + mScribbleArea->setSelection(vectorImage->getSelectionRect()); } - mScribbleArea->update(); } QPointF MoveTool::maintainAspectRatio(qreal offsetX, qreal offsetY) { - qreal factor = mScribbleArea->mySelection.width() / mScribbleArea->mySelection.height(); + qreal factor = mScribbleArea->myTransformedSelection.width() / mScribbleArea->myTransformedSelection.height(); - if (mScribbleArea->mMoveMode == ScribbleArea::TOPLEFT || mScribbleArea->mMoveMode == ScribbleArea::BOTTOMRIGHT) + if (mScribbleArea->mMoveMode == MoveMode::TOPLEFT || mScribbleArea->mMoveMode == MoveMode::BOTTOMRIGHT) { offsetY = offsetX / factor; } - else if (mScribbleArea->mMoveMode == ScribbleArea::TOPRIGHT || mScribbleArea->mMoveMode == ScribbleArea::BOTTOMLEFT) + else if (mScribbleArea->mMoveMode == MoveMode::TOPRIGHT || mScribbleArea->mMoveMode == MoveMode::BOTTOMLEFT) { offsetY = -(offsetX / factor); } - else if (mScribbleArea->mMoveMode == ScribbleArea::MIDDLE) + else if (mScribbleArea->mMoveMode == MoveMode::MIDDLE) { qreal absX = offsetX; if (absX < 0) { absX = -absX; } @@ -379,16 +269,32 @@ QPointF MoveTool::maintainAspectRatio(qreal offsetX, qreal offsetY) */ void MoveTool::storeClosestVectorCurve() { - Layer* layer = mEditor->layers()->currentLayer(); - auto layerVector = static_cast(layer); + auto layerVector = static_cast(mCurrentLayer); VectorImage* pVecImg = layerVector->getLastVectorImageAtFrame(mEditor->currentFrame(), 0); mScribbleArea->mClosestCurves = pVecImg->getCurvesCloseTo(getCurrentPoint(), mScribbleArea->selectionTolerance / mEditor->view()->scaling()); } +void MoveTool::whichAnchorPoint() +{ + anchorOriginPoint = mScribbleArea->whichAnchorPoint(anchorOriginPoint); +} + +void MoveTool::setAnchorToLastPoint() +{ + anchorOriginPoint = getLastPoint(); +} + void MoveTool::cancelChanges() { mScribbleArea->cancelTransformedSelection(); + mScribbleArea->resetSelectionProperties(); + mScribbleArea->deselectAll(); +} + +void MoveTool::applyAllChangesTo(QRectF& modifiedRect) +{ + mScribbleArea->applyAllSelectionChangesTo(modifiedRect); } void MoveTool::applyChanges() @@ -416,9 +322,8 @@ bool MoveTool::leavingThisTool() { if (mCurrentLayer->type() == Layer::BITMAP) { - applyChanges(); + applyAllChangesTo(mScribbleArea->myTransformedSelection); } - applyAllChangesTo(mScribbleArea->mySelection); } else if (returnValue == QMessageBox::No) @@ -430,6 +335,12 @@ bool MoveTool::leavingThisTool() } return true; } + +bool MoveTool::transformHasBeenModified() +{ + return mScribbleArea->transformHasBeenModified(); +} + bool MoveTool::switchingLayer() { if (!transformHasBeenModified()) @@ -443,7 +354,11 @@ bool MoveTool::switchingLayer() if (returnValue == QMessageBox::Yes) { - applyAllChangesTo(mScribbleArea->mySelection); + if (mCurrentLayer->type() == Layer::BITMAP) + { + applyAllChangesTo(mScribbleArea->myTransformedSelection); + } + mScribbleArea->deselectAll(); return true; } diff --git a/core_lib/src/tool/movetool.h b/core_lib/src/tool/movetool.h index 5df021b55..b00ed6350 100644 --- a/core_lib/src/tool/movetool.h +++ b/core_lib/src/tool/movetool.h @@ -22,6 +22,7 @@ GNU General Public License for more details. #include "movemode.h" class Layer; +class VectorImage; class MoveTool : public BaseTool @@ -43,21 +44,32 @@ class MoveTool : public BaseTool private: void cancelChanges(); void applyChanges(); + void applyAllChangesTo(QRectF& modifiedRect); void resetSelectionProperties(); void paintTransformedSelection(); + void whichAnchorPoint(); + void setAnchorToLastPoint(); + void updateTransformation(); + int showTransformWarning(); - /// @brief Selects which corner-point of the selection to move, if - /// one is range of the last click. - /// @return true if a corner point was selected, false otherwise. - bool whichTransformationPoint(); - void transformSelection(qreal offsetX, qreal offsetY); - void pressOperation(QMouseEvent* event, Layer *layer); - void actionOnVector(QMouseEvent *event, Layer *layer); + void beginInteraction(QMouseEvent* event); + void createVectorSelection(QMouseEvent* event); + void transformSelection(QMouseEvent* event); + + void setCurveSelected(VectorImage* vectorImage, QMouseEvent* event); + void setAreaSelected(VectorImage* vectorImage, QMouseEvent* event); + + bool transformHasBeenModified(); + bool shouldDeselect(); + void storeClosestVectorCurve(); QPointF maintainAspectRatio(qreal offsetX, qreal offsetY); QPointF anchorOriginPoint; + + Layer* mCurrentLayer = nullptr; + }; #endif diff --git a/core_lib/src/tool/penciltool.cpp b/core_lib/src/tool/penciltool.cpp index d8a3ce4b3..3b25e513b 100644 --- a/core_lib/src/tool/penciltool.cpp +++ b/core_lib/src/tool/penciltool.cpp @@ -369,7 +369,7 @@ void PencilTool::paintVectorStroke(Layer* layer) mEditor->color()->frontColorNumber()); } - if (vectorImage->isAnyCurveSelected() || mScribbleArea->somethingSelected) + if (vectorImage->isAnyCurveSelected() || mScribbleArea->isSomethingSelected()) { mScribbleArea->deselectAll(); } @@ -377,8 +377,7 @@ void PencilTool::paintVectorStroke(Layer* layer) // select last/newest curve vectorImage->setSelected(vectorImage->getLastCurveNumber(), true); - // TODO: selection doesn't apply on enter or escape - mScribbleArea->somethingSelected = true; + // TODO: selection doesn't apply on enter mScribbleArea->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame()); mScribbleArea->setAllDirty(); diff --git a/core_lib/src/tool/pentool.cpp b/core_lib/src/tool/pentool.cpp index 7380c4ef2..fd6929583 100644 --- a/core_lib/src/tool/pentool.cpp +++ b/core_lib/src/tool/pentool.cpp @@ -316,13 +316,12 @@ void PenTool::paintVectorStroke(Layer* layer) VectorImage* vectorImage = pLayerVector->getLastVectorImageAtFrame(mEditor->currentFrame(), 0); vectorImage->addCurve(curve, mEditor->view()->scaling(), false); - if (vectorImage->isAnyCurveSelected() || mScribbleArea->somethingSelected) + if (vectorImage->isAnyCurveSelected() || mScribbleArea->isSomethingSelected()) { mScribbleArea->deselectAll(); } vectorImage->setSelected(vectorImage->getLastCurveNumber(), true); - mScribbleArea->somethingSelected = true; mScribbleArea->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame()); mScribbleArea->setAllDirty(); diff --git a/core_lib/src/tool/selecttool.cpp b/core_lib/src/tool/selecttool.cpp index 904f7d35b..e02ce2aea 100644 --- a/core_lib/src/tool/selecttool.cpp +++ b/core_lib/src/tool/selecttool.cpp @@ -36,133 +36,159 @@ void SelectTool::loadSettings() properties.feather = -1; properties.stabilizerLevel = -1; properties.useAA = -1; + } QCursor SelectTool::cursor() { - return Qt::CrossCursor; + MoveMode mode = mScribbleArea->getMoveModeForSelectionAnchor(); + return mScribbleArea->currentTool()->selectMoveCursor(mode, type()); } void SelectTool::mousePressEvent(QMouseEvent* event) { - Layer* layer = mEditor->layers()->currentLayer(); - if (layer == NULL) return; + mCurrentLayer = mEditor->layers()->currentLayer(); + if (mCurrentLayer == NULL) return; + if (!mCurrentLayer->isPaintable()) { return; } + if (event->button() != Qt::LeftButton) { return; } + + beginSelection(); +} + +void SelectTool::beginSelection() +{ mScribbleArea->myRotatedAngle = 0; - if (event->button() == Qt::LeftButton) + // Store original click position for help with selection rectangle. + mAnchorOriginPoint = getLastPoint(); + + mScribbleArea->calculateSelectionTransformation(); + + // paint and apply the transformation + mScribbleArea->paintTransformedSelection(); + mScribbleArea->applyTransformedSelection(); + + if (mScribbleArea->isSomethingSelected())// there is something selected { + if (mCurrentLayer->type() == Layer::VECTOR) + { + static_cast(mCurrentLayer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0)->deselectAll(); + } - anchorOriginPoint = getLastPoint(); // Store original click position for help with selection rectangle. + mScribbleArea->findMoveModeOfCornerInRange(); + mAnchorOriginPoint = whichAnchorPoint(); - if (layer->isPaintable()) + // the user did not click on one of the corners + if (mScribbleArea->getMoveMode() == MoveMode::NONE) { - if (layer->type() == Layer::VECTOR) - { - static_cast(layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0)->deselectAll(); - } - mScribbleArea->setMoveMode(ScribbleArea::NONE); - - if (mScribbleArea->somethingSelected) // there is something selected - { - if (BezierCurve::mLength(getLastPoint() - mScribbleArea->myTransformedSelection.topLeft()) < 6) - { - mScribbleArea->setMoveMode(ScribbleArea::TOPLEFT); - anchorOriginPoint = mScribbleArea->mySelection.bottomRight(); - } - if (BezierCurve::mLength(getLastPoint() - mScribbleArea->myTransformedSelection.topRight()) < 6) - { - mScribbleArea->setMoveMode(ScribbleArea::TOPRIGHT); - anchorOriginPoint = mScribbleArea->mySelection.bottomLeft(); - } - if (BezierCurve::mLength(getLastPoint() - mScribbleArea->myTransformedSelection.bottomLeft()) < 6) - { - mScribbleArea->setMoveMode(ScribbleArea::BOTTOMLEFT); - anchorOriginPoint = mScribbleArea->mySelection.topRight(); - } - if (BezierCurve::mLength(getLastPoint() - mScribbleArea->myTransformedSelection.bottomRight()) < 6) - { - mScribbleArea->setMoveMode(ScribbleArea::BOTTOMRIGHT); - anchorOriginPoint = mScribbleArea->mySelection.topLeft(); - } - - // the user did not click on one of the corners - if (mScribbleArea->getMoveMode() == ScribbleArea::NONE) - { - // Deselect all and get ready for a new selection - mScribbleArea->deselectAll(); - - mScribbleArea->mySelection.setTopLeft(getLastPoint()); - mScribbleArea->mySelection.setBottomRight(getLastPoint()); - mScribbleArea->setSelection(mScribbleArea->mySelection, true); - } - } - else // there is nothing selected - { - mScribbleArea->mySelection.setTopLeft(getLastPoint()); - mScribbleArea->mySelection.setBottomRight(getLastPoint()); - mScribbleArea->setSelection(mScribbleArea->mySelection, true); - } - mScribbleArea->update(); + mScribbleArea->mySelection.setTopLeft(getLastPoint()); + mScribbleArea->mySelection.setBottomRight(getLastPoint()); + } } + else + { + mScribbleArea->setSelection(QRectF(getCurrentPoint().x(), + getCurrentPoint().y(),1,1)); + } + mScribbleArea->update(); } -void SelectTool::mouseReleaseEvent(QMouseEvent* event) +QPointF SelectTool::whichAnchorPoint() { - Layer* layer = mEditor->layers()->currentLayer(); - if (layer == NULL) return; + return mScribbleArea->whichAnchorPoint(mAnchorOriginPoint); +} +void SelectTool::mouseReleaseEvent(QMouseEvent* event) +{ + mCurrentLayer = mEditor->layers()->currentLayer(); + if (mCurrentLayer == NULL) return; if (event->button() != Qt::LeftButton) return; - - if (layer->type() == Layer::VECTOR) + + if (maybeDeselect()) { - if (mScribbleArea->somethingSelected) - { - mEditor->tools()->setCurrentTool(MOVE); - - VectorImage* vectorImage = static_cast(layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0); - mScribbleArea->setSelection(vectorImage->getSelectionRect(), true); - if (mScribbleArea->mySelection.width() <= 0 && mScribbleArea->mySelection.height() <= 0) - { - mScribbleArea->deselectAll(); - } - } - mScribbleArea->updateCurrentFrame(); - mScribbleArea->setAllDirty(); + mScribbleArea->deselectAll(); + } else { + keepSelection(); } - else if (layer->type() == Layer::BITMAP) + + mScribbleArea->updateToolCursor(); + + mScribbleArea->updateCurrentFrame(); + mScribbleArea->setAllDirty(); +} + +void SelectTool::mouseMoveEvent(QMouseEvent* event) +{ + mCurrentLayer = mEditor->layers()->currentLayer(); + if (mCurrentLayer == NULL) { return; } + if (!mCurrentLayer->isPaintable()) { return; } + if (!mScribbleArea->isSomethingSelected()) { return; } + + mScribbleArea->updateToolCursor(); + + if (event->buttons() & Qt::LeftButton) { - if (mScribbleArea->mySelection.width() <= 0 && mScribbleArea->mySelection.height() <= 0) + controlOffsetOrigin(); + + if (mCurrentLayer->type() == Layer::VECTOR) { - mScribbleArea->deselectAll(); + static_cast(mCurrentLayer)-> + getLastVectorImageAtFrame(mEditor->currentFrame(), 0)-> + select(mScribbleArea->myTempTransformedSelection); } - mScribbleArea->updateCurrentFrame(); - mScribbleArea->setAllDirty(); } + + mScribbleArea->updateCurrentFrame(); } -void SelectTool::mouseMoveEvent(QMouseEvent* event) +bool SelectTool::maybeDeselect() +{ + return (!isSelectionPointValid() && mScribbleArea->getMoveMode() == MoveMode::NONE); +} + +void SelectTool::controlOffsetOrigin() { - Layer* layer = mEditor->layers()->currentLayer(); - if (layer == NULL) { return; } + QPointF offset = QPointF(mScribbleArea->getTransformOffset().x(), + mScribbleArea->getTransformOffset().y()).toPoint(); - if ((event->buttons() & Qt::LeftButton) && - mScribbleArea->somethingSelected && - layer->isPaintable()) + if (mScribbleArea->getMoveMode() != MoveMode::NONE) { - mScribbleArea->manageSelectionOrigin(getCurrentPoint(), anchorOriginPoint); + if (mCurrentLayer->type() == Layer::BITMAP) { + offset = QPointF(mScribbleArea->getTransformOffset().x(), + mScribbleArea->getTransformOffset().y()).toPoint(); + } - mScribbleArea->myTransformedSelection = mScribbleArea->mySelection.adjusted(0, 0, 0, 0); - mScribbleArea->myTempTransformedSelection = mScribbleArea->mySelection.adjusted(0, 0, 0, 0); + mScribbleArea->adjustSelection(offset.x(),offset.y()); + } + else + { + // when the selection is none, manage the selection Origin + mScribbleArea->manageSelectionOrigin(getCurrentPoint(), mAnchorOriginPoint); + } +} - if (layer->type() == Layer::VECTOR) +/** + * @brief SelectTool::keepSelection + * Keep selection rect and normalize if invalid + */ +void SelectTool::keepSelection() +{ + if (mCurrentLayer->type() == Layer::BITMAP) { + if (!mScribbleArea->myTempTransformedSelection.isValid()) { - static_cast(layer)-> - getLastVectorImageAtFrame(mEditor->currentFrame(), 0)-> - select(mScribbleArea->mySelection); + mScribbleArea->setSelection(mScribbleArea->myTempTransformedSelection.normalized()); + } + else + { + mScribbleArea->setSelection(mScribbleArea->myTempTransformedSelection); } - mScribbleArea->update(); + } + else if (mCurrentLayer->type() == Layer::VECTOR) + { + VectorImage* vectorImage = static_cast(mCurrentLayer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0); + mScribbleArea->setSelection(vectorImage->getSelectionRect()); } } diff --git a/core_lib/src/tool/selecttool.h b/core_lib/src/tool/selecttool.h index ef03d7173..8533f66a3 100644 --- a/core_lib/src/tool/selecttool.h +++ b/core_lib/src/tool/selecttool.h @@ -20,6 +20,7 @@ GNU General Public License for more details. #include "basetool.h" +class Layer; class SelectTool : public BaseTool { @@ -31,16 +32,30 @@ class SelectTool : public BaseTool void loadSettings() override; QCursor cursor() override; +private: + void mousePressEvent(QMouseEvent*) override; void mouseReleaseEvent(QMouseEvent*) override; void mouseMoveEvent(QMouseEvent*) override; - bool keyPressEvent(QKeyEvent *event) override; + QPointF whichAnchorPoint(); + void controlOffsetOrigin(); + + void beginSelection(); + void keepSelection(); + + inline bool isSelectionPointValid() { return mAnchorOriginPoint != getLastPoint(); } + bool maybeDeselect(); + // Store selection origin so we can calculate // the selection rectangle in mousePressEvent. - QPointF anchorOriginPoint; + QPointF mAnchorOriginPoint; + MoveMode mOldMoveMode; + + Layer* mCurrentLayer = nullptr; + }; #endif From 4b21902e199c4ac3776ea3e16404a97391403335 Mon Sep 17 00:00:00 2001 From: CandyFace Date: Mon, 25 Jun 2018 21:04:55 +0200 Subject: [PATCH 114/184] Fix rotation being reset when rotating multiple times --- core_lib/src/interface/scribblearea.cpp | 6 +++--- core_lib/src/interface/scribblearea.h | 2 +- core_lib/src/tool/movetool.cpp | 4 +++- core_lib/src/tool/movetool.h | 2 ++ core_lib/src/tool/selecttool.cpp | 2 +- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index e04b0f3d2..5edd14802 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -1476,7 +1476,7 @@ QPointF ScribbleArea::whichAnchorPoint(QPointF anchorPoint) return anchorPoint; } -void ScribbleArea::adjustSelection(float offsetX, float offsetY) +void ScribbleArea::adjustSelection(float offsetX, float offsetY, qreal rotatedAngle) { QRectF& transformedSelection = myTransformedSelection; @@ -1527,8 +1527,8 @@ void ScribbleArea::adjustSelection(float offsetX, float offsetY) { myTempTransformedSelection = transformedSelection; // @ necessary? - myRotatedAngle = currentTool()->getCurrentPixel().x() - - currentTool()->getLastPressPixel().x(); + myRotatedAngle = (currentTool()->getCurrentPixel().x() - + currentTool()->getLastPressPixel().x()) + rotatedAngle; break; } default: diff --git a/core_lib/src/interface/scribblearea.h b/core_lib/src/interface/scribblearea.h index 996f3f5f0..c6c9e56b1 100644 --- a/core_lib/src/interface/scribblearea.h +++ b/core_lib/src/interface/scribblearea.h @@ -63,7 +63,7 @@ class ScribbleArea : public QWidget void deleteSelection(); void setSelection( QRectF rect ); - void adjustSelection(float offsetX, float offsetY); + void adjustSelection(float offsetX, float offsetY, qreal rotatedAngle); void applyAllSelectionChangesTo(QRectF& modifiedRect); void displaySelectionProperties(); void resetSelectionProperties(); diff --git a/core_lib/src/tool/movetool.cpp b/core_lib/src/tool/movetool.cpp index b6dae72c6..91a4c0f0e 100644 --- a/core_lib/src/tool/movetool.cpp +++ b/core_lib/src/tool/movetool.cpp @@ -70,6 +70,7 @@ void MoveTool::mouseReleaseEvent(QMouseEvent*) if (!mScribbleArea->isSomethingSelected()) return; + mRotatedAngle = mScribbleArea->myRotatedAngle; updateTransformation(); mScribbleArea->updateToolCursor(); @@ -130,7 +131,7 @@ void MoveTool::transformSelection(QMouseEvent* event) offset = maintainAspectRatio(offset.x(), offset.y()); } - mScribbleArea->adjustSelection(offset.x(),offset.y()); + mScribbleArea->adjustSelection(offset.x(),offset.y(), mRotatedAngle); mScribbleArea->calculateSelectionTransformation(); paintTransformedSelection(); @@ -156,6 +157,7 @@ void MoveTool::beginInteraction(QMouseEvent* event) } mScribbleArea->findMoveModeOfCornerInRange(); + mScribbleArea->myRotatedAngle = mRotatedAngle; if (event->modifiers() != Qt::ShiftModifier) { diff --git a/core_lib/src/tool/movetool.h b/core_lib/src/tool/movetool.h index b00ed6350..df24194e4 100644 --- a/core_lib/src/tool/movetool.h +++ b/core_lib/src/tool/movetool.h @@ -70,6 +70,8 @@ class MoveTool : public BaseTool Layer* mCurrentLayer = nullptr; + qreal mRotatedAngle = 0.0; + }; #endif diff --git a/core_lib/src/tool/selecttool.cpp b/core_lib/src/tool/selecttool.cpp index e02ce2aea..f73b4e65e 100644 --- a/core_lib/src/tool/selecttool.cpp +++ b/core_lib/src/tool/selecttool.cpp @@ -160,7 +160,7 @@ void SelectTool::controlOffsetOrigin() mScribbleArea->getTransformOffset().y()).toPoint(); } - mScribbleArea->adjustSelection(offset.x(),offset.y()); + mScribbleArea->adjustSelection(offset.x(),offset.y(), mScribbleArea->myRotatedAngle); } else { From 365c240bae05cc87860ee99d8dfd0ef54ca55a7e Mon Sep 17 00:00:00 2001 From: CandyFace Date: Wed, 27 Jun 2018 19:54:05 +0200 Subject: [PATCH 115/184] Refactor and fix transformation when rotating --- core_lib/src/interface/scribblearea.cpp | 31 +++++++++++-------------- core_lib/src/interface/scribblearea.h | 4 ++-- core_lib/src/tool/movetool.cpp | 25 +++++++++++++------- core_lib/src/tool/movetool.h | 4 ++-- core_lib/src/tool/selecttool.cpp | 2 -- 5 files changed, 35 insertions(+), 31 deletions(-) diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index 5edd14802..bc82df017 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -1607,32 +1607,29 @@ void ScribbleArea::paintTransformedSelection() update(); } -void ScribbleArea::applyAllSelectionChangesTo(QRectF& selectionRect) +void ScribbleArea::applySelectionChanges() { - // because we've applied some changes already, paint the transformation - // and make sure it's modified - paintTransformedSelection(); - - // we've painted the current selection but it has not been applied yet - // we make sure that the selection is correct - // by setting the temp (editing) selection - selectionRect = myTempTransformedSelection; - // Calculate the new transformation based on the new selection - calculateSelectionTransformation(); - - // apply the transformation to make the selection "stick" to the image - // we only want to do this when we're absolutely sure the transformation - // is final, othewise we will dirty the image upon further editing + // we haven't applied our last modifications yet + // therefore apply the transformed selection first. applyTransformedSelection(); - // finally set the transformation again - // normalize if below zero + // make sure the current transformed selection is valid if (!myTempTransformedSelection.isValid()) { myTempTransformedSelection = myTempTransformedSelection.normalized(); } setSelection(myTempTransformedSelection); + + // paint the transformed selection + paintTransformedSelection(); + + // Calculate the new transformation based on the new selection + calculateSelectionTransformation(); + + // apply the transformed selection to make the selection modification absolute. + applyTransformedSelection(); + } void ScribbleArea::applyTransformedSelection() diff --git a/core_lib/src/interface/scribblearea.h b/core_lib/src/interface/scribblearea.h index c6c9e56b1..371ffd8c2 100644 --- a/core_lib/src/interface/scribblearea.h +++ b/core_lib/src/interface/scribblearea.h @@ -64,7 +64,7 @@ class ScribbleArea : public QWidget void deleteSelection(); void setSelection( QRectF rect ); void adjustSelection(float offsetX, float offsetY, qreal rotatedAngle); - void applyAllSelectionChangesTo(QRectF& modifiedRect); + void applySelectionChanges(); void displaySelectionProperties(); void resetSelectionProperties(); @@ -141,7 +141,7 @@ public slots: void setModified( int layerNumber, int frameNumber ); inline bool transformHasBeenModified() { - return mySelection != myTempTransformedSelection; + return (mySelection != myTempTransformedSelection) || myRotatedAngle != 0; } void selectAll(); diff --git a/core_lib/src/tool/movetool.cpp b/core_lib/src/tool/movetool.cpp index 91a4c0f0e..72c55b4e1 100644 --- a/core_lib/src/tool/movetool.cpp +++ b/core_lib/src/tool/movetool.cpp @@ -163,7 +163,7 @@ void MoveTool::beginInteraction(QMouseEvent* event) { if (shouldDeselect()) { - applyChanges(); + applyTransformation(); mScribbleArea->deselectAll(); } } @@ -217,7 +217,7 @@ void MoveTool::setCurveSelected(VectorImage* vectorImage, QMouseEvent* event) { if (event->modifiers() != Qt::ShiftModifier) { - applyChanges(); + applyTransformation(); } vectorImage->setSelected(mScribbleArea->mClosestCurves, true); mScribbleArea->setSelection(vectorImage->getSelectionRect()); @@ -231,7 +231,7 @@ void MoveTool::setAreaSelected(VectorImage* vectorImage, QMouseEvent* event) { if (event->modifiers() != Qt::ShiftModifier) { - applyChanges(); + applyTransformation(); } vectorImage->setAreaSelected(areaNumber, true); mScribbleArea->setSelection(vectorImage->getSelectionRect()); @@ -294,12 +294,15 @@ void MoveTool::cancelChanges() mScribbleArea->deselectAll(); } -void MoveTool::applyAllChangesTo(QRectF& modifiedRect) +void MoveTool::applySelectionChanges() { - mScribbleArea->applyAllSelectionChangesTo(modifiedRect); + mScribbleArea->myRotatedAngle = 0; + mRotatedAngle = 0; + + mScribbleArea->applySelectionChanges(); } -void MoveTool::applyChanges() +void MoveTool::applyTransformation() { mScribbleArea->applyTransformedSelection(); } @@ -324,7 +327,10 @@ bool MoveTool::leavingThisTool() { if (mCurrentLayer->type() == Layer::BITMAP) { - applyAllChangesTo(mScribbleArea->myTransformedSelection); + applySelectionChanges(); + } + else if (mCurrentLayer->type() == Layer::VECTOR) { + applyTransformation(); } } @@ -358,7 +364,10 @@ bool MoveTool::switchingLayer() if (mCurrentLayer->type() == Layer::BITMAP) { - applyAllChangesTo(mScribbleArea->myTransformedSelection); + applySelectionChanges(); + + } else if (mCurrentLayer->type() == Layer::VECTOR) { + applyTransformation(); } mScribbleArea->deselectAll(); diff --git a/core_lib/src/tool/movetool.h b/core_lib/src/tool/movetool.h index df24194e4..11a84f796 100644 --- a/core_lib/src/tool/movetool.h +++ b/core_lib/src/tool/movetool.h @@ -43,8 +43,8 @@ class MoveTool : public BaseTool private: void cancelChanges(); - void applyChanges(); - void applyAllChangesTo(QRectF& modifiedRect); + void applyTransformation(); + void applySelectionChanges(); void resetSelectionProperties(); void paintTransformedSelection(); void whichAnchorPoint(); diff --git a/core_lib/src/tool/selecttool.cpp b/core_lib/src/tool/selecttool.cpp index f73b4e65e..d1e96a82a 100644 --- a/core_lib/src/tool/selecttool.cpp +++ b/core_lib/src/tool/selecttool.cpp @@ -58,8 +58,6 @@ void SelectTool::mousePressEvent(QMouseEvent* event) void SelectTool::beginSelection() { - mScribbleArea->myRotatedAngle = 0; - // Store original click position for help with selection rectangle. mAnchorOriginPoint = getLastPoint(); From 7b658d18ad66feb7e9fbb9dd2e271f6e67e4c672 Mon Sep 17 00:00:00 2001 From: CandyFace Date: Wed, 27 Jun 2018 19:55:45 +0200 Subject: [PATCH 116/184] Remove snap to selection --- core_lib/src/interface/scribblearea.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index bc82df017..27f1364d9 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -1484,16 +1484,9 @@ void ScribbleArea::adjustSelection(float offsetX, float offsetY, qreal rotatedAn { case MoveMode::MIDDLE: { - // if close enough to old selection, snap to origin. - if (QLineF(currentTool()->getLastPressPixel(), currentTool()->getCurrentPixel()).length() < 4) - { - myTempTransformedSelection = myTransformedSelection; - } - else - { - myTempTransformedSelection = - transformedSelection.translated(QPointF(offsetX, offsetY)); - } + myTempTransformedSelection = + transformedSelection.translated(QPointF(offsetX, offsetY)); + break; } case MoveMode::TOPRIGHT: From 038941a463e20215488660eb8ee275961c3250d8 Mon Sep 17 00:00:00 2001 From: CandyFace Date: Wed, 27 Jun 2018 19:59:26 +0200 Subject: [PATCH 117/184] Always apply transformation when leaving tool. --- core_lib/src/tool/movetool.cpp | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/core_lib/src/tool/movetool.cpp b/core_lib/src/tool/movetool.cpp index 72c55b4e1..661cbba9d 100644 --- a/core_lib/src/tool/movetool.cpp +++ b/core_lib/src/tool/movetool.cpp @@ -314,33 +314,15 @@ void MoveTool::paintTransformedSelection() bool MoveTool::leavingThisTool() { - if (mScribbleArea->isTemporaryTool()) { return true; } - if (!transformHasBeenModified()) { return true; } - - int returnValue = QMessageBox::warning(nullptr, - tr("Transform", "Windows title of layer switch pop-up."), - tr("You are about to switch tool, do you want to apply the transformation?"), - QMessageBox::No | QMessageBox::Cancel | QMessageBox::Yes, - QMessageBox::Yes); - - if (returnValue == QMessageBox::Yes) + if (mCurrentLayer->type() == Layer::BITMAP) { - if (mCurrentLayer->type() == Layer::BITMAP) - { - applySelectionChanges(); - } - else if (mCurrentLayer->type() == Layer::VECTOR) { - applyTransformation(); - } - + applySelectionChanges(); } - else if (returnValue == QMessageBox::No) + else if (mCurrentLayer->type() == Layer::VECTOR) { - cancelChanges(); - } - else if (returnValue == QMessageBox::Cancel) { - return false; + applyTransformation(); } + return true; } From 4ee4554cf18b872ffb8e22182f55b41e49d50a22 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Mon, 2 Jul 2018 22:53:32 +1000 Subject: [PATCH 118/184] Update miniz to 2.0.7 from 2.0.6 beta --- core_lib/src/miniz.cpp | 20 +++++++++++++------- core_lib/src/miniz.h | 8 ++++---- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/core_lib/src/miniz.cpp b/core_lib/src/miniz.cpp index 2355e4b61..4b640d0ac 100644 --- a/core_lib/src/miniz.cpp +++ b/core_lib/src/miniz.cpp @@ -630,7 +630,7 @@ const char *mz_error(int err) #ifdef __cplusplus -//extern "C" { +extern "C" { #endif /* ------------------- Low-level Compression (independent from all decompression API's) */ @@ -1936,6 +1936,8 @@ tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_fun d->m_pSrc = NULL; d->m_src_buf_left = 0; d->m_out_buf_ofs = 0; + if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) + MZ_CLEAR_OBJ(d->m_dict); memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); return TDEFL_STATUS_OKAY; @@ -2159,7 +2161,7 @@ void tdefl_compressor_free(tdefl_compressor *pComp) #endif #ifdef __cplusplus -//} +} #endif /************************************************************************** * @@ -2190,7 +2192,7 @@ void tdefl_compressor_free(tdefl_compressor *pComp) #ifdef __cplusplus -//extern "C" { +extern "C" { #endif /* ------------------- Low-level Decompression (completely independent from all compression API's) */ @@ -2892,7 +2894,7 @@ void tinfl_decompressor_free(tinfl_decompressor *pDecomp) } #ifdef __cplusplus -//} +} #endif /************************************************************************** * @@ -3015,7 +3017,7 @@ static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) #define MZ_FFLUSH fflush #define MZ_FREOPEN(p, m, s) freopen64(p, m, s) #define MZ_DELETE_FILE remove -#elif defined(__APPLE__) && _LARGEFILE64_SOURCE +#elif defined(__APPLE__) #ifndef MINIZ_NO_TIME #include #endif @@ -3881,7 +3883,10 @@ mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + { + MZ_FCLOSE(pFile); return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + } if (!mz_zip_reader_init_internal(pZip, flags)) { @@ -6031,14 +6036,15 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; mz_uint16 bit_flags = 0; + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; - if ((int)level_and_flags < 0) - level_and_flags = MZ_DEFAULT_LEVEL; level = level_and_flags & 0xF; store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); diff --git a/core_lib/src/miniz.h b/core_lib/src/miniz.h index 86fac4c32..8e5ad7287 100644 --- a/core_lib/src/miniz.h +++ b/core_lib/src/miniz.h @@ -1,4 +1,4 @@ -/* miniz.c 2.0.6 beta - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing +/* miniz.c 2.0.7 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing See "unlicense" statement at the end of this file. Rich Geldreich , last updated Oct. 13, 2013 Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt @@ -234,11 +234,11 @@ enum MZ_DEFAULT_COMPRESSION = -1 }; -#define MZ_VERSION "10.0.1" -#define MZ_VERNUM 0xA010 +#define MZ_VERSION "10.0.2" +#define MZ_VERNUM 0xA020 #define MZ_VER_MAJOR 10 #define MZ_VER_MINOR 0 -#define MZ_VER_REVISION 1 +#define MZ_VER_REVISION 2 #define MZ_VER_SUBREVISION 0 #ifndef MINIZ_NO_ZLIB_APIS From 406f82313ed5beb821ee4a2acee062f5e1af7237 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Mon, 2 Jul 2018 22:53:47 +1000 Subject: [PATCH 119/184] Debug info --- core_lib/src/qminiz.cpp | 15 +++++++-------- core_lib/src/structure/filemanager.cpp | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/core_lib/src/qminiz.cpp b/core_lib/src/qminiz.cpp index cc25cbfe5..dc8ec978b 100644 --- a/core_lib/src/qminiz.cpp +++ b/core_lib/src/qminiz.cpp @@ -42,26 +42,25 @@ bool MiniZ::isZip(const QString& sZipFilePath) Status MiniZ::compressFolder(QString zipFilePath, QString srcFolderPath, const QStringList& fileList) { DebugDetails dd; - dd << QString("Zip the folder %1 to %2").arg(zipFilePath).arg(srcFolderPath); + dd << QString("Creating Zip %1 from folder %2").arg(zipFilePath).arg(srcFolderPath); if (!srcFolderPath.endsWith("/")) { srcFolderPath.append("/"); } - mz_zip_archive* mz = new mz_zip_archive; OnScopeExit(delete mz); mz_zip_zero_struct(mz); mz_bool ok = mz_zip_writer_init_file(mz, zipFilePath.toUtf8().data(), 0); - if (!ok) { - dd << "Miniz writer init failed."; + mz_zip_error err = mz_zip_get_last_error(mz); + dd << QString("Miniz writer init failed: %1").arg((int)err); } - qDebug() << "SrcFolder=" << srcFolderPath; + //qDebug() << "SrcFolder=" << srcFolderPath; for (QString filePath : fileList) { QString sRelativePath = filePath; @@ -72,11 +71,11 @@ Status MiniZ::compressFolder(QString zipFilePath, QString srcFolderPath, const Q ok = mz_zip_writer_add_file(mz, sRelativePath.toUtf8().data(), filePath.toUtf8().data(), - "", 0, MZ_DEFAULT_COMPRESSION); - qDebug() << "Zip: " << filePath; + "", 0, MZ_BEST_SPEED); if (!ok) { - dd << QString(" Cannot add %1 to zip").arg(sRelativePath); + mz_zip_error err = mz_zip_get_last_error(mz); + dd << QString(" Cannot add %1: %2").arg(sRelativePath).arg((int)err); } } ok &= mz_zip_writer_finalize_archive(mz); diff --git a/core_lib/src/structure/filemanager.cpp b/core_lib/src/structure/filemanager.cpp index 8ea8a1ed5..109c397de 100644 --- a/core_lib/src/structure/filemanager.cpp +++ b/core_lib/src/structure/filemanager.cpp @@ -356,7 +356,7 @@ Status FileManager::save(Object* object, QString sFileName) out.flush(); file.close(); - dd << "Done writing main xml file"; + dd << "Done writing main xml file at" << sMainXMLFile; zippedFiles.append(sMainXMLFile); From c8067736b54a337bbe1c899ce7bc3102114034bc Mon Sep 17 00:00:00 2001 From: CandyFace Date: Mon, 2 Jul 2018 23:00:26 +0200 Subject: [PATCH 120/184] Set new filter for image sequence --- app/src/filedialogex.cpp | 2 +- core_lib/src/util/pencildef.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/filedialogex.cpp b/app/src/filedialogex.cpp index db07f573b..85ae5af7b 100644 --- a/app/src/filedialogex.cpp +++ b/app/src/filedialogex.cpp @@ -161,7 +161,7 @@ QString FileDialog::openFileFilters( FileType fileType ) { case FileType::ANIMATION: return PFF_OPEN_ALL_FILE_FILTER; case FileType::IMAGE: return PENCIL_IMAGE_FILTER; - case FileType::IMAGE_SEQUENCE: return PENCIL_IMAGE_FILTER; + case FileType::IMAGE_SEQUENCE: return PENCIL_IMAGE_SEQ_FILTER; case FileType::MOVIE: { Q_ASSERT(false); return PENCIL_MOVIE_EXT; } // currently not supported case FileType::SOUND: return tr( "Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3)" ); case FileType::PALETTE: return tr( "Pencil2D Palette (*.xml);; Gimp Palette (*.gpl)" ); diff --git a/core_lib/src/util/pencildef.h b/core_lib/src/util/pencildef.h index aee0eb282..a7bff8224 100644 --- a/core_lib/src/util/pencildef.h +++ b/core_lib/src/util/pencildef.h @@ -28,6 +28,9 @@ GNU General Public License for more details. #define PENCIL_IMAGE_FILTER \ QObject::tr( "Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif)" ) +#define PENCIL_IMAGE_SEQ_FILTER \ + QObject::tr( "Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);" ) + #define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) #define S__GIT_TIMESTAMP TOSTRING(GIT_TIMESTAMP) From 0b54248f31b12a883d885054b7e07229df49b6da Mon Sep 17 00:00:00 2001 From: CandyFace Date: Mon, 2 Jul 2018 23:09:01 +0200 Subject: [PATCH 121/184] fix tool properties being shared in some cases --- core_lib/src/tool/brushtool.cpp | 4 ++-- core_lib/src/tool/penciltool.cpp | 4 ++-- core_lib/src/tool/pentool.cpp | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/core_lib/src/tool/brushtool.cpp b/core_lib/src/tool/brushtool.cpp index f4b24cd74..86fac1ef0 100644 --- a/core_lib/src/tool/brushtool.cpp +++ b/core_lib/src/tool/brushtool.cpp @@ -61,7 +61,7 @@ void BrushTool::loadSettings() properties.pressure = settings.value( "brushPressure", false ).toBool(); properties.invisibility = settings.value("brushInvisibility", true).toBool(); properties.preserveAlpha = OFF; - properties.stabilizerLevel = settings.value("brushStabilization").toInt(); + properties.stabilizerLevel = settings.value("brushLineStabilization").toInt(); properties.useAA = settings.value("brushAA").toInt(); if (properties.useFeather == true) { @@ -140,7 +140,7 @@ void BrushTool::setStabilizerLevel(const int level) properties.stabilizerLevel = level; QSettings settings( PENCIL2D, PENCIL2D); - settings.setValue("brushStabilization", level); + settings.setValue("brushLineStabilization", level); settings.sync(); } diff --git a/core_lib/src/tool/penciltool.cpp b/core_lib/src/tool/penciltool.cpp index d8a3ce4b3..b86682761 100644 --- a/core_lib/src/tool/penciltool.cpp +++ b/core_lib/src/tool/penciltool.cpp @@ -50,7 +50,7 @@ void PencilTool::loadSettings() properties.width = settings.value("pencilWidth").toDouble(); properties.feather = 50; properties.pressure = settings.value("pencilPressure").toBool(); - properties.stabilizerLevel = settings.value("stabilizerLevel").toInt(); + properties.stabilizerLevel = settings.value("pencilLineStabilization").toInt(); properties.useAA = DISABLED; properties.useFeather = true; properties.useFillContour = false; @@ -124,7 +124,7 @@ void PencilTool::setStabilizerLevel(const int level) properties.stabilizerLevel = level; QSettings settings(PENCIL2D, PENCIL2D); - settings.setValue("stabilizerLevel", level); + settings.setValue("pencilLineStabilization", level); settings.sync(); } diff --git a/core_lib/src/tool/pentool.cpp b/core_lib/src/tool/pentool.cpp index 7380c4ef2..478991f77 100644 --- a/core_lib/src/tool/pentool.cpp +++ b/core_lib/src/tool/pentool.cpp @@ -47,8 +47,8 @@ void PenTool::loadSettings() properties.pressure = settings.value("penPressure").toBool(); properties.invisibility = OFF; properties.preserveAlpha = OFF; - properties.useAA = settings.value("brushAA").toBool(); - properties.stabilizerLevel = settings.value("stabilizerLevel").toInt(); + properties.useAA = settings.value("penAA").toBool(); + properties.stabilizerLevel = settings.value("penLineStabilization").toInt(); // First run if (properties.width <= 0) @@ -89,7 +89,7 @@ void PenTool::setAA(const int AA) // Update settings QSettings settings(PENCIL2D, PENCIL2D); - settings.setValue("brushAA", AA); + settings.setValue("penAA", AA); settings.sync(); } @@ -98,7 +98,7 @@ void PenTool::setStabilizerLevel(const int level) properties.stabilizerLevel = level; QSettings settings(PENCIL2D, PENCIL2D); - settings.setValue("stabilizerLevel", level); + settings.setValue("penLineStabilization", level); settings.sync(); } From 40d62cecd314e7fb718727ecc1f95646a7d4c05c Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 3 Jul 2018 10:13:06 +1000 Subject: [PATCH 122/184] Set MINIZ_NO_TIME - miniz uses _stat() to get file modified time but the file path doesn't accept Unicode - print miniz error strings when failing to add a file to zip archive --- core_lib/src/miniz.h | 2 +- core_lib/src/qminiz.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core_lib/src/miniz.h b/core_lib/src/miniz.h index 8e5ad7287..939add071 100644 --- a/core_lib/src/miniz.h +++ b/core_lib/src/miniz.h @@ -125,7 +125,7 @@ /* If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or */ /* get/set file times, and the C run-time funcs that get/set times won't be called. */ /* The current downside is the times written to your archives will be from 1979. */ -/*#define MINIZ_NO_TIME */ +#define MINIZ_NO_TIME /* Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. */ /*#define MINIZ_NO_ARCHIVE_APIS */ diff --git a/core_lib/src/qminiz.cpp b/core_lib/src/qminiz.cpp index dc8ec978b..f9302de6a 100644 --- a/core_lib/src/qminiz.cpp +++ b/core_lib/src/qminiz.cpp @@ -61,7 +61,7 @@ Status MiniZ::compressFolder(QString zipFilePath, QString srcFolderPath, const Q } //qDebug() << "SrcFolder=" << srcFolderPath; - for (QString filePath : fileList) + for (const QString& filePath : fileList) { QString sRelativePath = filePath; sRelativePath.replace(srcFolderPath, ""); @@ -75,7 +75,7 @@ Status MiniZ::compressFolder(QString zipFilePath, QString srcFolderPath, const Q if (!ok) { mz_zip_error err = mz_zip_get_last_error(mz); - dd << QString(" Cannot add %1: %2").arg(sRelativePath).arg((int)err); + dd << QString(" Cannot add %1: error %2, %3").arg(sRelativePath).arg((int)err).arg(mz_zip_get_error_string(err)); } } ok &= mz_zip_writer_finalize_archive(mz); From 8c7ec4e29c3ce3a9cfeae4c573c257bf25a0aa2c Mon Sep 17 00:00:00 2001 From: CandyFace Date: Tue, 3 Jul 2018 18:55:21 +0200 Subject: [PATCH 123/184] Improve gif import + Separate option to import GIF + space per image works now --- app/src/filedialogex.cpp | 4 +++ app/src/filedialogex.h | 1 + app/src/importimageseqdialog.cpp | 11 +++++-- app/src/importimageseqdialog.h | 2 +- app/src/mainwindow2.cpp | 55 +++++++++++++++++++++++++++++++ app/src/mainwindow2.h | 1 + app/ui/mainwindow2.ui | 6 ++++ core_lib/src/interface/editor.cpp | 19 +++++++++-- core_lib/src/interface/editor.h | 3 +- 9 files changed, 95 insertions(+), 7 deletions(-) diff --git a/app/src/filedialogex.cpp b/app/src/filedialogex.cpp index 85ae5af7b..9eec4eaec 100644 --- a/app/src/filedialogex.cpp +++ b/app/src/filedialogex.cpp @@ -132,6 +132,7 @@ QString FileDialog::openDialogTitle( FileType fileType ) case FileType::ANIMATION: return tr( "Open animation" ); case FileType::IMAGE: return tr( "Import image" ); case FileType::IMAGE_SEQUENCE: return tr( "Import image sequence" ); + case FileType::GIF: return tr( "Import Animated GIF" ); case FileType::MOVIE: return tr( "Import movie" ); case FileType::SOUND: return tr( "Import sound" ); case FileType::PALETTE: return tr( "Import palette" ); @@ -162,6 +163,7 @@ QString FileDialog::openFileFilters( FileType fileType ) case FileType::ANIMATION: return PFF_OPEN_ALL_FILE_FILTER; case FileType::IMAGE: return PENCIL_IMAGE_FILTER; case FileType::IMAGE_SEQUENCE: return PENCIL_IMAGE_SEQ_FILTER; + case FileType::GIF: return tr("Animated GIF (*.gif)"); case FileType::MOVIE: { Q_ASSERT(false); return PENCIL_MOVIE_EXT; } // currently not supported case FileType::SOUND: return tr( "Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3)" ); case FileType::PALETTE: return tr( "Pencil2D Palette (*.xml);; Gimp Palette (*.gpl)" ); @@ -222,6 +224,7 @@ QString FileDialog::defaultFileName( FileType fileType ) case FileType::ANIMATION: return tr( "MyAnimation.pclx" ); case FileType::IMAGE: return "untitled.png"; case FileType::IMAGE_SEQUENCE: return "untitled.png"; + case FileType::GIF: return "untitled.gif"; case FileType::MOVIE: return "untitled.mp4"; case FileType::SOUND: return "untitled.wav"; case FileType::PALETTE: return "untitled.xml"; @@ -237,6 +240,7 @@ QString FileDialog::toSettingKey( FileType fileType ) case FileType::ANIMATION: return "Animation"; case FileType::IMAGE: return "Image"; case FileType::IMAGE_SEQUENCE: return "ImageSequence"; + case FileType::GIF: return "Animated GIF"; case FileType::MOVIE: return "Movie"; case FileType::SOUND: return "Sound"; case FileType::PALETTE: return "Palette"; diff --git a/app/src/filedialogex.h b/app/src/filedialogex.h index f22dca02c..998314647 100644 --- a/app/src/filedialogex.h +++ b/app/src/filedialogex.h @@ -25,6 +25,7 @@ enum class FileType ANIMATION, IMAGE, IMAGE_SEQUENCE, + GIF, MOVIE, SOUND, PALETTE diff --git a/app/src/importimageseqdialog.cpp b/app/src/importimageseqdialog.cpp index 2d1ec2a0e..84dfb2e4c 100644 --- a/app/src/importimageseqdialog.cpp +++ b/app/src/importimageseqdialog.cpp @@ -19,13 +19,18 @@ GNU General Public License for more details. #include "ui_importimageseqoptions.h" #include "util.h" -ImportImageSeqDialog::ImportImageSeqDialog(QWidget* parent) : - ImportExportDialog(parent, ImportExportDialog::Import, FileType::IMAGE_SEQUENCE) +ImportImageSeqDialog::ImportImageSeqDialog(QWidget* parent, Mode mode, FileType fileType) : + ImportExportDialog(parent, mode, fileType) { ui = new Ui::ImportImageSeqOptions; ui->setupUi(getOptionsGroupBox()); - setWindowTitle(tr("Import image sequence")); + if (fileType == FileType::GIF) { + setWindowTitle(tr("Import Animated GIF")); + } else { + setWindowTitle(tr("Import image sequence")); + } + connect(ui->spaceSpinBox, static_cast(&QSpinBox::valueChanged), this, &ImportImageSeqDialog::setSpace); } diff --git a/app/src/importimageseqdialog.h b/app/src/importimageseqdialog.h index fafeba7ce..81d57de35 100644 --- a/app/src/importimageseqdialog.h +++ b/app/src/importimageseqdialog.h @@ -29,7 +29,7 @@ class ImportImageSeqDialog : public ImportExportDialog Q_OBJECT public: - explicit ImportImageSeqDialog(QWidget *parent = 0); + explicit ImportImageSeqDialog(QWidget *parent = 0, Mode mode = ImportExportDialog::Import, FileType fileType = FileType::IMAGE_SEQUENCE); ~ImportImageSeqDialog(); int getSpace(); diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index de2f64b57..a3617afa0 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -246,6 +246,7 @@ void MainWindow2::createMenus() //connect( ui->actionExport_Svg_Image, &QAction::triggered, editor, &Editor::saveSvg ); connect(ui->actionImport_Image, &QAction::triggered, this, &MainWindow2::importImage); connect(ui->actionImport_ImageSeq, &QAction::triggered, this, &MainWindow2::importImageSequence); + connect(ui->actionImport_Gif, &QAction::triggered, this, &MainWindow2::importGIF); connect(ui->actionImport_Movie, &QAction::triggered, this, &MainWindow2::importMovie); connect(ui->actionImport_Sound, &QAction::triggered, mCommands, &ActionCommands::importSound); @@ -838,6 +839,60 @@ void MainWindow2::importImageSequence() mIsImportingImageSequence = false; } +void MainWindow2::importGIF() +{ + auto gifDialog = new ImportImageSeqDialog(this, ImportExportDialog::Import, FileType::GIF); + gifDialog->exec(); + if (gifDialog->result() == QDialog::Rejected) + { + return; + } + + // Flag this so we don't prompt the user about auto-save in the middle of the import. + mIsImportingImageSequence = true; + + int space = gifDialog->getSpace(); + + // Show a progress dialog, as this could take a while if the gif is huge + QProgressDialog progress(tr("Importing Animated GIF..."), tr("Abort"), 0, 100, this); + hideQuestionMark(progress); + progress.setWindowModality(Qt::WindowModal); + progress.show(); + + bool failedImport = false; + QString strImgFileLower = gifDialog->getFilePath(); + + if (strImgFileLower.endsWith(".gif")) + { + mEditor->importGIF(strImgFileLower, space); + + progress.setValue(50); + QApplication::processEvents(); // Required to make progress bar update on-screen. + + } else { + if (!failedImport) + { + failedImport = true; + } + } + + if (failedImport) + { + QMessageBox::warning(this, + tr("Warning"), + tr("was unable to import") + strImgFileLower, + QMessageBox::Ok, + QMessageBox::Ok); + } + + mEditor->layers()->notifyAnimationLengthChanged(); + + progress.setValue(100); + progress.close(); + + mIsImportingImageSequence = false; +} + void MainWindow2::importMovie() { FileDialog fileDialog(this); diff --git a/app/src/mainwindow2.h b/app/src/mainwindow2.h index ac89b6bff..d557ed4ca 100644 --- a/app/src/mainwindow2.h +++ b/app/src/mainwindow2.h @@ -79,6 +79,7 @@ class MainWindow2 : public QMainWindow void importImage(); void importImageSequence(); void importMovie(); + void importGIF(); void lockWidgets(bool shouldLock); diff --git a/app/ui/mainwindow2.ui b/app/ui/mainwindow2.ui index c04406af5..2136fdd10 100644 --- a/app/ui/mainwindow2.ui +++ b/app/ui/mainwindow2.ui @@ -64,6 +64,7 @@ + @@ -876,6 +877,11 @@ F1 + + + Animated GIF + + diff --git a/core_lib/src/interface/editor.cpp b/core_lib/src/interface/editor.cpp index b08e3e78c..94c2d4b3b 100644 --- a/core_lib/src/interface/editor.cpp +++ b/core_lib/src/interface/editor.cpp @@ -760,7 +760,7 @@ QString Editor::workingDir() const return mObject->workingDir(); } -bool Editor::importBitmapImage(QString filePath) +bool Editor::importBitmapImage(QString filePath, int space) { QImageReader reader(filePath); @@ -787,7 +787,11 @@ bool Editor::importBitmapImage(QString filePath) BitmapImage importedBitmapImage{ boundaries, img }; bitmapImage->paste(&importedBitmapImage); - scrubTo(currentFrame() + 1); + if (space > 1) { + scrubTo(currentFrame() + space); + } else { + scrubTo(currentFrame() + 1); + } backup(tr("Import Image")); } @@ -841,6 +845,17 @@ bool Editor::importImage(QString filePath) } } +bool Editor::importGIF(QString filePath, int numOfImages) +{ + Layer* layer = layers()->currentLayer(); + if (layer->type() == Layer::BITMAP) { + return importBitmapImage(filePath, numOfImages); + } else { + return false; + } + +} + void Editor::updateFrame(int frameNumber) { mScribbleArea->updateFrame(frameNumber); diff --git a/core_lib/src/interface/editor.h b/core_lib/src/interface/editor.h index 21a0b295b..6c3f634fb 100644 --- a/core_lib/src/interface/editor.h +++ b/core_lib/src/interface/editor.h @@ -122,6 +122,7 @@ class Editor : public QObject void cut(); bool importImage(QString filePath); + bool importGIF(QString filePath, int numOfImages = 0); void updateFrame(int frameNumber); void restoreKey(); @@ -163,7 +164,7 @@ class Editor : public QObject void dropEvent(QDropEvent*); private: - bool importBitmapImage(QString); + bool importBitmapImage(QString, int space = 0); bool importVectorImage(QString); // the object to be edited by the editor From 2afe35c123482bc4191535128f0813721d3369dd Mon Sep 17 00:00:00 2001 From: CandyFace Date: Tue, 3 Jul 2018 21:00:54 +0200 Subject: [PATCH 124/184] Separate option to export GIF --- app/src/actioncommands.cpp | 22 +++++++++++++++++++--- app/src/actioncommands.h | 3 ++- app/src/exportmoviedialog.cpp | 11 ++++++++--- app/src/exportmoviedialog.h | 2 +- app/src/filedialogex.cpp | 4 +++- app/src/mainwindow2.cpp | 1 + app/ui/mainwindow2.ui | 6 ++++++ 7 files changed, 40 insertions(+), 9 deletions(-) diff --git a/app/src/actioncommands.cpp b/app/src/actioncommands.cpp index 2343a1891..96901ed7d 100644 --- a/app/src/actioncommands.cpp +++ b/app/src/actioncommands.cpp @@ -133,9 +133,20 @@ Status ActionCommands::importSound() return st; } -Status ActionCommands::exportMovie() +Status ActionCommands::exportGif() { - auto dialog = new ExportMovieDialog(mParent); + // exporting gif + return exportMovie(true); +} + +Status ActionCommands::exportMovie(bool isGif) +{ + ExportMovieDialog* dialog = nullptr; + if (isGif) { + dialog = new ExportMovieDialog(mParent, ImportExportDialog::Export, FileType::GIF); + } else { + dialog = new ExportMovieDialog(mParent); + } OnScopeExit(dialog->deleteLater()); dialog->init(); @@ -227,11 +238,16 @@ Status ActionCommands::exportMovie() if (st.ok() && QFile::exists(strMoviePath)) { + if (isGif) { + QMessageBox::information(mParent, "Pencil2D", + tr("Finished")); + return Status::OK; + } auto btn = QMessageBox::question(mParent, "Pencil2D", tr("Finished. Open movie now?", "When movie export done.")); if (btn == QMessageBox::Yes) { - QDesktopServices::openUrl(QUrl::fromLocalFile(strMoviePath)); + QDesktopServices::openUrl(QUrl::fromLocalFile(strMoviePath).path()); } } return Status::OK; diff --git a/app/src/actioncommands.h b/app/src/actioncommands.h index aea346665..bbd058ad0 100644 --- a/app/src/actioncommands.h +++ b/app/src/actioncommands.h @@ -36,9 +36,10 @@ class ActionCommands : public QObject // file Status importSound(); - Status exportMovie(); + Status exportMovie(bool isGif = false); Status exportImageSequence(); Status exportImage(); + Status exportGif(); // edit void flipSelectionX(); diff --git a/app/src/exportmoviedialog.cpp b/app/src/exportmoviedialog.cpp index 75ac31d65..c0730b57f 100644 --- a/app/src/exportmoviedialog.cpp +++ b/app/src/exportmoviedialog.cpp @@ -19,12 +19,17 @@ GNU General Public License for more details. #include "ui_exportmovieoptions.h" #include "util.h" -ExportMovieDialog::ExportMovieDialog(QWidget *parent) : - ImportExportDialog(parent, ImportExportDialog::Export, FileType::MOVIE), +ExportMovieDialog::ExportMovieDialog(QWidget *parent, Mode mode, FileType fileType) : + ImportExportDialog(parent, mode, fileType), ui(new Ui::ExportMovieOptions) { ui->setupUi(getOptionsGroupBox()); - setWindowTitle(tr("Export Movie")); + + if (fileType == FileType::GIF) { + setWindowTitle(tr("Export Animated GIF")); + } else { + setWindowTitle(tr("Export Movie")); + } connect(this, &ExportMovieDialog::filePathsChanged, this, &ExportMovieDialog::onFilePathsChanged); } diff --git a/app/src/exportmoviedialog.h b/app/src/exportmoviedialog.h index 850730f26..03a3731d1 100644 --- a/app/src/exportmoviedialog.h +++ b/app/src/exportmoviedialog.h @@ -31,7 +31,7 @@ class ExportMovieDialog : public ImportExportDialog Q_OBJECT public: - explicit ExportMovieDialog(QWidget* parent = 0); + explicit ExportMovieDialog(QWidget* parent = 0, Mode mode = ImportExportDialog::Export, FileType fileType = FileType::MOVIE); ~ExportMovieDialog(); void setCamerasInfo(const std::vector>); diff --git a/app/src/filedialogex.cpp b/app/src/filedialogex.cpp index 9eec4eaec..9fcaf5bb7 100644 --- a/app/src/filedialogex.cpp +++ b/app/src/filedialogex.cpp @@ -148,6 +148,7 @@ QString FileDialog::saveDialogTitle( FileType fileType ) case FileType::ANIMATION: return tr( "Save animation" ); case FileType::IMAGE: return tr( "Export image" ); case FileType::IMAGE_SEQUENCE: return tr( "Export image sequence" ); + case FileType::GIF: return tr( "Export Animated GIF" ); case FileType::MOVIE: return tr( "Export movie" ); case FileType::SOUND: return tr( "Export sound" ); case FileType::PALETTE: return tr( "Export palette" ); @@ -179,7 +180,8 @@ QString FileDialog::saveFileFilters( FileType fileType ) case FileType::ANIMATION: return PFF_SAVE_ALL_FILE_FILTER; case FileType::IMAGE: return ""; case FileType::IMAGE_SEQUENCE: return ""; - case FileType::MOVIE: return tr( "MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng)" ); + case FileType::GIF: return tr("Animated GIF (*.gif)"); + case FileType::MOVIE: return tr( "MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng)" ); case FileType::SOUND: return ""; case FileType::PALETTE: return tr( "Pencil2D Palette (*.xml);; Gimp Palette (*.gpl)" ); default: Q_ASSERT( false ); diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index a3617afa0..492597765 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -239,6 +239,7 @@ void MainWindow2::createMenus() connect(ui->actionExport_Image, &QAction::triggered, mCommands, &ActionCommands::exportImage); connect(ui->actionExport_ImageSeq, &QAction::triggered, mCommands, &ActionCommands::exportImageSequence); connect(ui->actionExport_Movie, &QAction::triggered, mCommands, &ActionCommands::exportMovie); + connect(ui->actionExport_Animated_GIF, &QAction::triggered, mCommands, &ActionCommands::exportGif); connect(ui->actionExport_Palette, &QAction::triggered, this, &MainWindow2::exportPalette); diff --git a/app/ui/mainwindow2.ui b/app/ui/mainwindow2.ui index 2136fdd10..70e310cd8 100644 --- a/app/ui/mainwindow2.ui +++ b/app/ui/mainwindow2.ui @@ -77,6 +77,7 @@ + @@ -882,6 +883,11 @@ Animated GIF + + + Animated GIF + + From 15b464af1fe9d99eb06dc5deca864eb5628ba98e Mon Sep 17 00:00:00 2001 From: CandyFace Date: Tue, 3 Jul 2018 22:38:46 +0200 Subject: [PATCH 125/184] Remove gif from image filter --- core_lib/src/util/pencildef.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core_lib/src/util/pencildef.h b/core_lib/src/util/pencildef.h index a7bff8224..71836eeff 100644 --- a/core_lib/src/util/pencildef.h +++ b/core_lib/src/util/pencildef.h @@ -26,7 +26,7 @@ GNU General Public License for more details. QObject::tr( "AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv)" ) #define PENCIL_IMAGE_FILTER \ - QObject::tr( "Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif)" ) + QObject::tr( "Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp)" ) #define PENCIL_IMAGE_SEQ_FILTER \ QObject::tr( "Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);" ) From 7acc49331dbda21101919a77a9471e6fee9213ba Mon Sep 17 00:00:00 2001 From: CandyFace Date: Tue, 3 Jul 2018 22:53:56 +0200 Subject: [PATCH 126/184] Fix UI typo --- app/ui/mainwindow2.ui | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/ui/mainwindow2.ui b/app/ui/mainwindow2.ui index 70e310cd8..94dc48b72 100644 --- a/app/ui/mainwindow2.ui +++ b/app/ui/mainwindow2.ui @@ -880,12 +880,12 @@ - Animated GIF + Animated GIF... - Animated GIF + Animated GIF... From 814abf0f510417628e5dd639b4239dd4c355e7b7 Mon Sep 17 00:00:00 2001 From: CandyFace Date: Thu, 5 Jul 2018 19:46:47 +0200 Subject: [PATCH 127/184] Fix tweening not working for GIF export --- core_lib/src/movieexporter.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core_lib/src/movieexporter.cpp b/core_lib/src/movieexporter.cpp index cfb197021..a2bcc4977 100644 --- a/core_lib/src/movieexporter.cpp +++ b/core_lib/src/movieexporter.cpp @@ -553,8 +553,6 @@ Status MovieExporter::generateGif( } imageToExportBase.fill(bgColor); - QTransform view = cameraLayer->getViewAtFrame(currentFrame); - QSize camSize = cameraLayer->getViewSize(); QTransform centralizeCamera; centralizeCamera.translate(camSize.width() / 2, camSize.height() / 2); @@ -597,6 +595,7 @@ Status MovieExporter::generateGif( QImage imageToExport = imageToExportBase.copy(); QPainter painter(&imageToExport); + QTransform view = cameraLayer->getViewAtFrame(currentFrame); painter.setWorldTransform(view * centralizeCamera); painter.setWindow(QRect(0, 0, camSize.width(), camSize.height())); From b4781f67f95f13b627e2c586921a7b75dcc4648f Mon Sep 17 00:00:00 2001 From: CandyFace Date: Thu, 5 Jul 2018 20:25:49 +0200 Subject: [PATCH 128/184] Fix movie not opening when prompted This is a bug presented in #1008 ... I accidentally added a change I wasn't meant to --- app/src/actioncommands.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/actioncommands.cpp b/app/src/actioncommands.cpp index 96901ed7d..27f6e8c7e 100644 --- a/app/src/actioncommands.cpp +++ b/app/src/actioncommands.cpp @@ -247,7 +247,7 @@ Status ActionCommands::exportMovie(bool isGif) tr("Finished. Open movie now?", "When movie export done.")); if (btn == QMessageBox::Yes) { - QDesktopServices::openUrl(QUrl::fromLocalFile(strMoviePath).path()); + QDesktopServices::openUrl(QUrl::fromLocalFile(strMoviePath)); } } return Status::OK; From 5bb0c3a03934cae4d908b20d5af240d4de26af7e Mon Sep 17 00:00:00 2001 From: CandyFace Date: Thu, 5 Jul 2018 21:21:00 +0200 Subject: [PATCH 129/184] UI/UX implement open file location dialog for GIF exports --- app/src/actioncommands.cpp | 15 +++++++++++++-- app/src/importexportdialog.cpp | 6 ++++++ app/src/importexportdialog.h | 1 + 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/app/src/actioncommands.cpp b/app/src/actioncommands.cpp index 27f6e8c7e..18e3009ed 100644 --- a/app/src/actioncommands.cpp +++ b/app/src/actioncommands.cpp @@ -239,8 +239,19 @@ Status ActionCommands::exportMovie(bool isGif) if (st.ok() && QFile::exists(strMoviePath)) { if (isGif) { - QMessageBox::information(mParent, "Pencil2D", - tr("Finished")); + auto btn = QMessageBox::question(mParent, "Pencil2D", + tr("Finished. Open file location?")); + + QString name = dialog->getFileName() + ".gif"; + + // Chop name + extension off the string + // to get folder path + strMoviePath.chop(name.size()); + + if (btn == QMessageBox::Yes) + { + QDesktopServices::openUrl(QUrl::fromLocalFile(strMoviePath)); + } return Status::OK; } auto btn = QMessageBox::question(mParent, "Pencil2D", diff --git a/app/src/importexportdialog.cpp b/app/src/importexportdialog.cpp index 3a61c0a3e..44abc5e51 100644 --- a/app/src/importexportdialog.cpp +++ b/app/src/importexportdialog.cpp @@ -49,6 +49,12 @@ QStringList ImportExportDialog::getFilePaths() return m_filePaths; } +QString ImportExportDialog::getFileName() +{ + QFileInfo info(m_filePaths.first()); + return info.baseName(); +} + void ImportExportDialog::init() { switch (mMode) diff --git a/app/src/importexportdialog.h b/app/src/importexportdialog.h index 8130db325..e991855d4 100644 --- a/app/src/importexportdialog.h +++ b/app/src/importexportdialog.h @@ -38,6 +38,7 @@ class ImportExportDialog : public QDialog void init(); QString getFilePath(); + QString getFileName(); QStringList getFilePaths(); signals: From b0d49495fde9471d17d4db2095eded12392b88f9 Mon Sep 17 00:00:00 2001 From: CandyFace Date: Fri, 6 Jul 2018 07:45:31 +0200 Subject: [PATCH 130/184] Use QFileInfo::AbsolutePath instead --- app/src/actioncommands.cpp | 9 ++------- app/src/importexportdialog.cpp | 4 ++-- app/src/importexportdialog.h | 2 +- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/app/src/actioncommands.cpp b/app/src/actioncommands.cpp index 18e3009ed..35c5b77af 100644 --- a/app/src/actioncommands.cpp +++ b/app/src/actioncommands.cpp @@ -242,15 +242,10 @@ Status ActionCommands::exportMovie(bool isGif) auto btn = QMessageBox::question(mParent, "Pencil2D", tr("Finished. Open file location?")); - QString name = dialog->getFileName() + ".gif"; - - // Chop name + extension off the string - // to get folder path - strMoviePath.chop(name.size()); - if (btn == QMessageBox::Yes) { - QDesktopServices::openUrl(QUrl::fromLocalFile(strMoviePath)); + QString path = dialog->getAbsolutePath(); + QDesktopServices::openUrl(QUrl::fromLocalFile(path)); } return Status::OK; } diff --git a/app/src/importexportdialog.cpp b/app/src/importexportdialog.cpp index 44abc5e51..9d86b4349 100644 --- a/app/src/importexportdialog.cpp +++ b/app/src/importexportdialog.cpp @@ -49,10 +49,10 @@ QStringList ImportExportDialog::getFilePaths() return m_filePaths; } -QString ImportExportDialog::getFileName() +QString ImportExportDialog::getAbsolutePath() { QFileInfo info(m_filePaths.first()); - return info.baseName(); + return info.absolutePath(); } void ImportExportDialog::init() diff --git a/app/src/importexportdialog.h b/app/src/importexportdialog.h index e991855d4..d78628b31 100644 --- a/app/src/importexportdialog.h +++ b/app/src/importexportdialog.h @@ -38,7 +38,7 @@ class ImportExportDialog : public QDialog void init(); QString getFilePath(); - QString getFileName(); + QString getAbsolutePath(); QStringList getFilePaths(); signals: From 18b28765c69dd917b994b2350327a184b124b071 Mon Sep 17 00:00:00 2001 From: CandyFace Date: Sat, 7 Jul 2018 16:39:28 +0200 Subject: [PATCH 131/184] Fix frame being moved but content not loaded properly #966 --- core_lib/src/graphics/bitmap/bitmapimage.cpp | 3 +++ core_lib/src/structure/layerbitmap.cpp | 27 +++++++++++++------- core_lib/src/structure/layerbitmap.h | 2 +- core_lib/src/util/pencilerror.h | 3 +++ 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/core_lib/src/graphics/bitmap/bitmapimage.cpp b/core_lib/src/graphics/bitmap/bitmapimage.cpp index 0fa990a36..7ec15ce94 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.cpp +++ b/core_lib/src/graphics/bitmap/bitmapimage.cpp @@ -83,6 +83,9 @@ BitmapImage& BitmapImage::operator=(const BitmapImage& a) BitmapImage* BitmapImage::clone() { + // try to load file if image appears to be null + loadFile(); + return new BitmapImage(*this); } diff --git a/core_lib/src/structure/layerbitmap.cpp b/core_lib/src/structure/layerbitmap.cpp index 9d8e09527..a1234ef9f 100644 --- a/core_lib/src/structure/layerbitmap.cpp +++ b/core_lib/src/structure/layerbitmap.cpp @@ -57,13 +57,23 @@ Status LayerBitmap::saveKeyFrameFile(KeyFrame* keyframe, QString path) QString theFileName = fileName(keyframe); QString strFilePath = QDir(path).filePath(theFileName); - if (needSaveFrame(keyframe, strFilePath) == false) + BitmapImage* bitmapImage = static_cast(keyframe); + + Status st = Status(Status::FAIL); + + st = needSaveFrame(keyframe, strFilePath); + if (st == Status::OK) { return Status::SAFE; + } else if (st == Status::KEYFRAME_MODIFIED) { + + bitmapImage = bitmapImage->clone(); + st = bitmapImage->writeFile(strFilePath); + } else { + st = bitmapImage->writeFile(strFilePath); } - BitmapImage* bitmapImage = static_cast(keyframe); - Status st = bitmapImage->writeFile(strFilePath); + if (!st.ok()) { bitmapImage->setFileName(""); @@ -77,7 +87,6 @@ Status LayerBitmap::saveKeyFrameFile(KeyFrame* keyframe, QString path) return Status(Status::FAIL, dd); } - bitmapImage->setFileName(strFilePath); bitmapImage->setModified(false); return Status::OK; } @@ -94,15 +103,15 @@ QString LayerBitmap::fileName(KeyFrame* key) const return QString::asprintf("%03d.%03d.png", id(), key->pos()); } -bool LayerBitmap::needSaveFrame(KeyFrame* key, const QString& strSavePath) +Status LayerBitmap::needSaveFrame(KeyFrame* key, const QString& strSavePath) { if (key->isModified()) // keyframe was modified - return true; + return Status::KEYFRAME_MODIFIED; if (QFile::exists(strSavePath) == false) // hasn't been saved before - return true; + return Status::KEYFRAME_MODIFIED; if (strSavePath != key->fileName()) // key frame moved - return true; - return false; + return Status::KEYFRAME_MODIFIED; + return Status::OK; } QDomElement LayerBitmap::createDomElement(QDomDocument& doc) diff --git a/core_lib/src/structure/layerbitmap.h b/core_lib/src/structure/layerbitmap.h index 8376b4ede..8010f113b 100644 --- a/core_lib/src/structure/layerbitmap.h +++ b/core_lib/src/structure/layerbitmap.h @@ -43,7 +43,7 @@ class LayerBitmap : public Layer private: QString fileName(KeyFrame* key) const; - bool needSaveFrame(KeyFrame* key, const QString& strSavePath); + Status needSaveFrame(KeyFrame* key, const QString& strSavePath); }; #endif diff --git a/core_lib/src/util/pencilerror.h b/core_lib/src/util/pencilerror.h index 64aa438c5..bc1d55c74 100644 --- a/core_lib/src/util/pencilerror.h +++ b/core_lib/src/util/pencilerror.h @@ -71,6 +71,9 @@ class Status // Layer ERROR_NEED_AT_LEAST_ONE_CAMERA_LAYER, + + // Timeline + KEYFRAME_MODIFIED }; Status(ErrorCode code); From 05e359b5055f8780a9aee72cc6887202c1f7df5c Mon Sep 17 00:00:00 2001 From: CandyFace Date: Sat, 7 Jul 2018 17:10:58 +0200 Subject: [PATCH 132/184] Remove files with no XML reference --- core_lib/src/structure/filemanager.cpp | 59 ++++++++++++++++++++++++++ core_lib/src/structure/filemanager.h | 3 ++ 2 files changed, 62 insertions(+) diff --git a/core_lib/src/structure/filemanager.cpp b/core_lib/src/structure/filemanager.cpp index 109c397de..c2d5d5ba5 100644 --- a/core_lib/src/structure/filemanager.cpp +++ b/core_lib/src/structure/filemanager.cpp @@ -292,6 +292,10 @@ Status FileManager::save(Object* object, QString sFileName) tr("Cannot Create Data Directory"), tr("\"%1\" is a file. Please delete the file and try again.").arg(dataInfo.absoluteFilePath())); } + // There may be old files lying around + // from projects before this implementation, cleanup their dirty workfolder + // before saving new content + removeFilesWithNoXMLReference(sMainXMLFile, sDataFolder); // save data int numLayers = object->getLayerCount(); @@ -356,6 +360,10 @@ Status FileManager::save(Object* object, QString sFileName) out.flush(); file.close(); + // There may be old files may be lying around, cleanup workfolder before + // zipping + removeFilesWithNoXMLReference(sMainXMLFile, sDataFolder); + dd << "Done writing main xml file at" << sMainXMLFile; zippedFiles.append(sMainXMLFile); @@ -622,3 +630,54 @@ Status FileManager::verifyObject(Object* obj) return Status::OK; } +QStringList FileManager::getImageSrcNamesFromXML(QString mainXmlFile, QString dataFolderPath) +{ + QStringList listOfWorkFolderFiles = QDir(dataFolderPath).entryList(QDir::Files); + + QFile xmlFile(mainXmlFile); + QDomDocument xmlDoc; + xmlDoc.setContent(&xmlFile); + QDomElement objectElem = xmlDoc.firstChildElement("document"); + + QStringList srcNames; + + QDomNode objectNode = objectElem.namedItem("object"); + QDomElement element = objectNode.toElement(); + + for (QDomNode child = element.firstChild(); !child.isNull(); child = child.nextSibling()) + { + QDomElement element = child.toElement(); + if (element.tagName() == "layer") + { + for (QDomNode child2 = element.firstChild(); !child2.isNull(); child2 = child2.nextSibling()) + { + QDomElement element = child2.toElement(); + + srcNames << element.attribute("src"); + } + } + } + return srcNames; +} + +void FileManager::removeFilesWithNoXMLReference(QString xmlFilePath, QString dataFolderPath) +{ + QStringList srcNames = getImageSrcNamesFromXML(xmlFilePath, dataFolderPath); + QStringList listOfWorkFolderFiles = QDir(dataFolderPath).entryList(QDir::Files); + for (QString fileName: listOfWorkFolderFiles) + { + bool fileExists = false; + for (QString srcName: srcNames) + { + if (fileName == srcName) + { + fileExists = true; + } + } + + if (!fileExists && !fileName.endsWith(".xml", Qt::CaseInsensitive)) + { + QDir(dataFolderPath).remove(fileName); + } + } +} diff --git a/core_lib/src/structure/filemanager.h b/core_lib/src/structure/filemanager.h index 9ace6e863..f31812f50 100644 --- a/core_lib/src/structure/filemanager.h +++ b/core_lib/src/structure/filemanager.h @@ -67,6 +67,9 @@ class FileManager : public QObject void deleteBackupFile(const QString& fileName); void progressForward(); + void removeFilesWithNoXMLReference(QString xmlFilePath, QString dataFolderPath); + + QStringList getImageSrcNamesFromXML(QString mainXmlFile, QString dataFolderPath); private: Status mError = Status::OK; From 599054b55b7a69f9f7a4ce22d46858aa21bc4ff6 Mon Sep 17 00:00:00 2001 From: CandyFace Date: Sun, 8 Jul 2018 13:04:32 +0200 Subject: [PATCH 133/184] Fix files not being written to because their name hadn't been set --- core_lib/src/graphics/bitmap/bitmapimage.cpp | 5 --- core_lib/src/structure/filemanager.cpp | 8 ----- core_lib/src/structure/keyframe.h | 3 ++ core_lib/src/structure/layerbitmap.cpp | 36 +++++++++++++------- core_lib/src/util/pencilerror.h | 4 ++- 5 files changed, 30 insertions(+), 26 deletions(-) diff --git a/core_lib/src/graphics/bitmap/bitmapimage.cpp b/core_lib/src/graphics/bitmap/bitmapimage.cpp index 7ec15ce94..8fb000e9d 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.cpp +++ b/core_lib/src/graphics/bitmap/bitmapimage.cpp @@ -83,9 +83,6 @@ BitmapImage& BitmapImage::operator=(const BitmapImage& a) BitmapImage* BitmapImage::clone() { - // try to load file if image appears to be null - loadFile(); - return new BitmapImage(*this); } @@ -93,10 +90,8 @@ void BitmapImage::loadFile() { if (mImage == nullptr) { - Q_ASSERT(isModified() == false); mImage = std::make_shared(fileName()); mBounds.setSize(mImage->size()); - //qDebug() << "Load file=" << fileName(); } } diff --git a/core_lib/src/structure/filemanager.cpp b/core_lib/src/structure/filemanager.cpp index c2d5d5ba5..a1ec37bb2 100644 --- a/core_lib/src/structure/filemanager.cpp +++ b/core_lib/src/structure/filemanager.cpp @@ -292,10 +292,6 @@ Status FileManager::save(Object* object, QString sFileName) tr("Cannot Create Data Directory"), tr("\"%1\" is a file. Please delete the file and try again.").arg(dataInfo.absoluteFilePath())); } - // There may be old files lying around - // from projects before this implementation, cleanup their dirty workfolder - // before saving new content - removeFilesWithNoXMLReference(sMainXMLFile, sDataFolder); // save data int numLayers = object->getLayerCount(); @@ -360,10 +356,6 @@ Status FileManager::save(Object* object, QString sFileName) out.flush(); file.close(); - // There may be old files may be lying around, cleanup workfolder before - // zipping - removeFilesWithNoXMLReference(sMainXMLFile, sDataFolder); - dd << "Done writing main xml file at" << sMainXMLFile; zippedFiles.append(sMainXMLFile); diff --git a/core_lib/src/structure/keyframe.h b/core_lib/src/structure/keyframe.h index 8922a7836..6c958b723 100644 --- a/core_lib/src/structure/keyframe.h +++ b/core_lib/src/structure/keyframe.h @@ -48,6 +48,8 @@ class KeyFrame QString fileName() const { return mAttachedFileName; } void setFileName(QString strFileName) { mAttachedFileName = strFileName; } + bool hasBeenRenamed() const { return mHasBeenRenamed; } + void setRenamed(bool b) { mHasBeenRenamed = b; } void addEventListener(KeyFrameEventListener*); void removeEventListner(KeyFrameEventListener*); @@ -61,6 +63,7 @@ class KeyFrame int mLength = 1; bool mIsModified = true; bool mIsSelected = false; + bool mHasBeenRenamed = false; QString mAttachedFileName; std::vector mEventListeners; diff --git a/core_lib/src/structure/layerbitmap.cpp b/core_lib/src/structure/layerbitmap.cpp index a1234ef9f..868b0618a 100644 --- a/core_lib/src/structure/layerbitmap.cpp +++ b/core_lib/src/structure/layerbitmap.cpp @@ -59,21 +59,26 @@ Status LayerBitmap::saveKeyFrameFile(KeyFrame* keyframe, QString path) BitmapImage* bitmapImage = static_cast(keyframe); - Status st = Status(Status::FAIL); - - st = needSaveFrame(keyframe, strFilePath); + Status st = needSaveFrame(keyframe, strFilePath); if (st == Status::OK) { return Status::SAFE; - } else if (st == Status::KEYFRAME_MODIFIED) { - - bitmapImage = bitmapImage->clone(); - st = bitmapImage->writeFile(strFilePath); - } else { - st = bitmapImage->writeFile(strFilePath); } + if (bitmapImage->fileName().isEmpty()) + { + bitmapImage->setFileName(strFilePath); + } + else if(strFilePath != bitmapImage->fileName()) + { + bitmapImage->setFileName(bitmapImage->fileName()); + } + else { + bitmapImage->setFileName(strFilePath); + } + bitmapImage->setRenamed(true); + st = bitmapImage->writeFile(strFilePath); if (!st.ok()) { bitmapImage->setFileName(""); @@ -108,9 +113,9 @@ Status LayerBitmap::needSaveFrame(KeyFrame* key, const QString& strSavePath) if (key->isModified()) // keyframe was modified return Status::KEYFRAME_MODIFIED; if (QFile::exists(strSavePath) == false) // hasn't been saved before - return Status::KEYFRAME_MODIFIED; + return Status::KEYFRAME_EXISTS; if (strSavePath != key->fileName()) // key frame moved - return Status::KEYFRAME_MODIFIED; + return Status::KEYFRAME_MOVED; return Status::OK; } @@ -133,7 +138,14 @@ QDomElement LayerBitmap::createDomElement(QDomDocument& doc) imageTag.setAttribute("topLeftY", pImg->topLeft().y()); layerTag.appendChild(imageTag); - Q_ASSERT(QFileInfo(pKeyFrame->fileName()).fileName() == fileName(pKeyFrame)); + if (!pImg->hasBeenRenamed()) + { + Q_ASSERT(QFileInfo(pKeyFrame->fileName()).fileName() == fileName(pKeyFrame)); + } + else + { + pImg->setRenamed(false); + } }); return layerTag; diff --git a/core_lib/src/util/pencilerror.h b/core_lib/src/util/pencilerror.h index bc1d55c74..a98a2976e 100644 --- a/core_lib/src/util/pencilerror.h +++ b/core_lib/src/util/pencilerror.h @@ -73,7 +73,9 @@ class Status ERROR_NEED_AT_LEAST_ONE_CAMERA_LAYER, // Timeline - KEYFRAME_MODIFIED + KEYFRAME_MODIFIED, + KEYFRAME_MOVED, + KEYFRAME_EXISTS }; Status(ErrorCode code); From dd580aaabad0fb953ac77aa0b369226b99751421 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Thu, 12 Jul 2018 17:39:59 +1000 Subject: [PATCH 134/184] Xcode warnings --- core_lib/src/canvaspainter.cpp | 6 +++--- core_lib/src/tool/smudgetool.h | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/core_lib/src/canvaspainter.cpp b/core_lib/src/canvaspainter.cpp index 88682cc8a..73ffd1368 100644 --- a/core_lib/src/canvaspainter.cpp +++ b/core_lib/src/canvaspainter.cpp @@ -77,9 +77,9 @@ void CanvasPainter::paint(const Object* object, int layer, int frame, QRect rect mCurrentLayerIndex = layer; mFrameNumber = frame; - QRectF mappedInvCanvas = mViewInverse.mapRect(QRectF(mCanvas->rect())); - QSizeF croppedPainter = QSizeF(mappedInvCanvas.size()); - QRectF aligned = QRectF(QPointF(mappedInvCanvas.topLeft()), croppedPainter); + //QRectF mappedInvCanvas = mViewInverse.mapRect(QRectF(mCanvas->rect())); + //QSizeF croppedPainter = QSizeF(mappedInvCanvas.size()); + //QRectF aligned = QRectF(QPointF(mappedInvCanvas.topLeft()), croppedPainter); QPainter painter(mCanvas); painter.setWorldMatrixEnabled(true); diff --git a/core_lib/src/tool/smudgetool.h b/core_lib/src/tool/smudgetool.h index 60b522b1f..f1f6de242 100644 --- a/core_lib/src/tool/smudgetool.h +++ b/core_lib/src/tool/smudgetool.h @@ -36,12 +36,12 @@ class SmudgeTool : public StrokeTool bool keyPressEvent(QKeyEvent *) override; bool keyReleaseEvent(QKeyEvent *) override; - void adjustPressureSensitiveProperties(qreal pressure, bool mouseDevice); + void adjustPressureSensitiveProperties(qreal pressure, bool mouseDevice) override; void drawStroke(); - void setWidth( const qreal width ); - void setFeather( const qreal feather ); - void setPressure( const bool pressure ); + void setWidth( const qreal width ) override; + void setFeather( const qreal feather ) override; + void setPressure( const bool pressure ) override; protected: bool emptyFrameActionEnabled() override; From 3634174b66152707a5366a7305d0df7ef86788d0 Mon Sep 17 00:00:00 2001 From: CandyFace Date: Thu, 12 Jul 2018 18:18:49 +0200 Subject: [PATCH 135/184] Revert changes and remove unused enums --- core_lib/src/structure/layerbitmap.cpp | 16 ++++++++-------- core_lib/src/structure/layerbitmap.h | 2 +- core_lib/src/util/pencilerror.h | 7 +------ 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/core_lib/src/structure/layerbitmap.cpp b/core_lib/src/structure/layerbitmap.cpp index 868b0618a..4f38c62da 100644 --- a/core_lib/src/structure/layerbitmap.cpp +++ b/core_lib/src/structure/layerbitmap.cpp @@ -59,8 +59,8 @@ Status LayerBitmap::saveKeyFrameFile(KeyFrame* keyframe, QString path) BitmapImage* bitmapImage = static_cast(keyframe); - Status st = needSaveFrame(keyframe, strFilePath); - if (st == Status::OK) + bool needSave = needSaveFrame(keyframe, strFilePath); + if (!needSave) { return Status::SAFE; } @@ -78,7 +78,7 @@ Status LayerBitmap::saveKeyFrameFile(KeyFrame* keyframe, QString path) } bitmapImage->setRenamed(true); - st = bitmapImage->writeFile(strFilePath); + Status st = bitmapImage->writeFile(strFilePath); if (!st.ok()) { bitmapImage->setFileName(""); @@ -108,15 +108,15 @@ QString LayerBitmap::fileName(KeyFrame* key) const return QString::asprintf("%03d.%03d.png", id(), key->pos()); } -Status LayerBitmap::needSaveFrame(KeyFrame* key, const QString& strSavePath) +bool LayerBitmap::needSaveFrame(KeyFrame* key, const QString& strSavePath) { if (key->isModified()) // keyframe was modified - return Status::KEYFRAME_MODIFIED; + return true; if (QFile::exists(strSavePath) == false) // hasn't been saved before - return Status::KEYFRAME_EXISTS; + return true; if (strSavePath != key->fileName()) // key frame moved - return Status::KEYFRAME_MOVED; - return Status::OK; + return true; + return false; } QDomElement LayerBitmap::createDomElement(QDomDocument& doc) diff --git a/core_lib/src/structure/layerbitmap.h b/core_lib/src/structure/layerbitmap.h index 8010f113b..8376b4ede 100644 --- a/core_lib/src/structure/layerbitmap.h +++ b/core_lib/src/structure/layerbitmap.h @@ -43,7 +43,7 @@ class LayerBitmap : public Layer private: QString fileName(KeyFrame* key) const; - Status needSaveFrame(KeyFrame* key, const QString& strSavePath); + bool needSaveFrame(KeyFrame* key, const QString& strSavePath); }; #endif diff --git a/core_lib/src/util/pencilerror.h b/core_lib/src/util/pencilerror.h index a98a2976e..42a8afb6d 100644 --- a/core_lib/src/util/pencilerror.h +++ b/core_lib/src/util/pencilerror.h @@ -70,12 +70,7 @@ class Status ERROR_FFMPEG_NOT_FOUND, // Layer - ERROR_NEED_AT_LEAST_ONE_CAMERA_LAYER, - - // Timeline - KEYFRAME_MODIFIED, - KEYFRAME_MOVED, - KEYFRAME_EXISTS + ERROR_NEED_AT_LEAST_ONE_CAMERA_LAYER }; Status(ErrorCode code); From a1687388c15e631bc33bb1cec7f2f7d61624a69b Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 17 Jul 2018 10:16:38 +1000 Subject: [PATCH 136/184] Update desktop entry translations --- app/data/pencil2d.desktop | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/app/data/pencil2d.desktop b/app/data/pencil2d.desktop index 10dcd9db2..1a6d6f3e9 100644 --- a/app/data/pencil2d.desktop +++ b/app/data/pencil2d.desktop @@ -9,7 +9,9 @@ Exec=pencil2d %f MimeType=application/x-pencil-pcl;application/x-pencil-pclx; Categories=Graphics;2DGraphics;VectorGraphics;RasterGraphics;Qt;AudioVideo;Video; Keywords=picture;drawing;vector;bitmap;cartoon; -Keywords[de]=Bild;Zeichnen;Vektor;Raster;Zeichentrick; + + +# Translations # Translations @@ -17,10 +19,10 @@ Name[he]=Pencil2D GenericName[he]=תוכנת הנפשה Comment[he]=צרו הנפשה מסורתית מצויירת ביד באמצעות כלי מפת ביטים וכלים וקטוריים Icon[he]=pencil2d -Name[sl]=Svinčnik2D -GenericName[sl]=Program za animacijo -Comment[sl]=Ustvarite tradicionalno ročno risano animacijo s pomočjo bitne in vektorske grafike -Icon[sl]=svinčnik2d +Name[ar]=بنسل2D +GenericName[ar]=برنامج تحريك الرسومات +Comment[ar]=أنشئ رسومات متحركة بالطريقة الكلاسكية بإستخدام bitmap و vector graphics +Icon[ar]=pencil2d Name[pt]=Pencil2D GenericName[pt]=Programa de Animação Comment[pt]=Cria animações tradicionais feitas a mão utilizando bitmaps e vectores gráficos @@ -43,17 +45,26 @@ Name[de]=Pencil2D GenericName[de]=Animationssoftware Comment[de]=Traditionelle handgezeichnete Animation sowohl mit Raster- als auch mit Vektorgrafik schaffen Icon[de]=pencil2d +Name[sl]=Svinčnik2D +GenericName[sl]=Program za animacijo +Comment[sl]=Ustvarite tradicionalno ročno risano animacijo s pomočjo bitne in vektorske grafike +Icon[sl]=pencil2d Name[es]=Pencil2D GenericName[es]=Programa de Animación Comment[es]=Crea animaciones tradicionales hechas a mano usando mapas de bits o vectores gráficos Icon[es]=pencil2d Name[et]=Pencil2D GenericName[et]=Animeerimistarkvara +Comment[et]=Loo traditsioonilisi käsitsijoonistatud animatsioone kasutades nii raster- kui vektorgraafikat. Icon[et]=pencil2d Name[vi]=Pencil 2D GenericName[vi]=Phần mềm làm phim hoạt hình Comment[vi]=Tạo nên các chuyển Động hoạt hình vẽ tay truyền thống bằng các hình ảnh Bitmap và Vector -Icon[vi]=Pencil 2D +Icon[vi]=pencil2d +Name[zh_CN]=Pencil2D +GenericName[zh_CN]=动画软件 +Comment[zh_CN]=用位图和矢量两种图像技术创作传统手绘动画 +Icon[zh_CN]=pencil2d Name[fr]=Pencil2D GenericName[fr]=Logiciel d'Animation Comment[fr]=Créez une animation traditionnelle dessinée à la main à l'aide de graphiques bitmap et vectoriels From 0200af1439b65d940195ed6b4f3a85736ee123fe Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 17 Jul 2018 10:19:53 +1000 Subject: [PATCH 137/184] Transifex sync --- translations/pencil_cs.ts | 1012 ++++++++++++++++++---------------- translations/pencil_da.ts | 746 +++++++++++++------------ translations/pencil_de.ts | 748 +++++++++++++------------ translations/pencil_es.ts | 748 +++++++++++++------------ translations/pencil_et.ts | 858 ++++++++++++++-------------- translations/pencil_fr.ts | 760 +++++++++++++------------ translations/pencil_he.ts | 748 +++++++++++++------------ translations/pencil_hu_HU.ts | 748 +++++++++++++------------ translations/pencil_id.ts | 746 +++++++++++++------------ translations/pencil_it.ts | 748 +++++++++++++------------ translations/pencil_ja.ts | 748 +++++++++++++------------ translations/pencil_pl.ts | 8 +- translations/pencil_pt.ts | 748 +++++++++++++------------ translations/pencil_pt_BR.ts | 748 +++++++++++++------------ translations/pencil_ru.ts | 748 +++++++++++++------------ translations/pencil_sl.ts | 748 +++++++++++++------------ translations/pencil_vi.ts | 748 +++++++++++++------------ translations/pencil_zh_TW.ts | 746 +++++++++++++------------ 18 files changed, 6942 insertions(+), 6162 deletions(-) diff --git a/translations/pencil_cs.ts b/translations/pencil_cs.ts index d23c5efe7..bb92d64ca 100644 --- a/translations/pencil_cs.ts +++ b/translations/pencil_cs.ts @@ -10,7 +10,7 @@ Official site: <a href="https://www.pencil2d.org">pencil2d.org</a><br>Developed by: <b>Pascal Naidon, Patrick Corrieri, Matt Chang</b><br>Thanks to Qt Framework <a href="https://www.qt.io/download">https://www.qt.io/</a><br>miniz: <a href="https://github.com/richgel999/miniz">https://github.com/richgel999/miniz</a><br>Distributed under the <a href="http://www.gnu.org/licenses/gpl-2.0.html">GNU General Public License, version 2</a> - + Stránky: <a href="https://www.pencil2d.org">pencil2d.org</a><br>Developed by: <b>Pascal Naidon, Patrick Corrieri, Matt Chang</b><br>Poděkování Qt Framework <a href="https://www.qt.io/download">https://www.qt.io/</a><br>miniz: <a href="https://github.com/richgel999/miniz">https://github.com/richgel999/miniz</a><br>Šířeno pod <a href="http://www.gnu.org/licenses/gpl-2.0.html">GNU General Public License, verze 2</a> @@ -57,7 +57,7 @@ Exporting movie - + Vyvádí se obrazový záznam... @@ -148,57 +148,57 @@ BaseTool - + Pencil Tužka - + Eraser Guma - + Select - Vybrat + Výběr - + Move - Posunout + Posun - + Hand Ruka - + Smudge Šmouha - + Pen Pero - + Polyline Lomená čára - + Bucket Kbelík - + Eyedropper Kapátko - + Brush Štětec @@ -208,7 +208,7 @@ Camera Properties - + Vlastnosti kamery @@ -289,7 +289,7 @@ Color Palette Window title of color palette. - + Paleta barev @@ -309,59 +309,59 @@ List Mode - + Režim seznamu Show palette as a list - + Ukázat paletu jako seznam Grid Mode - + Režim mřížky Show palette as icons - + Ukázat paletu jako ikony Small swatch - + Malý vzorek barvy Sets swatch size to: 16x16px - + Nastaví velikost vzorku barvy na: 16 x 16 obrazových bodů (px) Medium Swatch - + Střední vzorek barvy Sets swatch size to: 26x26px - + Nastaví velikost vzorku barvy na: 26 x 26 obrazových bodů (px) Large Swatch - + Velký vzorek barvy Sets swatch size to: 36x36px - + Nastaví velikost vzorku barvy na: 36 x 36 obrazových bodů (px) ColorPaletteWidget - - + + Colour name Název barvy @@ -371,7 +371,7 @@ Horizontal flip - Převrátit horizontálně + Převrátit vodorovně @@ -388,7 +388,7 @@ Display Window title of display options like . - + Zobrazení @@ -427,7 +427,7 @@ Vertical flip - Převrátit vertikálně + Převrátit svisle @@ -435,12 +435,12 @@ Loading... - + Nahrává se... Cancel - + Zrušit @@ -600,12 +600,12 @@ GIF and APNG only - + Pouze GIF a APNG Loop - + Smyčka @@ -684,7 +684,7 @@ MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) - + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) @@ -704,17 +704,17 @@ The path ("%1") points to a directory. - + Cesta ("%1") ukazuje na adresář. The directory ("%1") does not exist. - + Adresář ("%1") neexistuje. The path ("%1") is not writable. - + Cesta ("%1") není zapisovatelná. @@ -725,12 +725,12 @@ Failed to create directory "%1". Please make sure you have sufficient permissions. - + Nepodařilo se vytvořit adresář "%1". Ujistěte se, prosím, že máte dostatečná oprávnění. "%1" is a file. Please delete the file and try again. - + "%1" je soubor. Smažte, prosím, soubor a zkuste to znovu. @@ -742,7 +742,7 @@ An internal error occurred. Your file may not be saved successfully. - + Vyskytla se vnitřní chyba. Soubor se nemuselo podařit uložit úspěšně. @@ -797,7 +797,7 @@ [System-Language] First item of the language list - + [systémový jazyk] @@ -850,7 +850,7 @@ Hebrew - + Hebrejština @@ -860,7 +860,7 @@ Indonesian - + Indonésština @@ -875,7 +875,7 @@ Portuguese - Portugal - + Portugalština (Portugalsko) @@ -890,12 +890,12 @@ Slovenian - + Slovinština Vietnamese - + Větnamština @@ -1008,7 +1008,7 @@ Camera Layer - Vrstva kamery + Kamerová vrstva @@ -1278,7 +1278,7 @@ - + Play Přehrát @@ -1320,12 +1320,12 @@ Move - Posunout + Posun Select - Vybrat + Výběr @@ -1431,12 +1431,12 @@ Quick Reference Guide - + Rychlý odborný průvodce F1 - + F1 @@ -1448,7 +1448,7 @@ Previous KeyFrame - Předchozí Klíčový Snímek + Předchozí klíčový snímek @@ -1496,22 +1496,22 @@ Posunout snímek vzad - + color palette:<br>use <b>(C)</b><br>toggle at cursor Paleta barev:<br>použijte přepínač <b>(C)</b><br>na pozici kurzoru - + Lock Windows Zamknout okna - + Open Recent Otevřít nedávné - + You have successfully cleared the list @@ -1520,86 +1520,92 @@ Úspěšně jste vyprázdnil seznam - - - - + + + + + Warning Varování - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil není schopen přečíst tento soubor. Pokud chcete zavést obrázky, použijte příkaz Zavést. - + Opening document... Otevírám dokument... - - - + + + Abort Zrušit - + Saving document... Ukládám dokument... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: - + <br><br>Vyskytla se chyba, a tak soubor nemusí být úspěšně uložen. Pokud si myslíte, že potíže souvisí s Pencil2D, vytvořte, prosím, nové téma na:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Ujistěte se, prosím, že do záznamu o problému zahrnete následující podrobnosti: - + This animation has been modified. Do you want to save your changes? Tato animace byla změněna. Přejete si uložit změny? - + The animation is not saved yet. Do you want to save now? Animace ještě není uložena. Chcete ji uložit nyní? - + Never ask again AutoSave reminder button Už se znovu neptat - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Obrázek nelze zavést.<br><b>Rada:</b> K zavedení bitmap použijte bitmapovou vrstvu. - + Importing image sequence... - + Zavádí se řada obrázků... + + + + was unable to import + nebylo možno zavést - - + + Undo Menu item text - + Zpět - + Redo Menu item text - + Znovu - + Stop Zastavit @@ -1607,122 +1613,122 @@ Chcete ji uložit nyní? Object - + Black Černá - + Red Červená - + Dark Red Tmavě červená - + Orange Oranžová - + Dark Orange Tmavě oranžová - + Yellow Žlutá - + Dark Yellow Tmavě žlutá - + Green Zelená - + Dark Green Tmavě zelená - + Cyan Tyrkysová - + Dark Cyan Tmavě tyrkysová - + Blue Modrá - + Dark Blue Tmavě modrá - + White Bílá - + Very Light Grey Velmi světle šedá - + Light Grey Světle šedá - + Grey Šedá - + Dark Grey Tmavě šedá - + Light Skin Světle tělová - + Light Skin - shade Světle tělová - odstín - + Skin Tělová - + Skin - shade Tělová - odstín - + Dark Skin Tmavá tělová - + Dark Skin - shade Tmavě tělová - odstín @@ -1732,7 +1738,7 @@ Chcete ji uložit nyní? Pencil2D is an animation/drawing software for Mac OS X, Windows, and Linux. It lets you create traditional hand-drawn animation (cartoon) using both bitmap and vector graphics. - + Pencil2D je animační/kreslicí program pro operační systémy Mac OS X, Windows a Linux. Dovolí vám tvořit tradiční ručně kreslenou animaci pomocí bitmapové i vektorové grafiky @@ -1791,7 +1797,7 @@ Chcete ji uložit nyní? The last frame you want to include in the exported movie. Can also be last or last-sound to automatically use the last frame containing animation or sound, respectively - + Poslední snímek, který chcete zahrnout do vyvedeného obrazového záznamu. Také může být poslední nebo poslední-zvuk pro automatické použití posledního snímku obsahujícího animaci nebo zvuk, v tomto pořadí @@ -1811,22 +1817,22 @@ Chcete ji uložit nyní? Warning: start value %1 is not an integer, ignoring. - + Varování: Začáteční hodnota %1 není celé číslo. Přehlíží se. Warning: start value must be at least 1, ignoring. - + Varování: Začáteční hodnota musí být alespoň %1. Přehlíží se. Warning: end value %1 is not an integer, last or last-sound, ignoring. - + Varování: Koncová hodnota %1 není celé číslo, poslední nebo poslední-zvuk. Přehlíží se. Warning: end value %1 is smaller than start value %2, ignoring. - + Varování: Koncová hodnota %1 je menší než začáteční %2. Přehlíží se. @@ -1837,49 +1843,49 @@ Chcete ji uložit nyní? Error: the input file at '%1' does not exist Command line error - + Chyba: Vstupní soubor v '%1' neexistuje Error: the input path '%1' is not a file Command line error - + Chyba: Vstupní cesta '%1' není soubor Warning: the specified camera layer %1 was not found, ignoring. - + Varování: Daná kamerová vrstva %1 nebyla nalezena. Přehlíží se. Warning: Output format is not specified or unsupported. Using PNG. Command line warning - + Varování: Výstupní formát není stanoven nebo není podporován. Používá se PNG. - + Warning: Transparency is not currently supported in movie files Command line warning - + Varování: Průhlednost není v současnosti v souborech s obrazovým záznamem podporována. - + Exporting movie... Command line task progress - + Vyvádí se obrazový záznam... - - + + Done. Command line task done - + Hotovo. - + Exporting image sequence... Command line task progress - + Vyvádí se řada obrázků... @@ -1920,12 +1926,12 @@ Chcete ji uložit nyní? Checking environment... - + Prověřuje se prostředí... Done - + Hotovo @@ -1937,8 +1943,8 @@ Chcete ji uložit nyní? - Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - Obrázky (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) + Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + Obrázky (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) @@ -1981,1337 +1987,1337 @@ Chcete ji uložit nyní? Soubor s animací Pencil PCLX(*.pclx);;Starý soubor s animací Pencil PCL(*.pcl) - + Vivid Pink - + Jasná růžová - + Strong Pink - + Výrazná růžová - + Deep Pink Tmavě růžová - + Light Pink Světle růžová - + Moderate Pink - + Mírně růžová - + Dark Pink - + Tmavá růžová - + Pale Pink - + Světlá růžová - + Grayish Pink - + Šedavá růžová - + Pinkish White - + Narůžovělá bílá - + Pinkish Gray - + Narůžovělá šedá - + Vivid Red - + Jasná červená - + Strong Red - + Výrazná červená - + Deep Red Tmavě červená - + Very Deep Red - + Velice sytá červená - + Moderate Red - + Nevýrazná červená - + Dark Red Tmavě červená - + Very Dark Red - + Velice tmavá červená - + Light Grayish Red - + Světle šedavá červená - + Grayish Red - + Šedavá červená - + Dark Grayish Red - + Tmavá šedavá červená - + Blackish Red - + Černavá červená - + Reddish Gray - + Červenavá šedá - + Dark Reddish Gray - + Tmavá červenavá šedá - + Reddish Black - + Červenavá černá - + Vivid Yellowish Pink - + Jasná žlutavá růžová - + Strong Yellowish Pink - + Výrazná žlutavá růžová - + Deep Yellowish Pink - + Sytá žlutavá růžová - + Light Yellowish Pink - + Světlá žlutavá růžová - + Moderate Yellowish Pink - + Nevýrazná žlutavá růžová - + Dark Yellowish Pink - + Tmavá žlutavá růžová - + Pale Yellowish Pink - + Bledá žlutavá růžová - + Grayish Yellowish Pink - + Šedavá žlutavá růžová - + Brownish Pink - + Hnědavá růžová - + Vivid Reddish Orange - + Jasná červenavá oranžová - + Strong Reddish Orange - + Deep Reddish Orange - + Moderate Reddish Orange - + Dark Reddish Orange - + Grayish Reddish Orange - + Strong Reddish Brown - + Deep Reddish Brown - + Light Reddish Brown - + Moderate Reddish Brown - + Dark Reddish Brown - + Light Grayish Reddish Brown - + Grayish Reddish Brown - + Dark Grayish Reddish Brown - + Vivid Orange - + Jasná oranžová - + Brilliant Orange - + Strong Orange - + Deep Orange - + Light Orange - + Moderate Orange - + Brownish Orange - + Strong Brown - + Deep Brown - + Light Brown - + Moderate Brown - + Dark Brown - + Light Grayish Brown - + Grayish Brown - + Dark Grayish Brown - + Light Brownish Gray - + Brownish Gray - + Brownish Black - + Vivid Orange Yellow - + Jasná oranžovožlutá - + Brilliant Orange Yellow - + Strong Orange Yellow - + Deep Orange Yellow - + Light Orange Yellow - + Moderate Orange Yellow - + Dark Orange Yellow - + Pale Orange Yellow - + Strong Yellowish Brown - + Deep Yellowish Brown - + Light Yellowish Brown - + Moderate Yellowish Brown - + Dark Yellowish Brown - + Light Grayish Yellowish Brown - + Grayish Yellowish Brown - + Dark Grayish Yellowish Brown - + Vivid Yellow - + Jasná žlutá - + Brilliant Yellow - + Strong Yellow - + Deep Yellow - + Light Yellow - + Moderate Yellow - + Dark Yellow - + Pale Yellow - + Grayish Yellow - + Dark Grayish Yellow - + Yellowish White - + Yellowish Gray - + Light Olive Brown - + Moderate Olive Brown - + Dark Olive Brown - + Vivid Greenish Yellow - + Jasná šedavá žlutá - + Brilliant Greenish Yellow - + Strong Greenish Yellow - + Deep Greenish Yellow - + Light Greenish Yellow - + Moderate Greenish Yellow - + Dark Greenish Yellow - + Pale Greenish Yellow - + Grayish Greenish Yellow - + Light Olive - + Moderate Olive - + Dark Olive - + Light Grayish Olive - + Grayish Olive - + Dark Grayish Olive - + Light Olive Gray - + Olive Gray - + Olive Black - + Vivid Yellow Green - + Jasná žlutozelená - + Brilliant Yellow Green - + Strong Yellow Green - + Deep Yellow Green - + Light Yellow Green - + Moderate Yellow Green - + Pale Yellow Green - + Grayish Yellow Green - + Strong Olive Green - + Deep Olive Green - + Moderate Olive Green - + Dark Olive Green - + Grayish Olive Green - + Dark Grayish Olive Green - + Vivid Yellowish Green - + Jasná žlutavá zelená - + Brilliant Yellowish Green - + Strong Yellowish Green - + Deep Yellowish Green - + Very Deep Yellowish Green - + Very Light Yellowish Green - + Light Yellowish Green - + Moderate Yellowish Green - + Dark Yellowish Green - + Very Dark Yellowish Green - + Vivid Green - + Jasná zelená - + Brilliant Green - + Strong Green - + Deep Green - + Very Light Green - + Light Green - + Moderate Green - + Dark Green - + Very Dark Green - + Very Pale Green - + Pale Green - + Grayish Green - + Dark Grayish Green - + Blackish Green - + Greenish White - + Light Greenish Gray - + Greenish Gray - + Dark Greenish Gray - + Greenish Black - + Vivid Bluish Green - + Jasná modravá zelená - + Brilliant Bluish Green - + Strong Bluish Green - + Deep Bluish Green - + Very Light Bluish Green - + Light Bluish Green - + Moderate Bluish Green - + Dark Bluish Green - + Very Dark Bluish Green - + Vivid Greenish Blue - + Jasná šedavá modrá - + Brilliant Greenish Blue - + Strong Greenish Blue - + Deep Greenish Blue - + Very Light Greenish Blue - + Light Greenish Blue - + Moderate Greenish Blue - + Dark Greenish Blue - + Very Dark Greenish Blue - + Vivid Blue - + Jasná modrá - + Brilliant Blue - + Strong Blue - + Deep Blue - + Very Light Blue - + Light Blue - + Moderate Blue - + Dark Blue - + Very Pale Blue - + Pale Blue - + Grayish Blue - + Dark Grayish Blue - + Blackish Blue - + Bluish White - + Light Bluish Gray - + Bluish Gray - + Dark Bluish Gray - + Bluish Black - + Vivid Purplish Blue - + Jasná nafialovělá modrá - + Brilliant Purplish Blue - + Strong Purplish Blue - + Deep Purplish Blue - + Very Light Purplish Blue - + Light Purplish Blue - + Moderate Purplish Blue - + Dark Purplish Blue - + Very Pale Purplish Blue - + Pale Purplish Blue - + Grayish Purplish Blue - + Vivid Violet - + Jasná fialová - + Brilliant Violet - + Strong Violet - + Deep Violet - + Very Light Violet - + Light Violet - + Moderate Violet - + Dark Violet - + Very Pale Violet - + Pale Violet - + Grayish Violet - + Vivid Purple - + Jasná nachová - + Brilliant Purple - + Strong Purple - + Deep Purple - + Very Deep Purple - + Very Light Purple - + Light Purple - + Moderate Purple - + Dark Purple - + Very Dark Purple - + Very Pale Purple - + Pale Purple - + Grayish Purple - + Dark Grayish Purple - + Blackish Purple - + Purplish White - + Light Purplish Gray - + Purplish Gray - + Dark Purplish Gray - + Purplish Black - + Vivid Reddish Purple - + Jasná červenavá nachová - + Strong Reddish Purple - + Deep Reddish Purple - + Very Deep Reddish Purple - + Light Reddish Purple - + Moderate Reddish Purple - + Dark Reddish Purple - + Very Dark Reddish Purple - + Pale Reddish Purple - + Grayish Reddish Purple - + Brilliant Purplish Pink - + Strong Purplish Pink - + Deep Purplish Pink - + Light Purplish Pink - + Moderate Purplish Pink - + Dark Purplish Pink - + Pale Purplish Pink - + Grayish Purplish Pink - + Vivid Purplish Red - + Jasná nafialovělá červená - + Strong Purplish Red - + Deep Purplish Red - + Very Deep Purplish Red - + Moderate Purplish Red - + Dark Purplish Red - + Very Dark Purplish Red - + Light Grayish Purplish Red - + Grayish Purplish Red - + White Bílá - + Light Gray Světle šedá - + Medium Gray Středně šedá - + Dark Gray Tmavě šedá - + Black Černá @@ -3332,60 +3338,60 @@ Chcete ji uložit nyní? ScribbleArea - + Warning Varování - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Kreslíte na skrytou vrstvu! Vyberte, prosím, jinou vrstvu (nebo nynější vrstvu udělejte viditelnou). - + Delete Selection Undo Step: clear the selection area. Smazat výběr - - + + Clear Image Undo step text Smazat obrázek - + There is a gap in your drawing (or maybe you have zoomed too much). Ve vaší kresbě je mezera (nebo jste možná provedl moc velké přiblížení). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). - + Out of bound. Zakázáno. - + Could not find a closed path. Nepodařilo se najít zavřenou cestu. - + Could not find the root index. Nepodařilo se najít kořenový index. - + %1<br><br>Error: %2 %1<br><br>Chyba: %2 - + Flood fill error Chyba výplně @@ -3400,7 +3406,7 @@ Chcete ji uložit nyní? Action: - Akce: + Činnost: @@ -3590,12 +3596,12 @@ Chcete ji uložit nyní? TimeLineCells - + Layer Properties Vlastnosti vrstvy - + Layer name: Název vrstvy: @@ -3630,6 +3636,46 @@ Chcete ji uložit nyní? Timeline length: Preferences + Délka časové osy + + + + Drawing + + + + + When drawing on an empty frame: + + + + + Create a new (blank) key-frame and start drawing on it. + + + + + Create a new (blank) key-frame + + + + + Duplicate the previous key-frame and start drawing on the duplicate. + + + + + Duplicate the previous key-frame + + + + + Keep drawing on the previous key-frame + + + + + <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> @@ -3654,52 +3700,52 @@ Chcete ji uložit nyní? Pencil Tool (%1): Sketch with pencil - Nástroj tužky (%1): Dělání náčrtků tužkou + Nástroj tužka (%1): Dělání náčrtků tužkou Select Tool (%1): Select an object - Nástroj výběru (%1): Výběr předmětu + Nástroj pro výběr (%1): Výběr předmětu Move Tool (%1): Move an object - Nástroj přesunu (%1): Posunutí předmětu + Nástroj pro přesun (%1): Posunutí předmětu Hand Tool (%1): Move the canvas - Nástroj ruky (%1): Posunutí plátna + Nástroj ručka (%1): Posunutí plátna Pen Tool (%1): Sketch with pen - Nástroj pera (%1): Dělání náčrtků perem + Nástroj pero (%1): Dělání náčrtků perem Eraser Tool (%1): Erase - Nástroj gumy (%1): Vymazání + Nástroj guma (%1): Vymazání Polyline Tool (%1): Create line/curves - Nástroj lomené čáry (%1): vytváření čar/křivek + Nástroj lomená čára (%1): Vytváření čar/křivek Paint Bucket Tool (%1): Fill selected area with a color - Nástroj plechovky s barvou (%1): vyplnění vybrané oblasti barvou + Nástroj plechovka s barvou (%1): Vyplnění vybrané oblasti barvou Brush Tool (%1): Paint smooth stroke with a brush - Nástroj štětce (%1): Malování hladkých tahů štětcem + Nástroj štětec (%1): Malování hladkých tahů štětcem Eyedropper Tool (%1): Set color from the stage<br>[ALT] for instant access - Nástroj kapátka (%1): Nastavení barvy ze scény<br>[ALT] pro okamžitý přístup + Nástroj kapátko (%1): Nastavení barvy ze scény<br>[ALT] pro okamžitý přístup @@ -3709,57 +3755,57 @@ Chcete ji uložit nyní? Smudge Tool (%1):<br>Edit polyline/curves<br>Liquify bitmap pixels<br> (%1)+[Alt]: Smooth - Nástroj šmouhy (%1):<br>Upravit lomenou čáru/křivku<br>Zkapalnit obrazové body bitmapy<br> (%1)+[Alt]: Vyhladit + Nástroj šmouha (%1):<br>Upravit lomenou čáru/křivku<br>Zkapalnit obrazové body bitmapy<br> (%1)+[Alt]: Vyhladit Pencil Tool (%1) - Nástroj tužky (%1) + Nástroj tužka (%1) Select Tool (%1) - Nástroj výběru (%1) + Nástroj pro výběr (%1) Move Tool (%1) - Nástroj přesunu (%1) + Nástroj pro přesun (%1) Hand Tool (%1) - Nástroj ruky (%1) + Nástroj ručka (%1) Pen Tool (%1) - Nástroj pera (%1) + Nástroj pero (%1) Eraser Tool (%1) - Nástroj gumy (%1) + Nástroj guma (%1) Polyline Tool (%1) - Nástroj lomené čáry (%1) + Nástroj lomená čára (%1) Paint Bucket Tool (%1) - Nástroj plechovky s barvou (%1) + Nástroj plechovka s barvou (%1) Brush Tool (%1) - Nástroj štětce (%1) + Nástroj štětec (%1) Eyedropper Tool (%1) - Nástroj kapátka (%1) + Nástroj kapátko (%1) @@ -3769,7 +3815,7 @@ Chcete ji uložit nyní? Smudge Tool (%1) - Nástroj šmouhy (%1) + Nástroj šmouha (%1) @@ -3857,7 +3903,7 @@ Chcete ji uložit nyní? Pressure Brush - + Tlak @@ -3917,7 +3963,7 @@ Chcete ji uložit nyní? Stabilizer - + Ustalovač diff --git a/translations/pencil_da.ts b/translations/pencil_da.ts index 709cdf069..ce72e57ad 100644 --- a/translations/pencil_da.ts +++ b/translations/pencil_da.ts @@ -148,57 +148,57 @@ BaseTool - + Pencil Blyant - + Eraser Viskelæder - + Select Marker - + Move Bevæg - + Hand Hånd - + Smudge Udtvær - + Pen Fyldepen - + Polyline Linje - + Bucket Malerspand - + Eyedropper Pipette - + Brush Pensel @@ -360,8 +360,8 @@ ColorPaletteWidget - - + + Colour name Farve navn @@ -1278,7 +1278,7 @@ - + Play Afspil @@ -1496,106 +1496,112 @@ - + color palette:<br>use <b>(C)</b><br>toggle at cursor farve palet:<br>tryk på <b>(C)</b><br>Slå til/fra ved markøren - + Lock Windows - + Open Recent Åben Seneste - + You have successfully cleared the list - - - - + + + + + Warning Advarsel - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil kan ikke læse denne fil. hvis du vil importere billeder, brug kommandoen importer. - + Opening document... Åbner dokument... - - - + + + Abort Om - + Saving document... Gemmer dokument... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: - + This animation has been modified. Do you want to save your changes? - + The animation is not saved yet. Do you want to save now? - + Never ask again AutoSave reminder button - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. - + Importing image sequence... - - + + was unable to import + + + + + Undo Menu item text - + Redo Menu item text - + Stop @@ -1603,122 +1609,122 @@ Object - + Black Sort - + Red Rød - + Dark Red Mørkerød - + Orange Orange - + Dark Orange Mørke Orange - + Yellow Gul - + Dark Yellow Mørkegul - + Green Grøn - + Dark Green Mørkegrøn - + Cyan Turkis - + Dark Cyan Mørke turkis - + Blue Blå - + Dark Blue Mørkeblå - + White Hvid - + Very Light Grey Meget Lysegrå - + Light Grey Lysegrå - + Grey Grå - + Dark Grey Mørkegrå - + Light Skin Lys hud - + Light Skin - shade Lys hyd - skygge - + Skin Hud - + Skin - shade Hud - skygge - + Dark Skin Mørk Hud - + Dark Skin - shade Mørk Hud - skygge @@ -1853,26 +1859,26 @@ - + Warning: Transparency is not currently supported in movie files Command line warning - + Exporting movie... Command line task progress - - + + Done. Command line task done - + Exporting image sequence... Command line task progress @@ -1933,7 +1939,7 @@ - Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) + Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) @@ -1977,1337 +1983,1337 @@ - + Vivid Pink - + Strong Pink - + Deep Pink - + Light Pink - + Moderate Pink - + Dark Pink - + Pale Pink - + Grayish Pink - + Pinkish White - + Pinkish Gray - + Vivid Red - + Strong Red - + Deep Red - + Very Deep Red - + Moderate Red - + Dark Red - + Very Dark Red - + Light Grayish Red - + Grayish Red - + Dark Grayish Red - + Blackish Red - + Reddish Gray - + Dark Reddish Gray - + Reddish Black - + Vivid Yellowish Pink - + Strong Yellowish Pink - + Deep Yellowish Pink - + Light Yellowish Pink - + Moderate Yellowish Pink - + Dark Yellowish Pink - + Pale Yellowish Pink - + Grayish Yellowish Pink - + Brownish Pink - + Vivid Reddish Orange - + Strong Reddish Orange - + Deep Reddish Orange - + Moderate Reddish Orange - + Dark Reddish Orange - + Grayish Reddish Orange - + Strong Reddish Brown - + Deep Reddish Brown - + Light Reddish Brown - + Moderate Reddish Brown - + Dark Reddish Brown - + Light Grayish Reddish Brown - + Grayish Reddish Brown - + Dark Grayish Reddish Brown - + Vivid Orange - + Brilliant Orange - + Strong Orange - + Deep Orange - + Light Orange - + Moderate Orange - + Brownish Orange - + Strong Brown - + Deep Brown - + Light Brown - + Moderate Brown - + Dark Brown - + Light Grayish Brown - + Grayish Brown - + Dark Grayish Brown - + Light Brownish Gray - + Brownish Gray - + Brownish Black - + Vivid Orange Yellow - + Brilliant Orange Yellow - + Strong Orange Yellow - + Deep Orange Yellow - + Light Orange Yellow - + Moderate Orange Yellow - + Dark Orange Yellow - + Pale Orange Yellow - + Strong Yellowish Brown - + Deep Yellowish Brown - + Light Yellowish Brown - + Moderate Yellowish Brown - + Dark Yellowish Brown - + Light Grayish Yellowish Brown - + Grayish Yellowish Brown - + Dark Grayish Yellowish Brown - + Vivid Yellow - + Brilliant Yellow - + Strong Yellow - + Deep Yellow - + Light Yellow - + Moderate Yellow - + Dark Yellow - + Pale Yellow - + Grayish Yellow - + Dark Grayish Yellow - + Yellowish White - + Yellowish Gray - + Light Olive Brown - + Moderate Olive Brown - + Dark Olive Brown - + Vivid Greenish Yellow - + Brilliant Greenish Yellow - + Strong Greenish Yellow - + Deep Greenish Yellow - + Light Greenish Yellow - + Moderate Greenish Yellow - + Dark Greenish Yellow - + Pale Greenish Yellow - + Grayish Greenish Yellow - + Light Olive - + Moderate Olive - + Dark Olive - + Light Grayish Olive - + Grayish Olive - + Dark Grayish Olive - + Light Olive Gray - + Olive Gray - + Olive Black - + Vivid Yellow Green - + Brilliant Yellow Green - + Strong Yellow Green - + Deep Yellow Green - + Light Yellow Green - + Moderate Yellow Green - + Pale Yellow Green - + Grayish Yellow Green - + Strong Olive Green - + Deep Olive Green - + Moderate Olive Green - + Dark Olive Green - + Grayish Olive Green - + Dark Grayish Olive Green - + Vivid Yellowish Green - + Brilliant Yellowish Green - + Strong Yellowish Green - + Deep Yellowish Green - + Very Deep Yellowish Green - + Very Light Yellowish Green - + Light Yellowish Green - + Moderate Yellowish Green - + Dark Yellowish Green - + Very Dark Yellowish Green - + Vivid Green - + Brilliant Green - + Strong Green - + Deep Green - + Very Light Green - + Light Green - + Moderate Green - + Dark Green - + Very Dark Green - + Very Pale Green - + Pale Green - + Grayish Green - + Dark Grayish Green - + Blackish Green - + Greenish White - + Light Greenish Gray - + Greenish Gray - + Dark Greenish Gray - + Greenish Black - + Vivid Bluish Green - + Brilliant Bluish Green - + Strong Bluish Green - + Deep Bluish Green - + Very Light Bluish Green - + Light Bluish Green - + Moderate Bluish Green - + Dark Bluish Green - + Very Dark Bluish Green - + Vivid Greenish Blue - + Brilliant Greenish Blue - + Strong Greenish Blue - + Deep Greenish Blue - + Very Light Greenish Blue - + Light Greenish Blue - + Moderate Greenish Blue - + Dark Greenish Blue - + Very Dark Greenish Blue - + Vivid Blue - + Brilliant Blue - + Strong Blue - + Deep Blue - + Very Light Blue - + Light Blue - + Moderate Blue - + Dark Blue - + Very Pale Blue - + Pale Blue - + Grayish Blue - + Dark Grayish Blue - + Blackish Blue - + Bluish White - + Light Bluish Gray - + Bluish Gray - + Dark Bluish Gray - + Bluish Black - + Vivid Purplish Blue - + Brilliant Purplish Blue - + Strong Purplish Blue - + Deep Purplish Blue - + Very Light Purplish Blue - + Light Purplish Blue - + Moderate Purplish Blue - + Dark Purplish Blue - + Very Pale Purplish Blue - + Pale Purplish Blue - + Grayish Purplish Blue - + Vivid Violet - + Brilliant Violet - + Strong Violet - + Deep Violet - + Very Light Violet - + Light Violet - + Moderate Violet - + Dark Violet - + Very Pale Violet - + Pale Violet - + Grayish Violet - + Vivid Purple - + Brilliant Purple - + Strong Purple - + Deep Purple - + Very Deep Purple - + Very Light Purple - + Light Purple - + Moderate Purple - + Dark Purple - + Very Dark Purple - + Very Pale Purple - + Pale Purple - + Grayish Purple - + Dark Grayish Purple - + Blackish Purple - + Purplish White - + Light Purplish Gray - + Purplish Gray - + Dark Purplish Gray - + Purplish Black - + Vivid Reddish Purple - + Strong Reddish Purple - + Deep Reddish Purple - + Very Deep Reddish Purple - + Light Reddish Purple - + Moderate Reddish Purple - + Dark Reddish Purple - + Very Dark Reddish Purple - + Pale Reddish Purple - + Grayish Reddish Purple - + Brilliant Purplish Pink - + Strong Purplish Pink - + Deep Purplish Pink - + Light Purplish Pink - + Moderate Purplish Pink - + Dark Purplish Pink - + Pale Purplish Pink - + Grayish Purplish Pink - + Vivid Purplish Red - + Strong Purplish Red - + Deep Purplish Red - + Very Deep Purplish Red - + Moderate Purplish Red - + Dark Purplish Red - + Very Dark Purplish Red - + Light Grayish Purplish Red - + Grayish Purplish Red - + White - + Light Gray - + Medium Gray - + Dark Gray - + Black @@ -3328,60 +3334,60 @@ ScribbleArea - + Warning Advarsel - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Du tegner på et usynligt lag!, Vær venlig at vælge et andet lag (eller lav det nuværende lag synligt). - + Delete Selection Undo Step: clear the selection area. - - + + Clear Image Undo step text - + There is a gap in your drawing (or maybe you have zoomed too much). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). - + Out of bound. - + Could not find a closed path. - + Could not find the root index. - + %1<br><br>Error: %2 - + Flood fill error Fejl ved Oversvømmelses fyldning @@ -3586,12 +3592,12 @@ TimeLineCells - + Layer Properties - + Layer name: @@ -3628,6 +3634,46 @@ Preferences + + + Drawing + + + + + When drawing on an empty frame: + + + + + Create a new (blank) key-frame and start drawing on it. + + + + + Create a new (blank) key-frame + + + + + Duplicate the previous key-frame and start drawing on the duplicate. + + + + + Duplicate the previous key-frame + + + + + Keep drawing on the previous key-frame + + + + + <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + Frame size diff --git a/translations/pencil_de.ts b/translations/pencil_de.ts index da97d6f2f..202736217 100644 --- a/translations/pencil_de.ts +++ b/translations/pencil_de.ts @@ -148,57 +148,57 @@ BaseTool - + Pencil Bleistift - + Eraser Radierer - + Select Auswahl - + Move Verschieben - + Hand Hand - + Smudge Verwischen - + Pen Stift - + Polyline Polygonzug - + Bucket Fülleimer - + Eyedropper Pipette - + Brush Pinsel @@ -360,8 +360,8 @@ ColorPaletteWidget - - + + Colour name Name der Farbe @@ -1278,7 +1278,7 @@ - + Play Abspielen @@ -1496,22 +1496,22 @@ - + color palette:<br>use <b>(C)</b><br>toggle at cursor Farbpalette: <br><b>(C)</b><br>An Zeigerposition umschalten - + Lock Windows Fenster sperren - + Open Recent Zuletzt geöffnet - + You have successfully cleared the list @@ -1520,86 +1520,92 @@ Sie haben die Liste erfolgreich geleert - - - - + + + + + Warning Warnung - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil kann die Datei nicht lesen. Wenn Sie Bilder importieren möchten, benutzen sie die Importfunktion. - + Opening document... Dokument wird geöffnet... - - - + + + Abort Abbrechen - + Saving document... Dokument wird gespeichert... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>Ein Fehler ist aufgetreten und Ihre Datei wurde womöglich nicht erfolgreich gespeichert. Falls Sie glauben, dass es sich hierbei um einen Programmfehler in Pencil2D handelt, erstellen Sie bitte auf Englisch eine neue Meldung unter:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Bitte fügen Sie Ihrer Meldung unbedingt die folgenden Details bei: - + This animation has been modified. Do you want to save your changes? Diese Animation wurde geändert. Möchten Sie Ihre Änderungen speichern? - + The animation is not saved yet. Do you want to save now? Die Animation wurde noch nicht gespeichert. Möchten Sie sie jetzt speichern? - + Never ask again AutoSave reminder button Nicht mehr fragen - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Bild kann nicht importiert werden.<br><b>TIPP:</b> Verwenden Sie eine Rasterebene um Rasterbilder zu importieren. - + Importing image sequence... - - + + was unable to import + + + + + Undo Menu item text - + Redo Menu item text - + Stop @@ -1607,125 +1613,125 @@ Sie haben die Liste erfolgreich geleert Object - + Black Schwarz - + Red Rot - + Dark Red Dunkelrot - + Orange Orange - + Dark Orange Dunkelorange - + Yellow Gelb - + Dark Yellow Dunkelgelb - + Green Grün - + Dark Green Dunkelgrün - + Cyan Cyan - + Dark Cyan Dunkelcyan - + Blue Blau - + Dark Blue Dunkelblau - + White Weiß - + Very Light Grey Sehr helles Grau - + Light Grey Hellgrau - + Grey Grau - + Dark Grey Dunkelgrau - + Light Skin Helle Hautfarbe - + Light Skin - shade Helle Hautfarbe – Schatten - + Skin Hautfarbe - + Skin - shade Hautfarbe – Schatten - + Dark Skin Dunkle Hautfarbe - + Dark Skin - shade Dunkle Hautfarbe – Schatten @@ -1860,26 +1866,26 @@ Sie haben die Liste erfolgreich geleert - + Warning: Transparency is not currently supported in movie files Command line warning - + Exporting movie... Command line task progress - - + + Done. Command line task done - + Exporting image sequence... Command line task progress @@ -1940,8 +1946,8 @@ Sie haben die Liste erfolgreich geleert - Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - Bilder (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) + Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + @@ -1984,1337 +1990,1337 @@ Sie haben die Liste erfolgreich geleert Pencil-Animationsdatei PCLX(*.pclx);;Alte Pencil-Animationsdatei PCL(*.pcl) - + Vivid Pink Lebhaftes Rosa - + Strong Pink Kräftiges Rosa - + Deep Pink Tiefrosa - + Light Pink Hellrosa - + Moderate Pink Gemäßigtes Rosa - + Dark Pink Dunkelrosa - + Pale Pink Blassrosa - + Grayish Pink Graurosa - + Pinkish White Rosaweiß - + Pinkish Gray Rosagrau - + Vivid Red Lebhaftes Rot - + Strong Red Kräftiges Rot - + Deep Red Tiefrot - + Very Deep Red Sehr tiefes Rot - + Moderate Red Gemäßigtes Rot - + Dark Red Dunkelrot - + Very Dark Red Sehr dunkles Rot - + Light Grayish Red Helles Graurot - + Grayish Red Graurot - + Dark Grayish Red Dunkles Graurot - + Blackish Red Schwarzrot - + Reddish Gray Rotgrau - + Dark Reddish Gray Dunkles Rotgrau - + Reddish Black Rotschwarz - + Vivid Yellowish Pink Lebhaftes Gelbrosa - + Strong Yellowish Pink Kräftiges Gelbrosa - + Deep Yellowish Pink Tiefes Gelbrosa - + Light Yellowish Pink Helles Gelbrosa - + Moderate Yellowish Pink Gemäßigtes Gelbrosa - + Dark Yellowish Pink Dunkles Gelbrosa - + Pale Yellowish Pink Blasses Gelbrosa - + Grayish Yellowish Pink Gräuliches Gelbrosa - + Brownish Pink Braunrosa - + Vivid Reddish Orange Lebhaftes Rotorange - + Strong Reddish Orange Kräftiges Rotorange - + Deep Reddish Orange Tiefes Rotorange - + Moderate Reddish Orange Gemäßigtes Rotorange - + Dark Reddish Orange Dunkles Rotorange - + Grayish Reddish Orange Gräuliches Rotorange - + Strong Reddish Brown Kräftiges Rotbraun - + Deep Reddish Brown Tiefes Rotbraun - + Light Reddish Brown Helles Rotbraun - + Moderate Reddish Brown Gemäßigtes Rotbraun - + Dark Reddish Brown Dunkles Rotbraun - + Light Grayish Reddish Brown Hellgraurotbraun - + Grayish Reddish Brown Graurotbraun - + Dark Grayish Reddish Brown Dunkelgraurotbraun - + Vivid Orange Lebhaftes Orange - + Brilliant Orange Leuchtendes Orange - + Strong Orange Kräftiges Orange - + Deep Orange Tieforange - + Light Orange Hellorange - + Moderate Orange Gemäßigtes Orange - + Brownish Orange Braunorange - + Strong Brown Kräftiges Orange - + Deep Brown Tiefbraun - + Light Brown Hellbraun - + Moderate Brown Gemäßigtes Braun - + Dark Brown Dunkelbraun - + Light Grayish Brown Hellgraubraun - + Grayish Brown Graubraun - + Dark Grayish Brown Dunkelgraubraun - + Light Brownish Gray Hellbraungrau - + Brownish Gray Braungrau - + Brownish Black Braunschwarz - + Vivid Orange Yellow Lebhaftes Orangegelb - + Brilliant Orange Yellow Leuchtendes Orangegelb - + Strong Orange Yellow Kräftiges Orangegelb - + Deep Orange Yellow Tieforangegelb - + Light Orange Yellow Hellorangegelb - + Moderate Orange Yellow Gemäßigtes Orangegelb - + Dark Orange Yellow Dunkelorangegelb - + Pale Orange Yellow Blassorangegelb - + Strong Yellowish Brown Kräftiges Gelbbraun - + Deep Yellowish Brown Tiefgelbbraun - + Light Yellowish Brown Hellgelbbraun - + Moderate Yellowish Brown Gemäßigtes Gelbbraun - + Dark Yellowish Brown Dunkelgelbbraun - + Light Grayish Yellowish Brown Hellgraugelbbraun - + Grayish Yellowish Brown Graugelbbraun - + Dark Grayish Yellowish Brown Dunkelgraugelbbraun - + Vivid Yellow Lebhaftes Gelb - + Brilliant Yellow Leuchtendes Gelb - + Strong Yellow Kräftiges Gelb - + Deep Yellow Tiefgelb - + Light Yellow Hellgelb - + Moderate Yellow Gemäßigtes Gelb - + Dark Yellow Dunkelgelb - + Pale Yellow Blassgelb - + Grayish Yellow Graugelb - + Dark Grayish Yellow Dunkelgraugelb - + Yellowish White Gelbweiß - + Yellowish Gray Gelbgrau - + Light Olive Brown Hellolivbraun - + Moderate Olive Brown Gemäßigtes Olivbraun - + Dark Olive Brown Dunkelolivbraun - + Vivid Greenish Yellow Lebhaftes Grüngelb - + Brilliant Greenish Yellow Leuchtendes Grüngelb - + Strong Greenish Yellow Kräftiges Grüngelb - + Deep Greenish Yellow Tiefgrüngelb - + Light Greenish Yellow Hellgrüngelb - + Moderate Greenish Yellow Gemäßigtes Grüngelb - + Dark Greenish Yellow Dunkelgrüngelb - + Pale Greenish Yellow Blassgrüngelb - + Grayish Greenish Yellow Graugrüngelb - + Light Olive Helloliv - + Moderate Olive Gemäßigtes Oliv - + Dark Olive Dunkeloliv - + Light Grayish Olive Hellgrauoliv - + Grayish Olive Grauoliv - + Dark Grayish Olive Dunkelgrauoliv - + Light Olive Gray Hellolivgrau - + Olive Gray Olivgrau - + Olive Black Olivschwarz - + Vivid Yellow Green Lebhaftes Gelbgrün - + Brilliant Yellow Green Leuchtendes Gelbgrün - + Strong Yellow Green Kräftiges Gelbgrün - + Deep Yellow Green Tiefgelbgrün - + Light Yellow Green Hellgelbgrün - + Moderate Yellow Green Gemäßigtes Gelbgrün - + Pale Yellow Green Blassgelbgrün - + Grayish Yellow Green Graugelbgrün - + Strong Olive Green Kräftiges Olivgrün - + Deep Olive Green Tiefolivgrün - + Moderate Olive Green Gemäßigtes Olivgrün - + Dark Olive Green Dunkelolivgrün - + Grayish Olive Green Grauolivgrün - + Dark Grayish Olive Green Dunkelgrauolivgrün - + Vivid Yellowish Green Lebhaftes Gelbgrün - + Brilliant Yellowish Green Leuchtendes Gelbgrün - + Strong Yellowish Green Kräftiges Gelbgrün - + Deep Yellowish Green Tiefgelbgrün - + Very Deep Yellowish Green Sehr tiefes Gelbgrün - + Very Light Yellowish Green Sehr helles Gelbgrün - + Light Yellowish Green Hellgelbgrün - + Moderate Yellowish Green Gemäßigtes Gelbgrün - + Dark Yellowish Green Dunkelgelbgrün - + Very Dark Yellowish Green Sehr dunkles Gelbgrün - + Vivid Green Lebhaftes Grün - + Brilliant Green Leuchtendes Grün - + Strong Green Kräftiges Grün - + Deep Green Tiefgrün - + Very Light Green Sehr helles Grün - + Light Green Hellgrün - + Moderate Green Gemäßigtes Grün - + Dark Green Dunkelgrün - + Very Dark Green Sehr dunkles Grün - + Very Pale Green Sehr blasses grün - + Pale Green Blassgrün - + Grayish Green Graugrün - + Dark Grayish Green Dunkelgraugrün - + Blackish Green Schwarzgrün - + Greenish White Grünweiß - + Light Greenish Gray Hellgrünweiß - + Greenish Gray Grüngrau - + Dark Greenish Gray Dunkelgrüngrau - + Greenish Black Grünschwarz - + Vivid Bluish Green Lebhaftes Blaugrün - + Brilliant Bluish Green Leuchtendes Blaugrün - + Strong Bluish Green Kräftiges Blaugrün - + Deep Bluish Green Tiefblaugrün - + Very Light Bluish Green Sehr helles Blaugrün - + Light Bluish Green Hellblaugrün - + Moderate Bluish Green Gemäßigtes Blaugrün - + Dark Bluish Green Dunkelblaugrün - + Very Dark Bluish Green Sehr dunkles Blaugrün - + Vivid Greenish Blue Lebhaftes Grünblau - + Brilliant Greenish Blue Leuchtendes Grünblau - + Strong Greenish Blue Kräftiges Grünblau - + Deep Greenish Blue Tiefgrünblau - + Very Light Greenish Blue Sehr helles Grünblau - + Light Greenish Blue Hellgrünblau - + Moderate Greenish Blue Gemäßigtes Grünblau - + Dark Greenish Blue Dunkelgrünblau - + Very Dark Greenish Blue Sehr dunkles Grünblau - + Vivid Blue Lebhaftes Blau - + Brilliant Blue Leuchtendes Blau - + Strong Blue Kräftiges Blau - + Deep Blue Tiefblau - + Very Light Blue Sehr helles Blau - + Light Blue Hellblau - + Moderate Blue Gemäßigtes Blau - + Dark Blue Dunkelblau - + Very Pale Blue Sehr blasses Blau - + Pale Blue Blassblau - + Grayish Blue Graublau - + Dark Grayish Blue Dunkelgraublau - + Blackish Blue Schwarzblau - + Bluish White Blauweiß - + Light Bluish Gray Hellblaugrau - + Bluish Gray Blaugrau - + Dark Bluish Gray Dunkelblaugrau - + Bluish Black Blauschwarz - + Vivid Purplish Blue Lebhaftes Purpurblau - + Brilliant Purplish Blue Leuchtendes Purpurblau - + Strong Purplish Blue Kräftiges Purpurblau - + Deep Purplish Blue Dunkelpurpurblau - + Very Light Purplish Blue Sehr helles Purpurblau - + Light Purplish Blue Hellpurpurblau - + Moderate Purplish Blue Gemäßigtes Purpurblau - + Dark Purplish Blue Dunkelpurpurblau - + Very Pale Purplish Blue Sehr blasses Purpurblau - + Pale Purplish Blue Blasspurpurblau - + Grayish Purplish Blue Graupurpurblau - + Vivid Violet Lebhaftes Violett - + Brilliant Violet Leuchtendes Violett - + Strong Violet Kräftiges Violett - + Deep Violet Tiefviolett - + Very Light Violet Sehr helles Violett - + Light Violet Hellviolett - + Moderate Violet Gemäßigtes Violett - + Dark Violet Dunkelviolett - + Very Pale Violet Sehr blasses Violett - + Pale Violet Blassviolett - + Grayish Violet Grauviolett - + Vivid Purple Lebhaftes Purpur - + Brilliant Purple Leuchtendes Purpur - + Strong Purple Kräftiges Purpur - + Deep Purple Tiefpurpur - + Very Deep Purple Sehr tiefes Purpur - + Very Light Purple Sehr helles Purpur - + Light Purple Hellpurpur - + Moderate Purple Gemäßigtes Purpur - + Dark Purple Dunkelpurpur - + Very Dark Purple Sehr dunkles Purpur - + Very Pale Purple Sehr blasses Purpur - + Pale Purple Blasspurpur - + Grayish Purple Graupurpur - + Dark Grayish Purple Dunkelgraupurpur - + Blackish Purple Schwarzpurpur - + Purplish White Purpurweiß - + Light Purplish Gray Hellpurpurgrau - + Purplish Gray Purpurgrau - + Dark Purplish Gray Dunkelpurpurgrau - + Purplish Black Purpurschwarz - + Vivid Reddish Purple Lebhaftes Rotpurpur - + Strong Reddish Purple Kräftiges Rotpurpur - + Deep Reddish Purple Tiefrotpurpur - + Very Deep Reddish Purple Sehr tiefes Rotpurpur - + Light Reddish Purple Helles Rotpurpur - + Moderate Reddish Purple Gemäßigtes Rotpurpur - + Dark Reddish Purple Dunkelrotpurpur - + Very Dark Reddish Purple Sehr dunkles Rotpurpur - + Pale Reddish Purple Blassrotpurpur - + Grayish Reddish Purple Graurotpurpur - + Brilliant Purplish Pink Leuchtendes Purpurrosa - + Strong Purplish Pink Kräftiges Purpurrosa - + Deep Purplish Pink Tiefpurpurrosa - + Light Purplish Pink Hellpurpurrosa - + Moderate Purplish Pink Gemäßigtes Purpurrosa - + Dark Purplish Pink Dunkelpurpurrosa - + Pale Purplish Pink Blasspurpurrosa - + Grayish Purplish Pink Graupurpurrosa - + Vivid Purplish Red Lebhaftes Purpurrot - + Strong Purplish Red Kräftiges Purpurrot - + Deep Purplish Red Tiefpurpurrot - + Very Deep Purplish Red Sehr tiefes Purpurrot - + Moderate Purplish Red Gemäßigtes Purpurrot - + Dark Purplish Red Dunkelpurpurrot - + Very Dark Purplish Red Sehr dunkles Purpurrot - + Light Grayish Purplish Red Hellgraupurpurrot - + Grayish Purplish Red Graupurpurrot - + White Weiß - + Light Gray Hellgrau - + Medium Gray Mittelgrau - + Dark Gray Dunkelgrau - + Black Schwarz @@ -3335,60 +3341,60 @@ Sie haben die Liste erfolgreich geleert ScribbleArea - + Warning Warnung - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Sie zeichnen auf einer ausgeblendeten Ebene! Bitte wählen Sie eine andere Ebene aus (oder blenden Sie die aktuelle Ebene ein) - + Delete Selection Undo Step: clear the selection area. Auswahl löschen - - + + Clear Image Undo step text Bild leeren - + There is a gap in your drawing (or maybe you have zoomed too much). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). - + Out of bound. - + Could not find a closed path. Konnte keinen geschlossenen Pfad finden. - + Could not find the root index. - + %1<br><br>Error: %2 %1<br><br>Fehler: %2 - + Flood fill error @@ -3593,12 +3599,12 @@ Sie haben die Liste erfolgreich geleert TimeLineCells - + Layer Properties Ebeneneigenschaften - + Layer name: Ebenenname: @@ -3635,6 +3641,46 @@ Sie haben die Liste erfolgreich geleert Preferences Länge der Zeitleiste: + + + Drawing + + + + + When drawing on an empty frame: + + + + + Create a new (blank) key-frame and start drawing on it. + + + + + Create a new (blank) key-frame + + + + + Duplicate the previous key-frame and start drawing on the duplicate. + + + + + Duplicate the previous key-frame + + + + + Keep drawing on the previous key-frame + + + + + <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + Frame size diff --git a/translations/pencil_es.ts b/translations/pencil_es.ts index f863b4365..2064a0888 100644 --- a/translations/pencil_es.ts +++ b/translations/pencil_es.ts @@ -148,57 +148,57 @@ BaseTool - + Pencil Lápiz - + Eraser Borrador - + Select Seleccionar - + Move Mover - + Hand Mano - + Smudge Dedo - + Pen Pluma - + Polyline Polilínea - + Bucket Bote - + Eyedropper Pipeta - + Brush Pincel @@ -360,8 +360,8 @@ ColorPaletteWidget - - + + Colour name Nombre del color @@ -1278,7 +1278,7 @@ - + Play Reproducir @@ -1496,108 +1496,114 @@ Retroceder un fotograma - + color palette:<br>use <b>(C)</b><br>toggle at cursor Paleta de Color:<br>Utilice <b>(C)</b><br>para alternar sobre punteros - + Lock Windows Bloquear Ventanas - + Open Recent Abrir Reciente - + You have successfully cleared the list Lista eliminada con éxito - - - - + + + + + Warning Advertencia - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil no puede leer este archivo. Si desea importar imágenes, utilice la opción Importar. - + Opening document... Abriendo Documento... - - - + + + Abort Abortar - + Saving document... Grabando Documento... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>Una falla ha ocurrido y el archivo puede que no se haya grabado correctamente. Si piensa que este error es un problema de Pencil2D, por favor haga un informe en:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Asegúrese de incluir los siguientes detalles en su reporte: - + This animation has been modified. Do you want to save your changes? Esta animación ha sido modificada. ¿Desea guardar sus cambios? - + The animation is not saved yet. Do you want to save now? La animación aun no ha sido gravada. Quiere gravarla ahora? - + Never ask again AutoSave reminder button No volver a preguntar - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. No se puede importar imagen<br><b>TIP:</b> Use una capa Bitmap para importar bitmaps. - + Importing image sequence... Importando secuencia de imágenes... - - + + was unable to import + + + + + Undo Menu item text Deshacer - + Redo Menu item text Rehacer - + Stop Parar @@ -1605,122 +1611,122 @@ Quiere gravarla ahora? Object - + Black Negro - + Red Rojo - + Dark Red Rojo Oscuro - + Orange Naranja - + Dark Orange Naranja Oscuro - + Yellow Amarillo - + Dark Yellow Amarillo Oscuro - + Green Verde - + Dark Green Verde Oscuro - + Cyan Cian - + Dark Cyan Cian Oscuro - + Blue Azul - + Dark Blue Azul Oscuro - + White Blanco - + Very Light Grey Gris Muy Claro - + Light Grey Gris Claro - + Grey Gris - + Dark Grey Gris Oscuro - + Light Skin Piel Clara - + Light Skin - shade Piel Clara - Sombra - + Skin Piel - + Skin - shade Piel - Sombra - + Dark Skin Piel Oscura - + Dark Skin - shade Piel Oscura - Sombra @@ -1855,26 +1861,26 @@ Quiere gravarla ahora? Advertencia: el formato escogido no es soportado. Usar PNG. - + Warning: Transparency is not currently supported in movie files Command line warning Advertencia: La Transparencia no es actualmente soportada en archivos de películas - + Exporting movie... Command line task progress Exportando película - - + + Done. Command line task done Terminado. - + Exporting image sequence... Command line task progress Exportando secuencia de imágenes... @@ -1935,8 +1941,8 @@ Quiere gravarla ahora? - Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - Imágenes (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) + Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + @@ -1979,1337 +1985,1337 @@ Quiere gravarla ahora? Archivo de Animación Pencil PCLX(*.pclx);;Antiguo Archivo de Animación Pencil PCL(*.pcl) - + Vivid Pink Rosado Brillante - + Strong Pink Rosado Fuerte - + Deep Pink Rosado Intenso - + Light Pink Rosado Claro - + Moderate Pink Rosado Medio - + Dark Pink Rosado Oscuro - + Pale Pink Rosa Pálido - + Grayish Pink Rosa Grisáceo - + Pinkish White Blanco Rosado - + Pinkish Gray Gris Rosado - + Vivid Red Rojo Vivo - + Strong Red Rojo Fuerte - + Deep Red Rojo Intenso - + Very Deep Red Rojo Muy Intenso - + Moderate Red Rojo Medio - + Dark Red Rojo Oscuro - + Very Dark Red Rojo Muy Oscuro - + Light Grayish Red Rojo Grisáceo Claro - + Grayish Red Rojo Grisáceo - + Dark Grayish Red Rojo Grisáceo Oscuro - + Blackish Red Rojo Ennegrecido - + Reddish Gray Gris Rojizo - + Dark Reddish Gray Gris Rojizo Oscuro - + Reddish Black Negro Rojizo - + Vivid Yellowish Pink Rosa Amarillento Vivo - + Strong Yellowish Pink Rosa Amarillento Fuerte - + Deep Yellowish Pink Rosa Amarillento Intenso - + Light Yellowish Pink Rosa Amarillento Claro - + Moderate Yellowish Pink Rosa Amarillento Medio - + Dark Yellowish Pink Rosa Amarillento Oscuro - + Pale Yellowish Pink Rosa Amarillento Pálido - + Grayish Yellowish Pink Rosa Amarillento Grisáceo - + Brownish Pink Rosa Marrón - + Vivid Reddish Orange Naranja Rojizo Vivo - + Strong Reddish Orange Naranja Rojizo Fuerte - + Deep Reddish Orange Naranja Rojizo Intenso - + Moderate Reddish Orange Naranja Rojizo Medio - + Dark Reddish Orange Naranja Rojizo Oscuro - + Grayish Reddish Orange Naranja Rojizo Grisáceo - + Strong Reddish Brown Marrón Rojizo Fuerte - + Deep Reddish Brown Marrón Rojizo Intenso - + Light Reddish Brown Marrón Rojizo Claro - + Moderate Reddish Brown Marrón Rojizo Medo - + Dark Reddish Brown Marrón Rojizo Oscuro - + Light Grayish Reddish Brown Marrón Rojizo Grisáceo Claro - + Grayish Reddish Brown Marrón Rojizo Grisáceo - + Dark Grayish Reddish Brown Marrón Rojizo Grisáceo Oscuro - + Vivid Orange Naranja Vivo - + Brilliant Orange Naranja Brillante - + Strong Orange Naranja Fuerte - + Deep Orange Naranja Intenso - + Light Orange Naranja Claro - + Moderate Orange Naranja Moderado - + Brownish Orange Naranja Marrón - + Strong Brown Marrón Fuerte - + Deep Brown Marrón Profundo - + Light Brown Marrón Claro - + Moderate Brown Marrón Moderado - + Dark Brown Marrón Oscuro - + Light Grayish Brown Marrón Grisaceo Claro - + Grayish Brown Marrón Grisaceo - + Dark Grayish Brown Marrón Grisaceo Oscuro - + Light Brownish Gray Gris Marrón Claro - + Brownish Gray Gris Marrón - + Brownish Black Negro Marrón - + Vivid Orange Yellow Amarillo Anaranjado Vivido - + Brilliant Orange Yellow Amarillo Anaranjado Brillante - + Strong Orange Yellow Amarillo Anaranjado Fuerte - + Deep Orange Yellow Amarillo Naranja Intenso - + Light Orange Yellow Amarillo Naranja Claro - + Moderate Orange Yellow Amarillo Naranja Medio - + Dark Orange Yellow Amarillo Naranja Oscuro - + Pale Orange Yellow Amarillo Naranja Pálido - + Strong Yellowish Brown Marrón Amarillento Fuerte - + Deep Yellowish Brown Marrón Amarillento Intenso - + Light Yellowish Brown Marrón Amarillento Claro - + Moderate Yellowish Brown Marrón Amarillento Medio - + Dark Yellowish Brown Marrón Amarillento Oscuro - + Light Grayish Yellowish Brown Marrón Amarillento Grisáceo Claro - + Grayish Yellowish Brown Marrón Amarillento Grisáceo - + Dark Grayish Yellowish Brown Marrón Amarillento Oscuro Grisáceo - + Vivid Yellow Amarillo Vivo - + Brilliant Yellow Amarillo Brillante - + Strong Yellow Amarillo Fuerte - + Deep Yellow Amarillo Intenso - + Light Yellow Amarillo Claro - + Moderate Yellow Amarillo Medio - + Dark Yellow Amarillo Oscuro - + Pale Yellow Amarillo Pálido - + Grayish Yellow Amarillo Grisáceo - + Dark Grayish Yellow Amarillo Grisáceo Oscuro - + Yellowish White Blanco Amarillento - + Yellowish Gray Gris Amarillento - + Light Olive Brown Marrón Oliva Claro - + Moderate Olive Brown Marrón Oliva Medio - + Dark Olive Brown Marrón Oliva Oscuro - + Vivid Greenish Yellow Amarillo Verdoso Vivo - + Brilliant Greenish Yellow Amarillo Verdoso Brillante - + Strong Greenish Yellow Amarillo Verdoso Fuerte - + Deep Greenish Yellow Amarillo Verdoso Intenso - + Light Greenish Yellow Amarillo Verdoso Claro - + Moderate Greenish Yellow Amarillo Verdoso Medio - + Dark Greenish Yellow Amarillo Verdoso Oscuro - + Pale Greenish Yellow Amarillo Verdoso Pálido - + Grayish Greenish Yellow Amarillo Verdoso Grisáceo - + Light Olive Oliva Claro - + Moderate Olive Oliva Medio - + Dark Olive Oliva Oscuro - + Light Grayish Olive Oliva Grisáceo Claro - + Grayish Olive Oliva Grisáceo - + Dark Grayish Olive Oliva Grisáceo Oscuro - + Light Olive Gray Gris Oliva Claro - + Olive Gray Gris Oliva - + Olive Black Negro Oliva - + Vivid Yellow Green Verde Amarillo Vivo - + Brilliant Yellow Green Verde Amarillo Brillante - + Strong Yellow Green Verde Amarillo Fuerte - + Deep Yellow Green Verde Amarillo Intenso - + Light Yellow Green Verde Amarillo Claro - + Moderate Yellow Green Verde Amarillo Medio - + Pale Yellow Green Verde Amarillo Pálido - + Grayish Yellow Green Verde Amarillo Grisáceo - + Strong Olive Green Verde Oliva Fuerte - + Deep Olive Green Verde Oliva Intenso - + Moderate Olive Green Verde Oliva Medio - + Dark Olive Green Verde Oliva Oscuro - + Grayish Olive Green Verde Oliva Grisáceo - + Dark Grayish Olive Green Verde Oliva Grisáceo Oscuro - + Vivid Yellowish Green Verde Oliva Vivo - + Brilliant Yellowish Green Verde Amarillento Brillante - + Strong Yellowish Green Verde Amarillento Fuerte - + Deep Yellowish Green Verde Amarillento Intenso - + Very Deep Yellowish Green Verde Amarillento Muy Intenso - + Very Light Yellowish Green Verde Amarillento Muy Claro - + Light Yellowish Green Verde Amarillento Claro - + Moderate Yellowish Green Verde Amarillento Medio - + Dark Yellowish Green Verde Amarillento Oscuro - + Very Dark Yellowish Green Verde Amarillento Muy Oscuro - + Vivid Green Verde Vivo - + Brilliant Green Verde Brillante - + Strong Green Verde Fuerte - + Deep Green Verde Intenso - + Very Light Green Verde Muy Claro - + Light Green Verde Claro - + Moderate Green Verde Medio - + Dark Green Verde Oscuro - + Very Dark Green Verde Muy Oscuro - + Very Pale Green Verde Muy Pálido - + Pale Green Verde Pálido - + Grayish Green Verde Grisáceo - + Dark Grayish Green Verde Grisáceo Oscuro - + Blackish Green Verde Ennegrecido - + Greenish White Blanco Grisáceo - + Light Greenish Gray Gris Verdoso Claro - + Greenish Gray Gris Verdoso - + Dark Greenish Gray Gris Verdoso Oscuro - + Greenish Black Negro Verdoso - + Vivid Bluish Green Verde Azulado Vivo - + Brilliant Bluish Green Verde Azulado Brillante - + Strong Bluish Green Verde Azulado Fuerte - + Deep Bluish Green Verde Azulado Intenso - + Very Light Bluish Green Verde Azulado Muy Claro - + Light Bluish Green Verde Azulado Claro - + Moderate Bluish Green Verde Azulado Medio - + Dark Bluish Green Verde Azulado Oscuro - + Very Dark Bluish Green Verde Azulado Muy Oscuro - + Vivid Greenish Blue Azul Verdoso Vivo - + Brilliant Greenish Blue Azul Verdoso Brillante - + Strong Greenish Blue Azul Verdoso Fuerte - + Deep Greenish Blue Azul Verdoso Intenso - + Very Light Greenish Blue Azul Verdoso Muy Claro - + Light Greenish Blue Azul Verdoso Claro - + Moderate Greenish Blue Azul Verdoso Medio - + Dark Greenish Blue Azul Verdoso Oscuro - + Very Dark Greenish Blue Azul Verdoso Muy Oscuro - + Vivid Blue Azul Vivo - + Brilliant Blue Azul Brillante - + Strong Blue Azul Fuerte - + Deep Blue Azul Intenso - + Very Light Blue Azul Muy Claro - + Light Blue Azul Claro - + Moderate Blue Azul Medio - + Dark Blue Azul Oscuro - + Very Pale Blue Azul Muy Pálido - + Pale Blue Azul Pálido - + Grayish Blue Azul Grisáceo - + Dark Grayish Blue Azul Grisáceo Oscuro - + Blackish Blue Azul Ennegrecido - + Bluish White Blanco Azulado - + Light Bluish Gray Gris Azulado Claro - + Bluish Gray Gris Azulado - + Dark Bluish Gray Gris Azulado Oscuro - + Bluish Black Negro Azulado - + Vivid Purplish Blue Azul Purpúreo Vivo - + Brilliant Purplish Blue Azul Purpúreo Brillante - + Strong Purplish Blue Azul Purpúreo Fuerte - + Deep Purplish Blue Azul Purpúreo Intenso - + Very Light Purplish Blue Azul Purpúreo Muy Claro - + Light Purplish Blue Azul Purpúreo Claro - + Moderate Purplish Blue Azul Purpúreo Medio - + Dark Purplish Blue Azul Purpúreo Oscuro - + Very Pale Purplish Blue Azul Purpúreo Muy Pálido - + Pale Purplish Blue Azul Purpúreo Pálido - + Grayish Purplish Blue Azul Purpúreo grisáceo - + Vivid Violet Violeta Vivo - + Brilliant Violet Violeta Brillante - + Strong Violet Violeta Fuerte - + Deep Violet Violeta Intenso - + Very Light Violet Violeta Muy Claro - + Light Violet Violeta Claro - + Moderate Violet Violeta Medio - + Dark Violet Violeta Oscuro - + Very Pale Violet Violeta Muy Pálido - + Pale Violet Violeta Pálido - + Grayish Violet Violeta Grisáceo - + Vivid Purple Violeta Vivo - + Brilliant Purple Violeta Brillante - + Strong Purple Violeta Fuerte - + Deep Purple Violeta Intenso - + Very Deep Purple Violeta muy intenso - + Very Light Purple Violeta Muy Claro - + Light Purple Violeta Claro - + Moderate Purple Violeta Medio - + Dark Purple Violeta Oscuro - + Very Dark Purple Violeta Muy Oscuro - + Very Pale Purple Violeta Muy Pálido - + Pale Purple Violeta Pálido - + Grayish Purple Violeta Grisáceo - + Dark Grayish Purple Violeta Grisáceo Oscuro - + Blackish Purple Violeta Ennegrecido - + Purplish White Blanco Purpúreo - + Light Purplish Gray Gris Purpúreo Claro - + Purplish Gray Gris Purpúreo - + Dark Purplish Gray Gris Purpúreo Oscuro - + Purplish Black Negro Purpúreo - + Vivid Reddish Purple Violeta Rojizo Vivo - + Strong Reddish Purple Violeta Rojizo Fuerte - + Deep Reddish Purple Violeta Rojizo Intenso - + Very Deep Reddish Purple Violeta Rojizo Muy Intenso - + Light Reddish Purple Violeta Rojizo Claro - + Moderate Reddish Purple Violeta Rojizo Medio - + Dark Reddish Purple Violeta Rojizo Oscuro - + Very Dark Reddish Purple Violeta Rojizo Muy Oscuro - + Pale Reddish Purple Violeta Rojizo Pálido - + Grayish Reddish Purple Violeta Rojizo Grisáceo - + Brilliant Purplish Pink Rosado Purpúreo Brillante - + Strong Purplish Pink Rosado Purpúreo Fuerte - + Deep Purplish Pink Rosado Purpúreo Intenso - + Light Purplish Pink Rosado Purpúreo Claro - + Moderate Purplish Pink Rosado Purpúreo Medio - + Dark Purplish Pink Rosado Purpúreo Oscuro - + Pale Purplish Pink Rosado Purpúreo Pálido - + Grayish Purplish Pink Rosado Purpúreo Grisáceo - + Vivid Purplish Red Rojo Purpúreo Vivo - + Strong Purplish Red Rojo Purpúreo Fuerte - + Deep Purplish Red Rojo Purpúreo Intenso - + Very Deep Purplish Red Rojo Purpúreo Muy Intenso - + Moderate Purplish Red Rojo Purpúreo Medio - + Dark Purplish Red Rojo Purpúreo Oscuro - + Very Dark Purplish Red Rojo Purpúreo Muy Oscuro - + Light Grayish Purplish Red Rojo Purpúreo Grisáceo Claro - + Grayish Purplish Red Rojo Purpúreo Grisáceo - + White Blanco - + Light Gray Gris Claro - + Medium Gray Gris Medio - + Dark Gray Gris Oscuro - + Black Negro @@ -3330,60 +3336,60 @@ Quiere gravarla ahora? ScribbleArea - + Warning Advertencia - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Usted está dibujando en una capa oculta! Por favor seleccione otra capa (o haga visible la capa actual). - + Delete Selection Undo Step: clear the selection area. Quitar Selección - - + + Clear Image Undo step text Limpiar imagen - + There is a gap in your drawing (or maybe you have zoomed too much). Hay una interrupción en su dibujo (ó talvez usted haya usado mucho el zoom) - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). Disculpe! Esto ni siempre funciona. Por favor inténtelo de nuevo (aumente un poco el zoom, haga clic en otro sitio... )<br>Caso no funcione, aumente un poco más el zoom y asegúrese de que las interrupciones son conectadas presionando F1). - + Out of bound. Fuera del limite - + Could not find a closed path. No se encuentra el camino cerrado - + Could not find the root index. No se encuentra el índice principal. - + %1<br><br>Error: %2 %1<br><br>Fallo: %2 - + Flood fill error Fallo de Relleno @@ -3588,12 +3594,12 @@ Quiere gravarla ahora? TimeLineCells - + Layer Properties Propiedades de la capa - + Layer name: Nombre de la capa: @@ -3630,6 +3636,46 @@ Quiere gravarla ahora? Preferences Longitud línea de tiempo: + + + Drawing + + + + + When drawing on an empty frame: + + + + + Create a new (blank) key-frame and start drawing on it. + + + + + Create a new (blank) key-frame + + + + + Duplicate the previous key-frame and start drawing on the duplicate. + + + + + Duplicate the previous key-frame + + + + + Keep drawing on the previous key-frame + + + + + <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + Frame size diff --git a/translations/pencil_et.ts b/translations/pencil_et.ts index a06e4d9e7..b4f265219 100644 --- a/translations/pencil_et.ts +++ b/translations/pencil_et.ts @@ -85,7 +85,7 @@ A sound clip already exists on this frame! Please select another frame or layer. - + Heliklipp on selles kaadris juba olemas! Palun vali teine kaader või kiht. @@ -110,7 +110,7 @@ Bitmap Layer - + Pildifaili kiht @@ -148,57 +148,57 @@ BaseTool - + Pencil Pliiats - + Eraser Kustukumm - + Select Valimine - + Move Liigutamine - + Hand Käsi - + Smudge Hägustamine - + Pen Pliiats - + Polyline - + Bucket - + Eyedropper - + Brush Pintsel @@ -360,8 +360,8 @@ ColorPaletteWidget - - + + Colour name Värvi nimi @@ -486,7 +486,7 @@ Export image sequence - + Ekspordi pildiseeria @@ -605,7 +605,7 @@ Loop - + Kordamine @@ -623,7 +623,7 @@ Import image sequence - + Impordi pildiseeria @@ -653,7 +653,7 @@ Export image sequence - + Ekspordi pildiseeria @@ -725,12 +725,12 @@ Failed to create directory "%1". Please make sure you have sufficient permissions. - + Kausta "%1" loomine ebaõnnestus. Palun veendu, et sul oleks piisavalt õiguseid. "%1" is a file. Please delete the file and try again. - + "%1" on fail. Palun kustuta see fail ja proovi siis uuesti. @@ -742,7 +742,7 @@ An internal error occurred. Your file may not be saved successfully. - + Tekkis sisemine tõrge. Võimalik, et sinu faili ei salvestatud korrektselt. @@ -950,7 +950,7 @@ The language change will take effect after a restart of Pencil2D - + Keele muudatus rakendatakse pärast Pencil2D taaskäivitamist @@ -1278,7 +1278,7 @@ - + Play Esita @@ -1496,22 +1496,22 @@ Liiguta kaadrit tagasi - + color palette:<br>use <b>(C)</b><br>toggle at cursor - + Lock Windows Lukusta aknad - + Open Recent Ava hiljutised - + You have successfully cleared the list @@ -1520,84 +1520,90 @@ Nimekiri on tühjendatud - - - - + + + + + Warning Hoiatus - - + + Pencil cannot read this file. If you want to import images, use the command import. - + Opening document... Dokumendi avamine... - - - + + + Abort Info - + Saving document... Dokumendi salvestamine... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: - + This animation has been modified. Do you want to save your changes? - + The animation is not saved yet. Do you want to save now? - + Never ask again AutoSave reminder button Ära küsi kunagi uuesti - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. - + Importing image sequence... + Pildiseeria importimine... + + + + was unable to import - - + + Undo Menu item text Samm tagasi - + Redo Menu item text Korda - + Stop Peata @@ -1605,122 +1611,122 @@ Nimekiri on tühjendatud Object - + Black Must - + Red Punane - + Dark Red Tumepunane - + Orange Oraanž - + Dark Orange Tumeoraanž - + Yellow Kollane - + Dark Yellow Tumekollane - + Green Roheline - + Dark Green Tumeroheline - + Cyan Tsüaan - + Dark Cyan Tume tsüaan - + Blue Sinine - + Dark Blue Tumesinine - + White Valge - + Very Light Grey Väga hele hall - + Light Grey Helehall - + Grey Hall - + Dark Grey Tumehall - + Light Skin Hele nahk - + Light Skin - shade Hele nahk - varjuga - + Skin Nahk - + Skin - shade Nahk - varjuga - + Dark Skin Tume nahk - + Dark Skin - shade Tume nahk - varjuga @@ -1741,13 +1747,13 @@ Nimekiri on tühjendatud Render the file to <output_path> - + Renderda fail kausta <output_path> output_path - + väljundi_kaust @@ -1762,7 +1768,7 @@ Nimekiri on tühjendatud Width of the output frames - + Väljundikaadrite laius @@ -1855,29 +1861,29 @@ Nimekiri on tühjendatud - + Warning: Transparency is not currently supported in movie files Command line warning - + Exporting movie... Command line task progress Video eksportimine... - - + + Done. Command line task done Valmis. - + Exporting image sequence... Command line task progress - + Pildiseeria eksportimine... @@ -1935,8 +1941,8 @@ Nimekiri on tühjendatud - Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - Pildid (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) + Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + @@ -1971,1345 +1977,1345 @@ Nimekiri on tühjendatud All Pencil Files PCLX & PCL(*.pclx *.pcl);;Pencil Animation File PCLX(*.pclx);;Old Pencil Animation File PCL(*.pcl);;Any files (*) - + Kõik Pencil failid PCLX & PCL(*.pclx *.pcl);;Pencil animatsioonifail PCLX(*.pclx);;Vana Pencil animatsioonifail PCL(*.pcl);;Any files (*) Pencil Animation File PCLX(*.pclx);;Old Pencil Animation File PCL(*.pcl) - + Pencil animatsiooni fail PCLX(*.pclx);;Vana Pencil animatsiooni fail PCL(*.pcl) - + Vivid Pink Erk roosa - + Strong Pink Tugev roosa - + Deep Pink Sügav roosa - + Light Pink Heleroosa - + Moderate Pink Keskmine roosa - + Dark Pink Tumeroosa - + Pale Pink Kahvatu roosa - + Grayish Pink Hallikasroosa - + Pinkish White Roosakasvalge - + Pinkish Gray Roosakashall - + Vivid Red Erk punane - + Strong Red Tugev punane - + Deep Red Sügav punane - + Very Deep Red Väga sügav punane - + Moderate Red Keskmine punane - + Dark Red Tumepunane - + Very Dark Red Väga tume punane - + Light Grayish Red Hele hallikaspunane - + Grayish Red Hallikas-punane - + Dark Grayish Red Tume hallikaspunane - + Blackish Red Mustjaspunane - + Reddish Gray Punakas-hall - + Dark Reddish Gray Tume punakashall - + Reddish Black Punakasmust - + Vivid Yellowish Pink - + Strong Yellowish Pink - + Deep Yellowish Pink - + Light Yellowish Pink - + Moderate Yellowish Pink - + Dark Yellowish Pink - + Pale Yellowish Pink - + Grayish Yellowish Pink - + Brownish Pink - + Vivid Reddish Orange - + Strong Reddish Orange - + Deep Reddish Orange - + Moderate Reddish Orange - + Dark Reddish Orange - + Grayish Reddish Orange - + Strong Reddish Brown - + Deep Reddish Brown - + Light Reddish Brown - + Moderate Reddish Brown - + Dark Reddish Brown - + Light Grayish Reddish Brown - + Grayish Reddish Brown - + Dark Grayish Reddish Brown - + Vivid Orange - + Brilliant Orange - + Strong Orange - + Deep Orange - + Light Orange - + Moderate Orange - + Brownish Orange - + Strong Brown - + Deep Brown - + Light Brown - + Moderate Brown - + Dark Brown - + Light Grayish Brown - + Grayish Brown - + Dark Grayish Brown - + Light Brownish Gray - + Brownish Gray - + Brownish Black - + Vivid Orange Yellow - + Brilliant Orange Yellow - + Strong Orange Yellow - + Deep Orange Yellow - + Light Orange Yellow - + Moderate Orange Yellow - + Dark Orange Yellow - + Pale Orange Yellow - + Strong Yellowish Brown - + Deep Yellowish Brown - + Light Yellowish Brown - + Moderate Yellowish Brown - + Dark Yellowish Brown - + Light Grayish Yellowish Brown - + Grayish Yellowish Brown - + Dark Grayish Yellowish Brown - + Vivid Yellow - + Brilliant Yellow - + Strong Yellow - + Deep Yellow - + Light Yellow - + Moderate Yellow - + Dark Yellow - + Pale Yellow - + Grayish Yellow - + Dark Grayish Yellow - + Yellowish White - + Yellowish Gray - + Light Olive Brown - + Moderate Olive Brown - + Dark Olive Brown - + Vivid Greenish Yellow - + Brilliant Greenish Yellow - + Strong Greenish Yellow - + Deep Greenish Yellow - + Light Greenish Yellow - + Moderate Greenish Yellow - + Dark Greenish Yellow - + Pale Greenish Yellow - + Grayish Greenish Yellow - + Light Olive - + Moderate Olive - + Dark Olive Tume oliiv - + Light Grayish Olive - + Grayish Olive Hallikas oliiv - + Dark Grayish Olive - + Light Olive Gray - + Olive Gray - + Olive Black - + Vivid Yellow Green - + Brilliant Yellow Green - + Strong Yellow Green - + Deep Yellow Green - + Light Yellow Green - + Moderate Yellow Green - + Pale Yellow Green - + Grayish Yellow Green - + Strong Olive Green - + Deep Olive Green - + Moderate Olive Green - + Dark Olive Green - + Grayish Olive Green - + Dark Grayish Olive Green - + Vivid Yellowish Green - + Brilliant Yellowish Green - + Strong Yellowish Green - + Deep Yellowish Green - + Very Deep Yellowish Green - + Very Light Yellowish Green - + Light Yellowish Green - + Moderate Yellowish Green - + Dark Yellowish Green - + Very Dark Yellowish Green - + Vivid Green - + Brilliant Green - + Strong Green - + Deep Green - + Very Light Green - + Light Green - + Moderate Green - + Dark Green - + Very Dark Green - + Very Pale Green - + Pale Green - + Grayish Green - + Dark Grayish Green - + Blackish Green - + Greenish White - + Light Greenish Gray - + Greenish Gray - + Dark Greenish Gray - + Greenish Black - + Vivid Bluish Green - + Brilliant Bluish Green - + Strong Bluish Green - + Deep Bluish Green - + Very Light Bluish Green - + Light Bluish Green - + Moderate Bluish Green - + Dark Bluish Green - + Very Dark Bluish Green - + Vivid Greenish Blue - + Brilliant Greenish Blue - + Strong Greenish Blue - + Deep Greenish Blue - + Very Light Greenish Blue - + Light Greenish Blue - + Moderate Greenish Blue - + Dark Greenish Blue - + Very Dark Greenish Blue - + Vivid Blue - + Brilliant Blue - + Strong Blue - + Deep Blue - + Very Light Blue - + Light Blue - + Moderate Blue - + Dark Blue - + Very Pale Blue - + Pale Blue - + Grayish Blue - + Dark Grayish Blue - + Blackish Blue - + Bluish White - + Light Bluish Gray - + Bluish Gray - + Dark Bluish Gray - + Bluish Black - + Vivid Purplish Blue - + Brilliant Purplish Blue - + Strong Purplish Blue - + Deep Purplish Blue - + Very Light Purplish Blue - + Light Purplish Blue - + Moderate Purplish Blue - + Dark Purplish Blue - + Very Pale Purplish Blue - + Pale Purplish Blue - + Grayish Purplish Blue - + Vivid Violet - + Brilliant Violet - + Strong Violet - + Deep Violet - + Very Light Violet - + Light Violet - + Moderate Violet - + Dark Violet - + Very Pale Violet - + Pale Violet - + Grayish Violet - + Vivid Purple - + Brilliant Purple - + Strong Purple - + Deep Purple - + Very Deep Purple - + Very Light Purple - + Light Purple - + Moderate Purple - + Dark Purple - + Very Dark Purple - + Very Pale Purple - + Pale Purple - + Kahvatu lilla - + Grayish Purple - + Hallikaslilla - + Dark Grayish Purple - + Tume hallikaslilla - + Blackish Purple - + Mustjaslilla - + Purplish White - + Lillakasvalge - + Light Purplish Gray - + Hele lillakashall - + Purplish Gray - + Lillakashall - + Dark Purplish Gray - + Tume lillakashall - + Purplish Black - + Lillakasmust - + Vivid Reddish Purple - + Erk punakaslilla - + Strong Reddish Purple - + Deep Reddish Purple - + Sügav punakaslilla - + Very Deep Reddish Purple - + Light Reddish Purple - + Moderate Reddish Purple - + Dark Reddish Purple - + Very Dark Reddish Purple - + Pale Reddish Purple - + Grayish Reddish Purple - + Brilliant Purplish Pink - + Strong Purplish Pink - + Deep Purplish Pink - + Light Purplish Pink - + Moderate Purplish Pink - + Dark Purplish Pink - + Tume lillakasroosa - + Pale Purplish Pink - + Hele lillakasroosa - + Grayish Purplish Pink - + Vivid Purplish Red - + Strong Purplish Red - + Deep Purplish Red - + Sügav lillakaspunane - + Very Deep Purplish Red - + Väga sügav lillakaspunan - + Moderate Purplish Red - + Keskmine lillakaspunane - + Dark Purplish Red - + Tume lillakaspunane - + Very Dark Purplish Red - + Väga tume lillakaspunan - + Light Grayish Purplish Red - + Grayish Purplish Red - + White Valge - + Light Gray Helehall - + Medium Gray Keskmine hall - + Dark Gray Tumehall - + Black Must @@ -3330,60 +3336,60 @@ Nimekiri on tühjendatud ScribbleArea - + Warning Hoiatus - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). - + Delete Selection Undo Step: clear the selection area. Kustuta valik - - + + Clear Image Undo step text - + Eemalda pilt - + There is a gap in your drawing (or maybe you have zoomed too much). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). - + Out of bound. Piiridest väljas. - + Could not find a closed path. - + Suletud asukohta ei leitud. - + Could not find the root index. - + %1<br><br>Error: %2 - + %1<br><br>Viga: %2 - + Flood fill error @@ -3393,7 +3399,7 @@ Nimekiri on tühjendatud Form - + Vorm @@ -3418,17 +3424,17 @@ Nimekiri on tühjendatud Restore Default Shortcuts - + Taasta vaikimisi otseteed Shortcut Conflict! - + Otsetee konflikt! %1 is already used, overwrite? - + %1 on juba kasutusel. Kas kirjutan üle? @@ -3456,7 +3462,7 @@ Nimekiri on tühjendatud Playback range - + Esitamise vahemik @@ -3466,7 +3472,7 @@ Nimekiri on tühjendatud Loop - + Kordamine @@ -3495,7 +3501,7 @@ Nimekiri on tühjendatud Timeline - + Ajatelg @@ -3588,12 +3594,12 @@ Nimekiri on tühjendatud TimeLineCells - + Layer Properties Kihi omadused - + Layer name: Kihi nimi: @@ -3603,7 +3609,7 @@ Nimekiri on tühjendatud Timeline - + Ajatelg @@ -3630,6 +3636,46 @@ Nimekiri on tühjendatud Preferences Ajatelje pikkus: + + + Drawing + Joonistamine + + + + When drawing on an empty frame: + Kui joonistatakse tühja kaadrisse: + + + + Create a new (blank) key-frame and start drawing on it. + + + + + Create a new (blank) key-frame + + + + + Duplicate the previous key-frame and start drawing on the duplicate. + + + + + Duplicate the previous key-frame + + + + + Keep drawing on the previous key-frame + + + + + <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + Frame size @@ -3712,32 +3758,32 @@ Nimekiri on tühjendatud Pencil Tool (%1) - + Pliiats (%1) Select Tool (%1) - + Valimine (%1) Move Tool (%1) - + Liigutamine (%1) Hand Tool (%1) - + Käsi (%1) Pen Tool (%1) - + Pastakas (%1) Eraser Tool (%1) - + Kustutkumm (%1) @@ -3780,7 +3826,7 @@ Nimekiri on tühjendatud Feather - + Sujuv üleminek @@ -3809,7 +3855,7 @@ Nimekiri on tühjendatud Form - + Vorm @@ -3829,7 +3875,7 @@ Nimekiri on tühjendatud Use Feather - + Kasuta sujuvat üleminekut @@ -3915,7 +3961,7 @@ Nimekiri on tühjendatud Stabilizer - + Stabiliseerija diff --git a/translations/pencil_fr.ts b/translations/pencil_fr.ts index 1a0722f92..4f72a2cf2 100644 --- a/translations/pencil_fr.ts +++ b/translations/pencil_fr.ts @@ -148,57 +148,57 @@ BaseTool - + Pencil Crayon - + Eraser Gomme - + Select Sélectionner - + Move Déplacer - + Hand Main - + Smudge Etaler - + Pen Stylo - + Polyline Polyligne - + Bucket Seau - + Eyedropper Pipette - + Brush Brosse @@ -360,8 +360,8 @@ ColorPaletteWidget - - + + Colour name Nom de la couleur @@ -1279,7 +1279,7 @@ - + Play Play @@ -1437,7 +1437,7 @@ F1 - + F1 @@ -1497,22 +1497,22 @@ Reculer l'image - + color palette:<br>use <b>(C)</b><br>toggle at cursor palette de couleurs :<br>utiliser <b>(C)</b><br>bascule à curseur - + Lock Windows Verrouiller les fenêtres - + Open Recent Ouvrir fichier récent - + You have successfully cleared the list @@ -1521,86 +1521,92 @@ Vous avez effacé la liste avec succès - - - - + + + + + Warning Attention - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil ne peut pas lire ce fichier. Si vous voulez import des images, utilisez la commande import. - + Opening document... Document de démarrage... - - - + + + Abort Abandonner - + Saving document... Enregistrement d'un document... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>Une erreur est survenue et votre fichier n'a peut-être pas été sauvegardé correctement. Si vous pensez que cette erreur est un problème avec Pencil2D, veuillez créer un nouveau problème sur:<br><a href='https://github.com/pencil2d/pencil/issues'> https: //github.com/pencil2d/pencil/issues</a><br>Veuillez vous assurer d'inclure les détails suivants dans votre problème: - + This animation has been modified. Do you want to save your changes? Cette animation a été modifiée. Voulez vous sauvegarder vos modifications ? - + The animation is not saved yet. Do you want to save now? L'animation n'est pas encore enregistrée. Voulez-vous enregistrer maintenant? - + Never ask again AutoSave reminder button Ne plus me demander - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Impossible d'importer l'image.<br><b>ASTUCE:</b> Utilisez un calque "Bitmap" pour importer des bitmaps. - + Importing image sequence... Importation de la séquence d'image... - - + + was unable to import + incapable d'importer + + + + Undo Menu item text Annuler - + Redo Menu item text Rétablir - + Stop Arrêter @@ -1608,122 +1614,122 @@ Voulez-vous enregistrer maintenant? Object - + Black Noir - + Red Rouge - + Dark Red Rouge foncé - + Orange Orange - + Dark Orange Orange foncé - + Yellow Jaune - + Dark Yellow Jaune foncé - + Green Vert - + Dark Green Vert foncé - + Cyan Cyan - + Dark Cyan Cyan foncé - + Blue Bleu - + Dark Blue Bleu foncé - + White Blanc - + Very Light Grey Gris trés léger - + Light Grey Gris léger - + Grey Gris - + Dark Grey Gris foncé - + Light Skin Peau clair - + Light Skin - shade Peau claire - ombré - + Skin Peau - + Skin - shade Peau ombrée - + Dark Skin Peau foncée - + Dark Skin - shade Peau foncée ombrée @@ -1844,7 +1850,7 @@ Voulez-vous enregistrer maintenant? Error: the input path '%1' is not a file Command line error - + Erreur: le chemin d'entrée '%1' n'est pas un fichier @@ -1855,29 +1861,29 @@ Voulez-vous enregistrer maintenant? Warning: Output format is not specified or unsupported. Using PNG. Command line warning - + Attention: le format de sortie n'est pas spécifié ou non supporté. Utilisation PNG. - + Warning: Transparency is not currently supported in movie files Command line warning Attention: la transparence n'est actuellement pas supportée dans les fichiers vidéo - + Exporting movie... Command line task progress Exportation du film... - - + + Done. Command line task done Terminé. - + Exporting image sequence... Command line task progress Exportation de la séquence d'images... @@ -1938,8 +1944,8 @@ Voulez-vous enregistrer maintenant? - Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) + Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + Images (* .png * .jpg * .jpeg * .bmp * .gif) ;; PNG (* .png) ;; JPG (* .jpg * .jpeg) ;; BMP (* .bmp) ;; GIF (* .gif) @@ -1982,1337 +1988,1337 @@ Voulez-vous enregistrer maintenant? Pencil Animation File PCLX(*.pclx);;Old Pencil Animation File PCL(*.pcl) - + Vivid Pink Rose vif - + Strong Pink Rose fort - + Deep Pink Rose profond - + Light Pink Rose clair - + Moderate Pink Rose modéré - + Dark Pink Rose sombre - + Pale Pink Rose pâle - + Grayish Pink Rose grisâtre - + Pinkish White Blanc rosâtre - + Pinkish Gray Gris rosé - + Vivid Red Rouge vif - + Strong Red Rouge fort - + Deep Red Rouge profond - + Very Deep Red Rouge très profond - + Moderate Red Rouge modéré - + Dark Red Rouge sombre - + Very Dark Red Rouge très sombre - + Light Grayish Red Rouge grisâtre clair - + Grayish Red Rouge grisâtre - + Dark Grayish Red Rouge grisâtre sombre - + Blackish Red Rouge noirâtre - + Reddish Gray Gris rougeâtre - + Dark Reddish Gray Gris rougeâtre sombre - + Reddish Black Rougeâtre noir - + Vivid Yellowish Pink Rose jaunâtre vif - + Strong Yellowish Pink Rose jaunâtre fort - + Deep Yellowish Pink Rose jaunâtre profond - + Light Yellowish Pink Rose jaunâtre clair - + Moderate Yellowish Pink Rose jaunâtre modéré - + Dark Yellowish Pink Rose jaunâtre sombre - + Pale Yellowish Pink Rose jaunâtre pâle - + Grayish Yellowish Pink Gris jaunâtre rose - + Brownish Pink Rose brunâtre - + Vivid Reddish Orange Orange rougeâtre vif - + Strong Reddish Orange Orange rougeâtre fort - + Deep Reddish Orange Orange rougeâtre profond - + Moderate Reddish Orange Orange rougeâtre modéré - + Dark Reddish Orange Orange rougeâtre sombre - + Grayish Reddish Orange Orange rougeâtre grisâtre - + Strong Reddish Brown Fort brun rougeâtre - + Deep Reddish Brown Brun rougeâtre profond - + Light Reddish Brown Brun rougeâtre clair - + Moderate Reddish Brown Brun rougeâtre modéré - + Dark Reddish Brown Brun rougeâtre sombre - + Light Grayish Reddish Brown Brun rougeâtre grisâtre clair - + Grayish Reddish Brown Brun rougeâtre grisâtre - + Dark Grayish Reddish Brown Brun rougeâtre grisâtre sombre - + Vivid Orange Orange vif - + Brilliant Orange Orange brillant - + Strong Orange Orange fort - + Deep Orange Orange profond - + Light Orange Orange clair - + Moderate Orange Orange modéré - + Brownish Orange Orange brunâtre - + Strong Brown Brun fort - + Deep Brown Brun profond - + Light Brown Brun clair - + Moderate Brown Brun modéré - + Dark Brown Brun sombre - + Light Grayish Brown Brun grisâtre clair - + Grayish Brown Brun grisâtre - + Dark Grayish Brown Brun grisâtre sombre - + Light Brownish Gray Gris brunâtre clair - + Brownish Gray Gris brunâtre - + Brownish Black Noir brunâtre - + Vivid Orange Yellow Orange Jaune vif - + Brilliant Orange Yellow Orange Jaune brillant - + Strong Orange Yellow Orange Jaune fort - + Deep Orange Yellow Orange Jaune profond - + Light Orange Yellow Orange Jaune clair - + Moderate Orange Yellow Orange Jaune modéré - + Dark Orange Yellow Orange Jaune sombre - + Pale Orange Yellow Orange Jaune pâle - + Strong Yellowish Brown Brun jaunâtre fort - + Deep Yellowish Brown Brun jaunâtre profond - + Light Yellowish Brown Brun jaunâtre clair - + Moderate Yellowish Brown Brun jaunâtre modéré - + Dark Yellowish Brown Brun jaunâtre sombre - + Light Grayish Yellowish Brown Brun jaunâtre grisâtre clair - + Grayish Yellowish Brown Brun jaunâtre grisâtre - + Dark Grayish Yellowish Brown Brun jaunâtre grisâtre sombre - + Vivid Yellow Jaune vif - + Brilliant Yellow Jaune brillant - + Strong Yellow Jaune fort - + Deep Yellow Jaune profond - + Light Yellow Jaune clair - + Moderate Yellow Jaune modéré - + Dark Yellow Jaune sombre - + Pale Yellow Jaune pâle - + Grayish Yellow Jaune grisâtre - + Dark Grayish Yellow Jaune grisâtre sombre - + Yellowish White Blanc jaunâtre - + Yellowish Gray Gris jaunâtre - + Light Olive Brown Olive brun clair - + Moderate Olive Brown Olive brun modéré - + Dark Olive Brown Olive brun sombre - + Vivid Greenish Yellow Jaune verdâtre vif - + Brilliant Greenish Yellow Jaune verdâtre brillant - + Strong Greenish Yellow Jaune verdâtre fort - + Deep Greenish Yellow Jaune verdâtre profond - + Light Greenish Yellow Jaune clair verdâtre - + Moderate Greenish Yellow Jaune verdâtre modéré - + Dark Greenish Yellow Jaune verdâtre sombre - + Pale Greenish Yellow Jaune verdâtre pâle - + Grayish Greenish Yellow Jaune verdâtre grisâtre - + Light Olive Olive claire - + Moderate Olive Olive modérée - + Dark Olive Olive sombre - + Light Grayish Olive Olive grisâtre pâle - + Grayish Olive Olive grisâtre - + Dark Grayish Olive Olive Grisâtre sombre - + Light Olive Gray Olive Gris clair - + Olive Gray Olive Gris - + Olive Black Olive Noire - + Vivid Yellow Green Jaune Vert Vif - + Brilliant Yellow Green Jaune Vert Brillant - + Strong Yellow Green Jaune Vert Fort - + Deep Yellow Green Jaune Vert Sombre - + Light Yellow Green Jaune Vert Clair - + Moderate Yellow Green Jaune Vert Modéré - + Pale Yellow Green Jaune Vert Pâle - + Grayish Yellow Green Vert jaunâtre grisâtre - + Strong Olive Green Vert Olive fort - + Deep Olive Green Vert Olive Profond - + Moderate Olive Green Vert Olive Modéré - + Dark Olive Green Vert Olive Sombre - + Grayish Olive Green Vert Olive grisâtre - + Dark Grayish Olive Green Vert Olive grisâtre sombre - + Vivid Yellowish Green Vert jaunâtre vif - + Brilliant Yellowish Green Vert jaunâtre brillant - + Strong Yellowish Green Vert jaunâtre fort - + Deep Yellowish Green Vert jaunâtre profond - + Very Deep Yellowish Green Vert jaunâtre très profond - + Very Light Yellowish Green Vert jaunâtre très clair - + Light Yellowish Green Vert jaunâtre clair - + Moderate Yellowish Green Vert jaunâtre modéré - + Dark Yellowish Green Vert jaunâtre sombre - + Very Dark Yellowish Green Vert jaunâtre très sombre - + Vivid Green Vert vif - + Brilliant Green Vert brillant - + Strong Green Vert fort - + Deep Green Vert profond - + Very Light Green Vert très clair - + Light Green Vert clair - + Moderate Green Vert modéré - + Dark Green Vert sombre - + Very Dark Green Vert très sombre - + Very Pale Green Vert très pâle - + Pale Green Vert pâle - + Grayish Green Vert grisâtre - + Dark Grayish Green Vert grisâtre sombre - + Blackish Green Vert noirâtre - + Greenish White Blanc verdâtre - + Light Greenish Gray Gris verdâtre clair - + Greenish Gray Gris verdâtre - + Dark Greenish Gray Gris verdâtre sombre - + Greenish Black Noir verdâtre - + Vivid Bluish Green Vert bleuté vif - + Brilliant Bluish Green Vert bleuté brillant - + Strong Bluish Green Bleu fort bleuté - + Deep Bluish Green Vert bleuâtre profond - + Very Light Bluish Green Vert bleuâtre très clair - + Light Bluish Green Vert bleuté clair - + Moderate Bluish Green Vert bleuté modéré - + Dark Bluish Green Vert bleuâtre sombre - + Very Dark Bluish Green Vert bleuâtre très sombre - + Vivid Greenish Blue Bleu verdâtre vif - + Brilliant Greenish Blue Bleu verdâtre brillant - + Strong Greenish Blue Bleu verdâtre fort - + Deep Greenish Blue Bleu verdâtre profond - + Very Light Greenish Blue Bleu verdâtre très clair - + Light Greenish Blue Bleu clair verdâtre - + Moderate Greenish Blue Bleu verdâtre modéré - + Dark Greenish Blue Bleu verdâtre sombre - + Very Dark Greenish Blue Bleu verdâtre très sombre - + Vivid Blue Bleu vif - + Brilliant Blue Bleu brillant - + Strong Blue Bleu fort - + Deep Blue Bleu profond - + Very Light Blue Bleu très clair - + Light Blue Bleu clair - + Moderate Blue Bleu modéré - + Dark Blue Bleu sombre - + Very Pale Blue Bleu très pâle - + Pale Blue Bleu pâle - + Grayish Blue Bleu grisâtre - + Dark Grayish Blue Bleu grisâtre sombre - + Blackish Blue Bleu noirâtre - + Bluish White Blanc bleuâtre - + Light Bluish Gray Gris bleuté clair - + Bluish Gray Gris bleuté - + Dark Bluish Gray Gris bleuté sombre - + Bluish Black Noir bleuté - + Vivid Purplish Blue Bleu violacé vif - + Brilliant Purplish Blue Bleu violacé brillant - + Strong Purplish Blue Bleu violacé fort - + Deep Purplish Blue Bleu violacé profond - + Very Light Purplish Blue Bleu violacé très clair - + Light Purplish Blue Bleu violacé clair - + Moderate Purplish Blue Bleu violacé modéré - + Dark Purplish Blue Bleu violacé sombre - + Very Pale Purplish Blue Bleu violacé très pâle - + Pale Purplish Blue Bleu violacé pâle - + Grayish Purplish Blue Bleu violacé grisâtre - + Vivid Violet Violet vif - + Brilliant Violet Violet brillant - + Strong Violet Violet fort - + Deep Violet Violet profond - + Very Light Violet Violet très clair - + Light Violet Violet clair - + Moderate Violet Violet modéré - + Dark Violet Violet sombre - + Very Pale Violet Violet très pâle - + Pale Violet Violet pâle - + Grayish Violet Violet grisâtre - + Vivid Purple Pourpre vif - + Brilliant Purple Pourpre brillant - + Strong Purple Pourpre fort - + Deep Purple Pourpre profond - + Very Deep Purple Pourpre très profond - + Very Light Purple Pourpre très clair - + Light Purple Pourpre clair - + Moderate Purple Pourpre modéré - + Dark Purple Pourpre sombre - + Very Dark Purple Pourpre très sombre - + Very Pale Purple Pourpre très pâle - + Pale Purple Pourpre pâle - + Grayish Purple Pourpre grisâtre - + Dark Grayish Purple Pourpre grisâtre sombre - + Blackish Purple Pourpre noirâtre - + Purplish White Blanc violacé - + Light Purplish Gray Gris clair violacé - + Purplish Gray Gris violacé - + Dark Purplish Gray Gris violacé sombre - + Purplish Black Noir violacé - + Vivid Reddish Purple Pourpre rougeâtre vif - + Strong Reddish Purple Pourpre rougeâtre fort - + Deep Reddish Purple Pourpre rougeâtre profond - + Very Deep Reddish Purple Pourpre rougeâtre très profond - + Light Reddish Purple Pourpre rougeâtre clair - + Moderate Reddish Purple Pourpre rougeâtre modéré - + Dark Reddish Purple Pourpre rougeâtre sombre - + Very Dark Reddish Purple Pourpre rougeâtre très sombre - + Pale Reddish Purple Pourpre rougeâtre pâle - + Grayish Reddish Purple Pourpre rougeâtre grisâtre - + Brilliant Purplish Pink Rose violacé brillant - + Strong Purplish Pink Rose violacé fort - + Deep Purplish Pink Rose violacé profond - + Light Purplish Pink Rose violacé clair - + Moderate Purplish Pink Rose violacé modéré - + Dark Purplish Pink Rose violacé sombre - + Pale Purplish Pink Rose violacé pâle - + Grayish Purplish Pink Rose violacé grisâtre - + Vivid Purplish Red Rouge violacé vif - + Strong Purplish Red Rouge violacé fort - + Deep Purplish Red Rouge violacé profond - + Very Deep Purplish Red Rouge violacé très profond - + Moderate Purplish Red Rouge violacé modéré - + Dark Purplish Red Rouge violacé sombre - + Very Dark Purplish Red Rouge violacé très sombre - + Light Grayish Purplish Red Rouge violacé très clair - + Grayish Purplish Red Rouge violacé grisâtre - + White Blanc - + Light Gray Gris clair - + Medium Gray Gris moyen - + Dark Gray Gris sombre - + Black Noir @@ -3333,60 +3339,60 @@ Voulez-vous enregistrer maintenant? ScribbleArea - + Warning Attention - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Vous dessinez sur un calque masqué ! Veuillez sélectionner une autre couche (ou rendre le calque visible). - + Delete Selection Undo Step: clear the selection area. Supprimer la sélection - - + + Clear Image Undo step text Effacer l'image - + There is a gap in your drawing (or maybe you have zoomed too much). Il y a un écart dans votre dessin (ou peut-être que vous avez trop zoomé). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). Pardon! Cela ne fonctionne pas toujours. Veuillez réessayer (zoomer un peu, cliquer à un autre endroit ...)<br>si cela ne fonctionne pas, zoomez un peu et vérifiez que vos chemins sont connectés en appuyant sur F1.). - + Out of bound. En dehors de la limite. - + Could not find a closed path. Impossible de trouver un chemin fermé. - + Could not find the root index. Impossible de trouver l'index racine. - + %1<br><br>Error: %2 %1<br><br>Erreur:%2 - + Flood fill error Erreur de remplissage @@ -3591,12 +3597,12 @@ Voulez-vous enregistrer maintenant? TimeLineCells - + Layer Properties Propriétés du calque - + Layer name: Nom du calque: @@ -3633,6 +3639,46 @@ Voulez-vous enregistrer maintenant? Preferences Longueur de la chronologie: + + + Drawing + Dessiner + + + + When drawing on an empty frame: + Lorsque vous dessiner sur un cadre vide: + + + + Create a new (blank) key-frame and start drawing on it. + Créer une nouvelle image clé (blanc) et commencer à dessiner dessus. + + + + Create a new (blank) key-frame + Créer une nouvelle image clé (blanc) + + + + Duplicate the previous key-frame and start drawing on the duplicate. + Dupliquer l'image clé précédente et commencer à dessiner sur le doublon. + + + + Duplicate the previous key-frame + Dupliquer l'image clé précédente + + + + Keep drawing on the previous key-frame + Continuer à dessiner sur l'image clé précédente + + + + <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + <html><head/><body><p>(S'applique aux outils Crayon, Gomme, Stylo, Polyligne, Seau et Pinceau)</p></body></html> + Frame size @@ -3876,19 +3922,19 @@ Voulez-vous enregistrer maintenant? None Stabilizer option - + Aucun Simple Stabilizer option - + Simple Strong Stabilizer option - + Fort diff --git a/translations/pencil_he.ts b/translations/pencil_he.ts index bdd528208..fa511a497 100644 --- a/translations/pencil_he.ts +++ b/translations/pencil_he.ts @@ -148,57 +148,57 @@ BaseTool - + Pencil עפרון - + Eraser מחק - + Select בחירה - + Move הזזה - + Hand יד - + Smudge טשטוש - + Pen עט - + Polyline רב-קו - + Bucket דלי - + Eyedropper טפטפת - + Brush מברשת @@ -360,8 +360,8 @@ ColorPaletteWidget - - + + Colour name שם צבע @@ -1278,7 +1278,7 @@ - + Play נגן @@ -1496,22 +1496,22 @@ הזז מסגרת אחורה - + color palette:<br>use <b>(C)</b><br>toggle at cursor מסגרת צבעים: <br>השתמש ב<b>(C)</b><br>להחליף בסמן - + Lock Windows נעל חלונות - + Open Recent פתח מהאחרונים - + You have successfully cleared the list @@ -1520,86 +1520,92 @@ מחקת בהצלחה את הרשימה - - - - + + + + + Warning אזהרה - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil2D לא הצליחה לקרוא את הקובץ. אם ברצונך לייבא תמונות, השתמש בפעולת הייבוא - + Opening document... פותח מסמך... - - - + + + Abort בטל - + Saving document... שומר מסמך: - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>שגיאה ארעה ויתכן כי הקובץ שלך לא נשמר בהצלחה. אם אתה מאמין שזו תקלה ב-Pencil2D, אנא צור דו״ח תקלה בכתובת: <br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>אנא כלול את הפרטים הבאים בדיווח שלך: - + This animation has been modified. Do you want to save your changes? הנפשה זו נערכה ושונתה. האם ברצונך לשמור השינויים? - + The animation is not saved yet. Do you want to save now? ההנפשה לא נשמרה עדיין. האם ברצונך לשמור כעת? - + Never ask again AutoSave reminder button אל תשאל שוב - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. לא ניתן לייבא תמונה.<br><b>טיפ:</b> השתמש בשכבת מפת ביטים לייבוא תמונות - + Importing image sequence... - - + + was unable to import + + + + + Undo Menu item text - + Redo Menu item text - + Stop עצור @@ -1607,122 +1613,122 @@ Object - + Black שחור - + Red אדום - + Dark Red אדום כהה - + Orange כתום - + Dark Orange כתום כהה - + Yellow צהוב - + Dark Yellow צהוב כהה - + Green ירוק - + Dark Green ירוק כהה - + Cyan תכלת ציאן - + Dark Cyan תכלת ציאן כהה - + Blue כחול - + Dark Blue כחול כהה - + White לבן - + Very Light Grey אפור בהיר מאד - + Light Grey אפור בהיר - + Grey אפור - + Dark Grey אפור כהה - + Light Skin צבע עור בהיר - + Light Skin - shade צבע עור בהיר - צללית - + Skin צבע עור - + Skin - shade צבע עור - צללית - + Dark Skin צבע עור כהה - + Dark Skin - shade צבע עור כהה - צללית @@ -1857,26 +1863,26 @@ - + Warning: Transparency is not currently supported in movie files Command line warning - + Exporting movie... Command line task progress - - + + Done. Command line task done - + Exporting image sequence... Command line task progress @@ -1937,8 +1943,8 @@ - Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - תמונות (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) + Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + @@ -1981,1337 +1987,1337 @@ Pencil Animation File PCLX(*.pclx);;Old Pencil Animation File PCL(*.pcl) - + Vivid Pink ורוד חי - + Strong Pink ורוד עז - + Deep Pink ורוד עמוק - + Light Pink ורוד בהיר - + Moderate Pink ורוד מתון - + Dark Pink ורוד כהה - + Pale Pink ורוד חיוור - + Grayish Pink ורוד אפרפר - + Pinkish White לבן ורדרד - + Pinkish Gray אפור ורדרד - + Vivid Red אדום חי - + Strong Red אדום עז - + Deep Red אדום עמוק - + Very Deep Red אדום עמוק מאד - + Moderate Red אדום מתון - + Dark Red אדום כהה - + Very Dark Red אדום כהה מאד - + Light Grayish Red אדום בהיר אפרפר - + Grayish Red אדום אפרפר - + Dark Grayish Red אדום אפרפר כהה - + Blackish Red אדום שחרחר - + Reddish Gray אפור אדמומי - + Dark Reddish Gray אפור אדמומי כהה - + Reddish Black שחור אדמומי - + Vivid Yellowish Pink ורוד צהבהב חי - + Strong Yellowish Pink ורוד צהבהב עז - + Deep Yellowish Pink ורוד צהבהב עמוק - + Light Yellowish Pink ורוד צהבהב בהיר - + Moderate Yellowish Pink ורוד צהבהב מתון - + Dark Yellowish Pink ורוד צהבהב כהה - + Pale Yellowish Pink ורוד צהבהב חיוור - + Grayish Yellowish Pink ורוד צהבהב אפרפר - + Brownish Pink ורוד חום - + Vivid Reddish Orange כתום אדמדם חי - + Strong Reddish Orange כתום אדמדם עז - + Deep Reddish Orange כתום אדמדם עמוק - + Moderate Reddish Orange כתום אדמדם מתון - + Dark Reddish Orange כתום אדמדם כהה - + Grayish Reddish Orange כתום אדמדם אפרפר - + Strong Reddish Brown חום אדמדם עז - + Deep Reddish Brown חום אדמדם עמוק - + Light Reddish Brown חום אדמדם בהיר - + Moderate Reddish Brown חום אדמדם מתון - + Dark Reddish Brown חום אדמדם כהה - + Light Grayish Reddish Brown חום אדמדם אפרפר בהיר - + Grayish Reddish Brown חום אדמדם אפרפר - + Dark Grayish Reddish Brown חום אדמדם אפרפר כהה - + Vivid Orange כתום חי - + Brilliant Orange כתום מזהיר - + Strong Orange כתום עז - + Deep Orange כתום עמוק - + Light Orange כתום בהיר - + Moderate Orange כתום מתון - + Brownish Orange כתום חום - + Strong Brown חום עז - + Deep Brown חום כהה - + Light Brown חום בהיר - + Moderate Brown חום מתון - + Dark Brown חום כהה - + Light Grayish Brown חום אפרפר בהיר - + Grayish Brown חום אפרפר - + Dark Grayish Brown חום אפרפר כהה - + Light Brownish Gray אפור חום בהיר - + Brownish Gray אפור חום - + Brownish Black שחור חום - + Vivid Orange Yellow צהוב כתמתם חי - + Brilliant Orange Yellow צהוב כתמתם מזהיר - + Strong Orange Yellow צהוב כתמתם עז - + Deep Orange Yellow צהוב כתמתם עמוק - + Light Orange Yellow צהוב כתמתם בהיר - + Moderate Orange Yellow צהוב כתמתם מתון - + Dark Orange Yellow צהוב כתמתם כהה - + Pale Orange Yellow צהוב כתמתם חיוור - + Strong Yellowish Brown חום צהבהב עז - + Deep Yellowish Brown חום צהבהב עמוק - + Light Yellowish Brown חום צהבהב בהיר - + Moderate Yellowish Brown חום צהבהב מתון - + Dark Yellowish Brown חום צהבהב כהה - + Light Grayish Yellowish Brown חום צהבהב אפרפר בהיר - + Grayish Yellowish Brown חום צהבהב אפרפר - + Dark Grayish Yellowish Brown חום צהבהב אפרפר כהה - + Vivid Yellow צהוב חי - + Brilliant Yellow צהוב מזהיר - + Strong Yellow צהוב עז - + Deep Yellow צהוב עמוק - + Light Yellow צהוב בהיר - + Moderate Yellow צהוב מתון - + Dark Yellow צהוב כהה - + Pale Yellow צהוב חיוור - + Grayish Yellow צהוב אפרפר - + Dark Grayish Yellow צהוב אפרפר כהה - + Yellowish White לבן צהבהב - + Yellowish Gray אפור צהבהב - + Light Olive Brown חום זית בהיר - + Moderate Olive Brown חום זית מתון - + Dark Olive Brown חום זית כהה - + Vivid Greenish Yellow - + Brilliant Greenish Yellow - + Strong Greenish Yellow - + Deep Greenish Yellow - + Light Greenish Yellow - + Moderate Greenish Yellow - + Dark Greenish Yellow - + Pale Greenish Yellow - + Grayish Greenish Yellow - + Light Olive - + Moderate Olive - + Dark Olive - + Light Grayish Olive - + Grayish Olive - + Dark Grayish Olive - + Light Olive Gray - + Olive Gray - + Olive Black - + Vivid Yellow Green - + Brilliant Yellow Green - + Strong Yellow Green - + Deep Yellow Green - + Light Yellow Green - + Moderate Yellow Green - + Pale Yellow Green - + Grayish Yellow Green - + Strong Olive Green - + Deep Olive Green - + Moderate Olive Green - + Dark Olive Green - + Grayish Olive Green - + Dark Grayish Olive Green - + Vivid Yellowish Green - + Brilliant Yellowish Green - + Strong Yellowish Green - + Deep Yellowish Green - + Very Deep Yellowish Green - + Very Light Yellowish Green - + Light Yellowish Green - + Moderate Yellowish Green - + Dark Yellowish Green - + Very Dark Yellowish Green - + Vivid Green - + Brilliant Green - + Strong Green - + Deep Green - + Very Light Green - + Light Green - + Moderate Green - + Dark Green - + Very Dark Green - + Very Pale Green - + Pale Green - + Grayish Green - + Dark Grayish Green - + Blackish Green - + Greenish White - + Light Greenish Gray - + Greenish Gray - + Dark Greenish Gray - + Greenish Black - + Vivid Bluish Green - + Brilliant Bluish Green - + Strong Bluish Green - + Deep Bluish Green - + Very Light Bluish Green - + Light Bluish Green - + Moderate Bluish Green - + Dark Bluish Green - + Very Dark Bluish Green - + Vivid Greenish Blue - + Brilliant Greenish Blue - + Strong Greenish Blue - + Deep Greenish Blue - + Very Light Greenish Blue - + Light Greenish Blue - + Moderate Greenish Blue - + Dark Greenish Blue - + Very Dark Greenish Blue - + Vivid Blue - + Brilliant Blue - + Strong Blue - + Deep Blue - + Very Light Blue - + Light Blue - + Moderate Blue - + Dark Blue - + Very Pale Blue - + Pale Blue - + Grayish Blue - + Dark Grayish Blue - + Blackish Blue - + Bluish White - + Light Bluish Gray - + Bluish Gray - + Dark Bluish Gray - + Bluish Black - + Vivid Purplish Blue - + Brilliant Purplish Blue - + Strong Purplish Blue - + Deep Purplish Blue - + Very Light Purplish Blue - + Light Purplish Blue - + Moderate Purplish Blue - + Dark Purplish Blue - + Very Pale Purplish Blue - + Pale Purplish Blue - + Grayish Purplish Blue - + Vivid Violet - + Brilliant Violet - + Strong Violet - + Deep Violet - + Very Light Violet - + Light Violet - + Moderate Violet - + Dark Violet - + Very Pale Violet - + Pale Violet - + Grayish Violet - + Vivid Purple - + Brilliant Purple - + Strong Purple - + Deep Purple - + Very Deep Purple - + Very Light Purple - + Light Purple - + Moderate Purple - + Dark Purple - + Very Dark Purple - + Very Pale Purple - + Pale Purple - + Grayish Purple - + Dark Grayish Purple - + Blackish Purple - + Purplish White - + Light Purplish Gray - + Purplish Gray - + Dark Purplish Gray - + Purplish Black - + Vivid Reddish Purple - + Strong Reddish Purple - + Deep Reddish Purple - + Very Deep Reddish Purple - + Light Reddish Purple - + Moderate Reddish Purple - + Dark Reddish Purple - + Very Dark Reddish Purple - + Pale Reddish Purple - + Grayish Reddish Purple - + Brilliant Purplish Pink - + Strong Purplish Pink - + Deep Purplish Pink - + Light Purplish Pink - + Moderate Purplish Pink - + Dark Purplish Pink - + Pale Purplish Pink - + Grayish Purplish Pink - + Vivid Purplish Red - + Strong Purplish Red - + Deep Purplish Red - + Very Deep Purplish Red - + Moderate Purplish Red - + Dark Purplish Red - + Very Dark Purplish Red - + Light Grayish Purplish Red - + Grayish Purplish Red - + White - + Light Gray - + Medium Gray - + Dark Gray - + Black @@ -3332,60 +3338,60 @@ ScribbleArea - + Warning אזהרה - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). אתה מצייר על שכבה נסתרת! בחר בבקשה שכבה אחרת (או הפוך את השכבה הנוכחית לנראית) - + Delete Selection Undo Step: clear the selection area. מחק את הבחירה - - + + Clear Image Undo step text מחק תמונה - + There is a gap in your drawing (or maybe you have zoomed too much). יש רווח בציור שלך (או אולי אתה ברמת הגדלה גבוהה מדי) - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). מצטערים! זה לא תמיד עובד. אנא נסה שוב (הגדל מעט, לחץ במקום אחר...) <br> אם זה לא עובד, הגדל מעט ובדוק שהקווים מחוברים על ידי לחיצה על F1). - + Out of bound. מחוץ לגבולות. - + Could not find a closed path. לא ניתן למצא קו סגור. - + Could not find the root index. לא ניתן למצוא את אינדקס השורש. - + %1<br><br>Error: %2 %1<br><br> שגיאה: %2 - + Flood fill error שגיאה במילוי שטף @@ -3590,12 +3596,12 @@ TimeLineCells - + Layer Properties מאפייני שכבה - + Layer name: שם שכבה: @@ -3632,6 +3638,46 @@ Preferences + + + Drawing + + + + + When drawing on an empty frame: + + + + + Create a new (blank) key-frame and start drawing on it. + + + + + Create a new (blank) key-frame + + + + + Duplicate the previous key-frame and start drawing on the duplicate. + + + + + Duplicate the previous key-frame + + + + + Keep drawing on the previous key-frame + + + + + <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + Frame size diff --git a/translations/pencil_hu_HU.ts b/translations/pencil_hu_HU.ts index c97430f55..192acaf2b 100644 --- a/translations/pencil_hu_HU.ts +++ b/translations/pencil_hu_HU.ts @@ -148,57 +148,57 @@ BaseTool - + Pencil Ceruza - + Eraser Radír - + Select Kijelölés - + Move Mozgatás - + Hand Kéz - + Smudge Maszatolás - + Pen Toll - + Polyline Vonallánc - + Bucket Vödör - + Eyedropper Szemcseppentő - + Brush Ecset @@ -360,8 +360,8 @@ ColorPaletteWidget - - + + Colour name Szín neve @@ -1278,7 +1278,7 @@ - + Play Lejátszás @@ -1496,107 +1496,113 @@ Képkocka mozgatása hátra - + color palette:<br>use <b>(C)</b><br>toggle at cursor Színpaletta:<br><b>(C)</b>lenyomásával<br>átváltás a kurzornál - + Lock Windows - + Open Recent Legutóbbi megnyitása - + You have successfully cleared the list - - - - + + + + + Warning Figyelmeztetés - - + + Pencil cannot read this file. If you want to import images, use the command import. A Pencil nem tudja olvasni ezt a fájlt. Képek beemeléséhez az "Importálás" művelet használható. - + Opening document... Dokumentum megnyitása... - - - + + + Abort Névjegy - + Saving document... Dokumentum mentése... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: - + This animation has been modified. Do you want to save your changes? Ez az animáció meg lett változtatva. Szeretné menteni a változásokat? - + The animation is not saved yet. Do you want to save now? - + Never ask again AutoSave reminder button - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. A kép nem importálható.<br><b>TIPP:</b> Képek importálásához bitkép réteget kell használni. - + Importing image sequence... - - + + was unable to import + + + + + Undo Menu item text - + Redo Menu item text - + Stop Megállítás @@ -1604,122 +1610,122 @@ Object - + Black Fekete - + Red Piros - + Dark Red Sötét vörös - + Orange Narancs - + Dark Orange Sötét narancs - + Yellow Sárga - + Dark Yellow Sötét sárga - + Green Zöld - + Dark Green Sötét zöld - + Cyan Cián - + Dark Cyan Sötét cián - + Blue Kék - + Dark Blue Sötét kék - + White Fehér - + Very Light Grey Halvány szürke - + Light Grey Világos szürke - + Grey Szürke - + Dark Grey Sötét szürke - + Light Skin Világos bőr - + Light Skin - shade Világos bőr - árnyék - + Skin Bőr - + Skin - shade Bőr - árnyék - + Dark Skin Sötét bőr - + Dark Skin - shade Sötét bőr - árnyék @@ -1854,26 +1860,26 @@ - + Warning: Transparency is not currently supported in movie files Command line warning - + Exporting movie... Command line task progress - - + + Done. Command line task done - + Exporting image sequence... Command line task progress @@ -1934,8 +1940,8 @@ - Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - Képek (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) + Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + @@ -1978,1337 +1984,1337 @@ - + Vivid Pink - + Strong Pink - + Deep Pink - + Light Pink - + Moderate Pink - + Dark Pink - + Pale Pink - + Grayish Pink - + Pinkish White - + Pinkish Gray - + Vivid Red - + Strong Red - + Deep Red - + Very Deep Red - + Moderate Red - + Dark Red - + Very Dark Red - + Light Grayish Red - + Grayish Red - + Dark Grayish Red - + Blackish Red - + Reddish Gray - + Dark Reddish Gray - + Reddish Black - + Vivid Yellowish Pink - + Strong Yellowish Pink - + Deep Yellowish Pink - + Light Yellowish Pink - + Moderate Yellowish Pink - + Dark Yellowish Pink - + Pale Yellowish Pink - + Grayish Yellowish Pink - + Brownish Pink - + Vivid Reddish Orange - + Strong Reddish Orange - + Deep Reddish Orange - + Moderate Reddish Orange - + Dark Reddish Orange - + Grayish Reddish Orange - + Strong Reddish Brown - + Deep Reddish Brown - + Light Reddish Brown - + Moderate Reddish Brown - + Dark Reddish Brown - + Light Grayish Reddish Brown - + Grayish Reddish Brown - + Dark Grayish Reddish Brown - + Vivid Orange - + Brilliant Orange - + Strong Orange - + Deep Orange - + Light Orange - + Moderate Orange - + Brownish Orange - + Strong Brown - + Deep Brown - + Light Brown - + Moderate Brown - + Dark Brown - + Light Grayish Brown - + Grayish Brown - + Dark Grayish Brown - + Light Brownish Gray - + Brownish Gray - + Brownish Black - + Vivid Orange Yellow - + Brilliant Orange Yellow - + Strong Orange Yellow - + Deep Orange Yellow - + Light Orange Yellow - + Moderate Orange Yellow - + Dark Orange Yellow - + Pale Orange Yellow - + Strong Yellowish Brown - + Deep Yellowish Brown - + Light Yellowish Brown - + Moderate Yellowish Brown - + Dark Yellowish Brown - + Light Grayish Yellowish Brown - + Grayish Yellowish Brown - + Dark Grayish Yellowish Brown - + Vivid Yellow - + Brilliant Yellow - + Strong Yellow - + Deep Yellow - + Light Yellow - + Moderate Yellow - + Dark Yellow - + Pale Yellow - + Grayish Yellow - + Dark Grayish Yellow - + Yellowish White - + Yellowish Gray - + Light Olive Brown - + Moderate Olive Brown - + Dark Olive Brown - + Vivid Greenish Yellow - + Brilliant Greenish Yellow - + Strong Greenish Yellow - + Deep Greenish Yellow - + Light Greenish Yellow - + Moderate Greenish Yellow - + Dark Greenish Yellow - + Pale Greenish Yellow - + Grayish Greenish Yellow - + Light Olive - + Moderate Olive - + Dark Olive - + Light Grayish Olive - + Grayish Olive - + Dark Grayish Olive - + Light Olive Gray - + Olive Gray - + Olive Black - + Vivid Yellow Green - + Brilliant Yellow Green - + Strong Yellow Green - + Deep Yellow Green - + Light Yellow Green - + Moderate Yellow Green - + Pale Yellow Green - + Grayish Yellow Green - + Strong Olive Green - + Deep Olive Green - + Moderate Olive Green - + Dark Olive Green - + Grayish Olive Green - + Dark Grayish Olive Green - + Vivid Yellowish Green - + Brilliant Yellowish Green - + Strong Yellowish Green - + Deep Yellowish Green - + Very Deep Yellowish Green - + Very Light Yellowish Green - + Light Yellowish Green - + Moderate Yellowish Green - + Dark Yellowish Green - + Very Dark Yellowish Green - + Vivid Green - + Brilliant Green - + Strong Green - + Deep Green - + Very Light Green - + Light Green - + Moderate Green - + Dark Green - + Very Dark Green - + Very Pale Green - + Pale Green - + Grayish Green - + Dark Grayish Green - + Blackish Green - + Greenish White - + Light Greenish Gray - + Greenish Gray - + Dark Greenish Gray - + Greenish Black - + Vivid Bluish Green - + Brilliant Bluish Green - + Strong Bluish Green - + Deep Bluish Green - + Very Light Bluish Green - + Light Bluish Green - + Moderate Bluish Green - + Dark Bluish Green - + Very Dark Bluish Green - + Vivid Greenish Blue - + Brilliant Greenish Blue - + Strong Greenish Blue - + Deep Greenish Blue - + Very Light Greenish Blue - + Light Greenish Blue - + Moderate Greenish Blue - + Dark Greenish Blue - + Very Dark Greenish Blue - + Vivid Blue - + Brilliant Blue - + Strong Blue - + Deep Blue - + Very Light Blue - + Light Blue - + Moderate Blue - + Dark Blue - + Very Pale Blue - + Pale Blue - + Grayish Blue - + Dark Grayish Blue - + Blackish Blue - + Bluish White - + Light Bluish Gray - + Bluish Gray - + Dark Bluish Gray - + Bluish Black - + Vivid Purplish Blue - + Brilliant Purplish Blue - + Strong Purplish Blue - + Deep Purplish Blue - + Very Light Purplish Blue - + Light Purplish Blue - + Moderate Purplish Blue - + Dark Purplish Blue - + Very Pale Purplish Blue - + Pale Purplish Blue - + Grayish Purplish Blue - + Vivid Violet - + Brilliant Violet - + Strong Violet - + Deep Violet - + Very Light Violet - + Light Violet - + Moderate Violet - + Dark Violet - + Very Pale Violet - + Pale Violet - + Grayish Violet - + Vivid Purple - + Brilliant Purple - + Strong Purple - + Deep Purple - + Very Deep Purple - + Very Light Purple - + Light Purple - + Moderate Purple - + Dark Purple - + Very Dark Purple - + Very Pale Purple - + Pale Purple - + Grayish Purple - + Dark Grayish Purple - + Blackish Purple - + Purplish White - + Light Purplish Gray - + Purplish Gray - + Dark Purplish Gray - + Purplish Black - + Vivid Reddish Purple - + Strong Reddish Purple - + Deep Reddish Purple - + Very Deep Reddish Purple - + Light Reddish Purple - + Moderate Reddish Purple - + Dark Reddish Purple - + Very Dark Reddish Purple - + Pale Reddish Purple - + Grayish Reddish Purple - + Brilliant Purplish Pink - + Strong Purplish Pink - + Deep Purplish Pink - + Light Purplish Pink - + Moderate Purplish Pink - + Dark Purplish Pink - + Pale Purplish Pink - + Grayish Purplish Pink - + Vivid Purplish Red - + Strong Purplish Red - + Deep Purplish Red - + Very Deep Purplish Red - + Moderate Purplish Red - + Dark Purplish Red - + Very Dark Purplish Red - + Light Grayish Purplish Red - + Grayish Purplish Red - + White - + Light Gray - + Medium Gray - + Dark Gray - + Black @@ -3329,60 +3335,60 @@ ScribbleArea - + Warning Figyelmeztetés - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Most egy láthatatlan rétegre rajzol! Válasszon egy másik réteget (vagy tegye láthatóvá az aktuális réteget). - + Delete Selection Undo Step: clear the selection area. - - + + Clear Image Undo step text - + There is a gap in your drawing (or maybe you have zoomed too much). Egy rés van a rajzon (vagy túlságosan fel van nagyítva). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). Elnézést! Ez nem mindig működik. Próbáld újra (egy kis nagyítással vagy máshová kattintva...)<br>Ha nem működik nagyíts egy kicsit és az F1 lenyomásával ellenőrizd, hogy az útvonalak összeérnek-e.). - + Out of bound. Tartományon kívül. - + Could not find a closed path. Nem található zárt útvonal. - + Could not find the root index. Nem található a gyökér index. - + %1<br><br>Error: %2 %1<br><br>Hiba: %2 - + Flood fill error Kitöltési hiba @@ -3587,12 +3593,12 @@ TimeLineCells - + Layer Properties - + Layer name: @@ -3629,6 +3635,46 @@ Preferences + + + Drawing + + + + + When drawing on an empty frame: + + + + + Create a new (blank) key-frame and start drawing on it. + + + + + Create a new (blank) key-frame + + + + + Duplicate the previous key-frame and start drawing on the duplicate. + + + + + Duplicate the previous key-frame + + + + + Keep drawing on the previous key-frame + + + + + <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + Frame size diff --git a/translations/pencil_id.ts b/translations/pencil_id.ts index 2f6f2f304..a1c826936 100644 --- a/translations/pencil_id.ts +++ b/translations/pencil_id.ts @@ -148,57 +148,57 @@ BaseTool - + Pencil Pensil - + Eraser Penghapus - + Select Pilih - + Move Pindah - + Hand Tangan - + Smudge - + Pen - + Polyline - + Bucket Ember - + Eyedropper Tetes mata - + Brush Kuas @@ -360,8 +360,8 @@ ColorPaletteWidget - - + + Colour name Nama warna @@ -1278,7 +1278,7 @@ - + Play @@ -1496,106 +1496,112 @@ - + color palette:<br>use <b>(C)</b><br>toggle at cursor - + Lock Windows - + Open Recent - + You have successfully cleared the list - - - - + + + + + Warning - - + + Pencil cannot read this file. If you want to import images, use the command import. - + Opening document... - - - + + + Abort - + Saving document... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: - + This animation has been modified. Do you want to save your changes? - + The animation is not saved yet. Do you want to save now? - + Never ask again AutoSave reminder button - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. - + Importing image sequence... - - + + was unable to import + + + + + Undo Menu item text - + Redo Menu item text - + Stop @@ -1603,122 +1609,122 @@ Object - + Black - + Red - + Dark Red - + Orange - + Dark Orange - + Yellow - + Dark Yellow - + Green - + Dark Green - + Cyan - + Dark Cyan - + Blue - + Dark Blue - + White - + Very Light Grey - + Light Grey - + Grey - + Dark Grey - + Light Skin - + Light Skin - shade - + Skin - + Skin - shade - + Dark Skin - + Dark Skin - shade @@ -1853,26 +1859,26 @@ - + Warning: Transparency is not currently supported in movie files Command line warning - + Exporting movie... Command line task progress - - + + Done. Command line task done - + Exporting image sequence... Command line task progress @@ -1933,7 +1939,7 @@ - Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) + Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) @@ -1977,1337 +1983,1337 @@ - + Vivid Pink - + Strong Pink - + Deep Pink - + Light Pink - + Moderate Pink - + Dark Pink - + Pale Pink - + Grayish Pink - + Pinkish White - + Pinkish Gray - + Vivid Red - + Strong Red - + Deep Red - + Very Deep Red - + Moderate Red - + Dark Red - + Very Dark Red - + Light Grayish Red - + Grayish Red - + Dark Grayish Red - + Blackish Red - + Reddish Gray - + Dark Reddish Gray - + Reddish Black - + Vivid Yellowish Pink - + Strong Yellowish Pink - + Deep Yellowish Pink - + Light Yellowish Pink - + Moderate Yellowish Pink - + Dark Yellowish Pink - + Pale Yellowish Pink - + Grayish Yellowish Pink - + Brownish Pink - + Vivid Reddish Orange - + Strong Reddish Orange - + Deep Reddish Orange - + Moderate Reddish Orange - + Dark Reddish Orange - + Grayish Reddish Orange - + Strong Reddish Brown - + Deep Reddish Brown - + Light Reddish Brown - + Moderate Reddish Brown - + Dark Reddish Brown - + Light Grayish Reddish Brown - + Grayish Reddish Brown - + Dark Grayish Reddish Brown - + Vivid Orange - + Brilliant Orange - + Strong Orange - + Deep Orange - + Light Orange - + Moderate Orange - + Brownish Orange - + Strong Brown - + Deep Brown - + Light Brown - + Moderate Brown - + Dark Brown - + Light Grayish Brown - + Grayish Brown - + Dark Grayish Brown - + Light Brownish Gray - + Brownish Gray - + Brownish Black - + Vivid Orange Yellow - + Brilliant Orange Yellow - + Strong Orange Yellow - + Deep Orange Yellow - + Light Orange Yellow - + Moderate Orange Yellow - + Dark Orange Yellow - + Pale Orange Yellow - + Strong Yellowish Brown - + Deep Yellowish Brown - + Light Yellowish Brown - + Moderate Yellowish Brown - + Dark Yellowish Brown - + Light Grayish Yellowish Brown - + Grayish Yellowish Brown - + Dark Grayish Yellowish Brown - + Vivid Yellow - + Brilliant Yellow - + Strong Yellow - + Deep Yellow - + Light Yellow - + Moderate Yellow - + Dark Yellow - + Pale Yellow - + Grayish Yellow - + Dark Grayish Yellow - + Yellowish White - + Yellowish Gray - + Light Olive Brown - + Moderate Olive Brown - + Dark Olive Brown - + Vivid Greenish Yellow - + Brilliant Greenish Yellow - + Strong Greenish Yellow - + Deep Greenish Yellow - + Light Greenish Yellow - + Moderate Greenish Yellow - + Dark Greenish Yellow - + Pale Greenish Yellow - + Grayish Greenish Yellow - + Light Olive - + Moderate Olive - + Dark Olive - + Light Grayish Olive - + Grayish Olive - + Dark Grayish Olive - + Light Olive Gray - + Olive Gray - + Olive Black - + Vivid Yellow Green - + Brilliant Yellow Green - + Strong Yellow Green - + Deep Yellow Green - + Light Yellow Green - + Moderate Yellow Green - + Pale Yellow Green - + Grayish Yellow Green - + Strong Olive Green - + Deep Olive Green - + Moderate Olive Green - + Dark Olive Green - + Grayish Olive Green - + Dark Grayish Olive Green - + Vivid Yellowish Green - + Brilliant Yellowish Green - + Strong Yellowish Green - + Deep Yellowish Green - + Very Deep Yellowish Green - + Very Light Yellowish Green - + Light Yellowish Green - + Moderate Yellowish Green - + Dark Yellowish Green - + Very Dark Yellowish Green - + Vivid Green - + Brilliant Green - + Strong Green - + Deep Green - + Very Light Green - + Light Green - + Moderate Green - + Dark Green - + Very Dark Green - + Very Pale Green - + Pale Green - + Grayish Green - + Dark Grayish Green - + Blackish Green - + Greenish White - + Light Greenish Gray - + Greenish Gray - + Dark Greenish Gray - + Greenish Black - + Vivid Bluish Green - + Brilliant Bluish Green - + Strong Bluish Green - + Deep Bluish Green - + Very Light Bluish Green - + Light Bluish Green - + Moderate Bluish Green - + Dark Bluish Green - + Very Dark Bluish Green - + Vivid Greenish Blue - + Brilliant Greenish Blue - + Strong Greenish Blue - + Deep Greenish Blue - + Very Light Greenish Blue - + Light Greenish Blue - + Moderate Greenish Blue - + Dark Greenish Blue - + Very Dark Greenish Blue - + Vivid Blue - + Brilliant Blue - + Strong Blue - + Deep Blue - + Very Light Blue - + Light Blue - + Moderate Blue - + Dark Blue - + Very Pale Blue - + Pale Blue - + Grayish Blue - + Dark Grayish Blue - + Blackish Blue - + Bluish White - + Light Bluish Gray - + Bluish Gray - + Dark Bluish Gray - + Bluish Black - + Vivid Purplish Blue - + Brilliant Purplish Blue - + Strong Purplish Blue - + Deep Purplish Blue - + Very Light Purplish Blue - + Light Purplish Blue - + Moderate Purplish Blue - + Dark Purplish Blue - + Very Pale Purplish Blue - + Pale Purplish Blue - + Grayish Purplish Blue - + Vivid Violet - + Brilliant Violet - + Strong Violet - + Deep Violet - + Very Light Violet - + Light Violet - + Moderate Violet - + Dark Violet - + Very Pale Violet - + Pale Violet - + Grayish Violet - + Vivid Purple - + Brilliant Purple - + Strong Purple - + Deep Purple - + Very Deep Purple - + Very Light Purple - + Light Purple - + Moderate Purple - + Dark Purple - + Very Dark Purple - + Very Pale Purple - + Pale Purple Ungu Pucat - + Grayish Purple - + Dark Grayish Purple - + Blackish Purple - + Purplish White - + Light Purplish Gray - + Purplish Gray - + Dark Purplish Gray - + Purplish Black - + Vivid Reddish Purple - + Strong Reddish Purple - + Deep Reddish Purple - + Very Deep Reddish Purple - + Light Reddish Purple - + Moderate Reddish Purple - + Dark Reddish Purple - + Very Dark Reddish Purple - + Pale Reddish Purple - + Grayish Reddish Purple - + Brilliant Purplish Pink - + Strong Purplish Pink - + Deep Purplish Pink - + Light Purplish Pink - + Moderate Purplish Pink - + Dark Purplish Pink - + Pale Purplish Pink - + Grayish Purplish Pink - + Vivid Purplish Red - + Strong Purplish Red - + Deep Purplish Red - + Very Deep Purplish Red - + Moderate Purplish Red - + Dark Purplish Red - + Very Dark Purplish Red - + Light Grayish Purplish Red - + Grayish Purplish Red - + White Putih - + Light Gray Abu-abu Cerah - + Medium Gray Abu-abu Sedang - + Dark Gray Abu-abu Gelap - + Black Hitam @@ -3328,60 +3334,60 @@ ScribbleArea - + Warning - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). - + Delete Selection Undo Step: clear the selection area. - - + + Clear Image Undo step text - + There is a gap in your drawing (or maybe you have zoomed too much). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). - + Out of bound. - + Could not find a closed path. - + Could not find the root index. - + %1<br><br>Error: %2 - + Flood fill error @@ -3586,12 +3592,12 @@ TimeLineCells - + Layer Properties - + Layer name: @@ -3628,6 +3634,46 @@ Preferences + + + Drawing + + + + + When drawing on an empty frame: + + + + + Create a new (blank) key-frame and start drawing on it. + + + + + Create a new (blank) key-frame + + + + + Duplicate the previous key-frame and start drawing on the duplicate. + + + + + Duplicate the previous key-frame + + + + + Keep drawing on the previous key-frame + + + + + <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + Frame size diff --git a/translations/pencil_it.ts b/translations/pencil_it.ts index 6ebb8ed05..0a278f446 100644 --- a/translations/pencil_it.ts +++ b/translations/pencil_it.ts @@ -148,57 +148,57 @@ BaseTool - + Pencil Matita - + Eraser Gomma - + Select Seleziona - + Move Sposta - + Hand Mano - + Smudge Sfuma - + Pen Penna - + Polyline Polilinea - + Bucket Secchiello - + Eyedropper Contagocce - + Brush Pennello @@ -360,8 +360,8 @@ ColorPaletteWidget - - + + Colour name Nome colore @@ -1278,7 +1278,7 @@ - + Play Riproduci @@ -1496,107 +1496,113 @@ Sposta fotogramma indietro - + color palette:<br>use <b>(C)</b><br>toggle at cursor tavolozza colori:<br>usare<b>(C)</b><br>per aprire/chiudere al cursore - + Lock Windows - + Open Recent Apri recenti - + You have successfully cleared the list - - - - + + + + + Warning Attenzione - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil non può leggere questo file. Per importare immagini usare il comando importa. - + Opening document... Apertura del documento... - - - + + + Abort Annulla - + Saving document... Salvataggio del documento... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: - + This animation has been modified. Do you want to save your changes? Questa animazione è stata modificata. Vuoi salavare i cambiamenti? - + The animation is not saved yet. Do you want to save now? L'animazione non è ancora salvata. Vuoi salvarla ora? - + Never ask again AutoSave reminder button Non chiederlo più - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Impossibile caricare l'immagine.<br><b>Suggerimento:</b> usare un livello bitmap per importarla. - + Importing image sequence... - - + + was unable to import + + + + + Undo Menu item text - + Redo Menu item text - + Stop Stop @@ -1604,122 +1610,122 @@ Vuoi salavare i cambiamenti? Object - + Black Nero - + Red Rosso - + Dark Red Rosso scuro - + Orange Arancio - + Dark Orange Arancio scuro - + Yellow Giallo - + Dark Yellow Giallo scuro - + Green Verde - + Dark Green Verde scuro - + Cyan Ciano - + Dark Cyan Ciano scuro - + Blue Blu - + Dark Blue Blu scuro - + White Bianco - + Very Light Grey Grigio molto chiaro - + Light Grey Grigio chiaro - + Grey Grigio - + Dark Grey Grigio scuro - + Light Skin Pelle chiaro - + Light Skin - shade Pelle chiaro - sfumato - + Skin Pelle - + Skin - shade Pelle - sfumato - + Dark Skin Pelle scuro - + Dark Skin - shade Pelle scuro - sfumato @@ -1854,26 +1860,26 @@ Vuoi salavare i cambiamenti? - + Warning: Transparency is not currently supported in movie files Command line warning - + Exporting movie... Command line task progress - - + + Done. Command line task done - + Exporting image sequence... Command line task progress @@ -1934,8 +1940,8 @@ Vuoi salavare i cambiamenti? - Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - Immagini (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) + Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + @@ -1978,1337 +1984,1337 @@ Vuoi salavare i cambiamenti? - + Vivid Pink - + Strong Pink - + Deep Pink - + Light Pink - + Moderate Pink - + Dark Pink - + Pale Pink - + Grayish Pink - + Pinkish White - + Pinkish Gray - + Vivid Red - + Strong Red - + Deep Red - + Very Deep Red - + Moderate Red - + Dark Red - + Very Dark Red - + Light Grayish Red - + Grayish Red - + Dark Grayish Red - + Blackish Red - + Reddish Gray - + Dark Reddish Gray - + Reddish Black - + Vivid Yellowish Pink - + Strong Yellowish Pink - + Deep Yellowish Pink - + Light Yellowish Pink - + Moderate Yellowish Pink - + Dark Yellowish Pink - + Pale Yellowish Pink - + Grayish Yellowish Pink - + Brownish Pink - + Vivid Reddish Orange - + Strong Reddish Orange - + Deep Reddish Orange - + Moderate Reddish Orange - + Dark Reddish Orange - + Grayish Reddish Orange - + Strong Reddish Brown - + Deep Reddish Brown - + Light Reddish Brown - + Moderate Reddish Brown - + Dark Reddish Brown - + Light Grayish Reddish Brown - + Grayish Reddish Brown - + Dark Grayish Reddish Brown - + Vivid Orange - + Brilliant Orange - + Strong Orange - + Deep Orange - + Light Orange - + Moderate Orange - + Brownish Orange - + Strong Brown - + Deep Brown - + Light Brown - + Moderate Brown - + Dark Brown - + Light Grayish Brown - + Grayish Brown - + Dark Grayish Brown - + Light Brownish Gray - + Brownish Gray - + Brownish Black - + Vivid Orange Yellow - + Brilliant Orange Yellow - + Strong Orange Yellow - + Deep Orange Yellow - + Light Orange Yellow - + Moderate Orange Yellow - + Dark Orange Yellow - + Pale Orange Yellow - + Strong Yellowish Brown - + Deep Yellowish Brown - + Light Yellowish Brown - + Moderate Yellowish Brown - + Dark Yellowish Brown - + Light Grayish Yellowish Brown - + Grayish Yellowish Brown - + Dark Grayish Yellowish Brown - + Vivid Yellow - + Brilliant Yellow - + Strong Yellow - + Deep Yellow - + Light Yellow - + Moderate Yellow - + Dark Yellow - + Pale Yellow - + Grayish Yellow - + Dark Grayish Yellow - + Yellowish White - + Yellowish Gray - + Light Olive Brown - + Moderate Olive Brown - + Dark Olive Brown - + Vivid Greenish Yellow - + Brilliant Greenish Yellow - + Strong Greenish Yellow - + Deep Greenish Yellow - + Light Greenish Yellow - + Moderate Greenish Yellow - + Dark Greenish Yellow - + Pale Greenish Yellow - + Grayish Greenish Yellow - + Light Olive - + Moderate Olive - + Dark Olive - + Light Grayish Olive - + Grayish Olive - + Dark Grayish Olive - + Light Olive Gray - + Olive Gray - + Olive Black - + Vivid Yellow Green - + Brilliant Yellow Green - + Strong Yellow Green - + Deep Yellow Green - + Light Yellow Green - + Moderate Yellow Green - + Pale Yellow Green - + Grayish Yellow Green - + Strong Olive Green - + Deep Olive Green - + Moderate Olive Green - + Dark Olive Green - + Grayish Olive Green - + Dark Grayish Olive Green - + Vivid Yellowish Green - + Brilliant Yellowish Green - + Strong Yellowish Green - + Deep Yellowish Green - + Very Deep Yellowish Green - + Very Light Yellowish Green - + Light Yellowish Green - + Moderate Yellowish Green - + Dark Yellowish Green - + Very Dark Yellowish Green - + Vivid Green - + Brilliant Green - + Strong Green - + Deep Green - + Very Light Green - + Light Green - + Moderate Green - + Dark Green - + Very Dark Green - + Very Pale Green - + Pale Green - + Grayish Green - + Dark Grayish Green - + Blackish Green - + Greenish White - + Light Greenish Gray - + Greenish Gray - + Dark Greenish Gray - + Greenish Black - + Vivid Bluish Green - + Brilliant Bluish Green - + Strong Bluish Green - + Deep Bluish Green - + Very Light Bluish Green - + Light Bluish Green - + Moderate Bluish Green - + Dark Bluish Green - + Very Dark Bluish Green - + Vivid Greenish Blue - + Brilliant Greenish Blue - + Strong Greenish Blue - + Deep Greenish Blue - + Very Light Greenish Blue - + Light Greenish Blue - + Moderate Greenish Blue - + Dark Greenish Blue - + Very Dark Greenish Blue - + Vivid Blue - + Brilliant Blue - + Strong Blue - + Deep Blue - + Very Light Blue - + Light Blue - + Moderate Blue - + Dark Blue - + Very Pale Blue - + Pale Blue - + Grayish Blue - + Dark Grayish Blue - + Blackish Blue - + Bluish White - + Light Bluish Gray - + Bluish Gray - + Dark Bluish Gray - + Bluish Black - + Vivid Purplish Blue - + Brilliant Purplish Blue - + Strong Purplish Blue - + Deep Purplish Blue - + Very Light Purplish Blue - + Light Purplish Blue - + Moderate Purplish Blue - + Dark Purplish Blue - + Very Pale Purplish Blue - + Pale Purplish Blue - + Grayish Purplish Blue - + Vivid Violet - + Brilliant Violet - + Strong Violet - + Deep Violet - + Very Light Violet - + Light Violet - + Moderate Violet - + Dark Violet - + Very Pale Violet - + Pale Violet - + Grayish Violet - + Vivid Purple - + Brilliant Purple - + Strong Purple - + Deep Purple - + Very Deep Purple - + Very Light Purple - + Light Purple - + Moderate Purple - + Dark Purple - + Very Dark Purple - + Very Pale Purple - + Pale Purple - + Grayish Purple - + Dark Grayish Purple - + Blackish Purple - + Purplish White - + Light Purplish Gray - + Purplish Gray - + Dark Purplish Gray - + Purplish Black - + Vivid Reddish Purple - + Strong Reddish Purple - + Deep Reddish Purple - + Very Deep Reddish Purple - + Light Reddish Purple - + Moderate Reddish Purple - + Dark Reddish Purple - + Very Dark Reddish Purple - + Pale Reddish Purple - + Grayish Reddish Purple - + Brilliant Purplish Pink - + Strong Purplish Pink - + Deep Purplish Pink - + Light Purplish Pink - + Moderate Purplish Pink - + Dark Purplish Pink - + Pale Purplish Pink - + Grayish Purplish Pink - + Vivid Purplish Red - + Strong Purplish Red - + Deep Purplish Red - + Very Deep Purplish Red - + Moderate Purplish Red - + Dark Purplish Red - + Very Dark Purplish Red - + Light Grayish Purplish Red - + Grayish Purplish Red - + White - + Light Gray - + Medium Gray - + Dark Gray - + Black @@ -3329,60 +3335,60 @@ Vuoi salavare i cambiamenti? ScribbleArea - + Warning Attenzione - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Si sta disegnando su un livello nascosto! Scegliere un altro livello (o rendere visibile questo livello). - + Delete Selection Undo Step: clear the selection area. - - + + Clear Image Undo step text Cancella immagine - + There is a gap in your drawing (or maybe you have zoomed too much). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). - + Out of bound. - + Could not find a closed path. - + Could not find the root index. - + %1<br><br>Error: %2 %1<br><br>Errore: %2 - + Flood fill error Errore di riempimento @@ -3587,12 +3593,12 @@ Vuoi salavare i cambiamenti? TimeLineCells - + Layer Properties - + Layer name: @@ -3629,6 +3635,46 @@ Vuoi salavare i cambiamenti? Preferences + + + Drawing + + + + + When drawing on an empty frame: + + + + + Create a new (blank) key-frame and start drawing on it. + + + + + Create a new (blank) key-frame + + + + + Duplicate the previous key-frame and start drawing on the duplicate. + + + + + Duplicate the previous key-frame + + + + + Keep drawing on the previous key-frame + + + + + <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + Frame size diff --git a/translations/pencil_ja.ts b/translations/pencil_ja.ts index 4216dc1d2..440988f35 100644 --- a/translations/pencil_ja.ts +++ b/translations/pencil_ja.ts @@ -148,57 +148,57 @@ BaseTool - + Pencil 鉛筆 - + Eraser 消しゴム - + Select 選択 - + Move 移動 - + Hand 手のひら - + Smudge こする - + Pen ペン - + Polyline 折れ線 - + Bucket バケツ - + Eyedropper スポイト - + Brush ブラシ @@ -360,8 +360,8 @@ ColorPaletteWidget - - + + Colour name 色名 @@ -1278,7 +1278,7 @@ - + Play 再生 @@ -1496,107 +1496,113 @@ 前のフレームに移動 - + color palette:<br>use <b>(C)</b><br>toggle at cursor - + Lock Windows - + Open Recent 最近使ったファイル - + You have successfully cleared the list リストは正常に削除されました - - - - + + + + + Warning 警告 - - + + Pencil cannot read this file. If you want to import images, use the command import. 読み込みエラーです。画像を読み込む場合は「読み込む」コマンドを使用して下さい。 - + Opening document... ドキュメントを開いています... - - - + + + Abort 中断 - + Saving document... ドキュメントを保存しています... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>エラーによってファイルが正常に保存されなかった可能性があります。もしこのエラーがPencil2Dによって起こったと推測される場合は, <br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>にアクセスして新しい"issue"として報告してください。ご報告の際は、以下の詳細を追記してください: - + This animation has been modified. Do you want to save your changes? ファイルの変更があります。 これらの変更を保存しますか? - + The animation is not saved yet. Do you want to save now? - + Never ask again AutoSave reminder button - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. 画像が読み込めません。<br><b>ヒント:</b> ビットマップファイルはビットマップレイヤーに読み込んでください。 - + Importing image sequence... - - + + was unable to import + + + + + Undo Menu item text - + Redo Menu item text - + Stop 停止 @@ -1604,122 +1610,122 @@ Object - + Black - + Red - + Dark Red 暗い赤 - + Orange オレンジ - + Dark Orange 暗いオレンジ - + Yellow 黄色 - + Dark Yellow 暗い黄色 - + Green - + Dark Green 暗い緑 - + Cyan シアン - + Dark Cyan 暗いシアン - + Blue - + Dark Blue 暗い青 - + White - + Very Light Grey 非常に明るい灰色 - + Light Grey 明るい灰色 - + Grey 灰色 - + Dark Grey 暗い灰色 - + Light Skin 明るい肌色 - + Light Skin - shade 明るい肌色 (陰) - + Skin 肌色 - + Skin - shade 肌色 (陰) - + Dark Skin 暗い肌色 - + Dark Skin - shade 暗い肌色 (陰) @@ -1854,26 +1860,26 @@ - + Warning: Transparency is not currently supported in movie files Command line warning - + Exporting movie... Command line task progress - - + + Done. Command line task done - + Exporting image sequence... Command line task progress @@ -1934,8 +1940,8 @@ - Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - 画像 (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) + Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + @@ -1978,1337 +1984,1337 @@ Pencil Animation ファイル PCLX(*.pclx);;Old Pencil Animation File PCL(*.pcl) - + Vivid Pink - + Strong Pink - + Deep Pink - + Light Pink - + Moderate Pink - + Dark Pink - + Pale Pink - + Grayish Pink - + Pinkish White - + Pinkish Gray - + Vivid Red - + Strong Red - + Deep Red - + Very Deep Red - + Moderate Red - + Dark Red - + Very Dark Red - + Light Grayish Red - + Grayish Red - + Dark Grayish Red - + Blackish Red - + Reddish Gray - + Dark Reddish Gray - + Reddish Black - + Vivid Yellowish Pink - + Strong Yellowish Pink - + Deep Yellowish Pink - + Light Yellowish Pink - + Moderate Yellowish Pink - + Dark Yellowish Pink - + Pale Yellowish Pink - + Grayish Yellowish Pink - + Brownish Pink - + Vivid Reddish Orange - + Strong Reddish Orange - + Deep Reddish Orange - + Moderate Reddish Orange - + Dark Reddish Orange - + Grayish Reddish Orange - + Strong Reddish Brown - + Deep Reddish Brown - + Light Reddish Brown - + Moderate Reddish Brown - + Dark Reddish Brown - + Light Grayish Reddish Brown - + Grayish Reddish Brown - + Dark Grayish Reddish Brown - + Vivid Orange - + Brilliant Orange - + Strong Orange - + Deep Orange - + Light Orange - + Moderate Orange - + Brownish Orange - + Strong Brown - + Deep Brown - + Light Brown - + Moderate Brown - + Dark Brown - + Light Grayish Brown - + Grayish Brown - + Dark Grayish Brown - + Light Brownish Gray - + Brownish Gray - + Brownish Black - + Vivid Orange Yellow - + Brilliant Orange Yellow - + Strong Orange Yellow - + Deep Orange Yellow - + Light Orange Yellow - + Moderate Orange Yellow - + Dark Orange Yellow - + Pale Orange Yellow - + Strong Yellowish Brown - + Deep Yellowish Brown - + Light Yellowish Brown - + Moderate Yellowish Brown - + Dark Yellowish Brown - + Light Grayish Yellowish Brown - + Grayish Yellowish Brown - + Dark Grayish Yellowish Brown - + Vivid Yellow - + Brilliant Yellow - + Strong Yellow - + Deep Yellow - + Light Yellow - + Moderate Yellow - + Dark Yellow - + Pale Yellow - + Grayish Yellow - + Dark Grayish Yellow - + Yellowish White - + Yellowish Gray - + Light Olive Brown - + Moderate Olive Brown - + Dark Olive Brown - + Vivid Greenish Yellow - + Brilliant Greenish Yellow - + Strong Greenish Yellow - + Deep Greenish Yellow - + Light Greenish Yellow - + Moderate Greenish Yellow - + Dark Greenish Yellow - + Pale Greenish Yellow - + Grayish Greenish Yellow - + Light Olive - + Moderate Olive - + Dark Olive - + Light Grayish Olive - + Grayish Olive - + Dark Grayish Olive - + Light Olive Gray - + Olive Gray - + Olive Black - + Vivid Yellow Green - + Brilliant Yellow Green - + Strong Yellow Green - + Deep Yellow Green - + Light Yellow Green - + Moderate Yellow Green - + Pale Yellow Green - + Grayish Yellow Green - + Strong Olive Green - + Deep Olive Green - + Moderate Olive Green - + Dark Olive Green - + Grayish Olive Green - + Dark Grayish Olive Green - + Vivid Yellowish Green - + Brilliant Yellowish Green - + Strong Yellowish Green - + Deep Yellowish Green - + Very Deep Yellowish Green - + Very Light Yellowish Green - + Light Yellowish Green - + Moderate Yellowish Green - + Dark Yellowish Green - + Very Dark Yellowish Green - + Vivid Green - + Brilliant Green - + Strong Green - + Deep Green - + Very Light Green - + Light Green - + Moderate Green - + Dark Green - + Very Dark Green - + Very Pale Green - + Pale Green - + Grayish Green - + Dark Grayish Green - + Blackish Green - + Greenish White - + Light Greenish Gray - + Greenish Gray - + Dark Greenish Gray - + Greenish Black - + Vivid Bluish Green - + Brilliant Bluish Green - + Strong Bluish Green - + Deep Bluish Green - + Very Light Bluish Green - + Light Bluish Green - + Moderate Bluish Green - + Dark Bluish Green - + Very Dark Bluish Green - + Vivid Greenish Blue - + Brilliant Greenish Blue - + Strong Greenish Blue - + Deep Greenish Blue - + Very Light Greenish Blue - + Light Greenish Blue - + Moderate Greenish Blue - + Dark Greenish Blue - + Very Dark Greenish Blue - + Vivid Blue - + Brilliant Blue - + Strong Blue - + Deep Blue - + Very Light Blue - + Light Blue - + Moderate Blue - + Dark Blue - + Very Pale Blue - + Pale Blue - + Grayish Blue - + Dark Grayish Blue - + Blackish Blue - + Bluish White - + Light Bluish Gray - + Bluish Gray - + Dark Bluish Gray - + Bluish Black - + Vivid Purplish Blue - + Brilliant Purplish Blue - + Strong Purplish Blue - + Deep Purplish Blue - + Very Light Purplish Blue - + Light Purplish Blue - + Moderate Purplish Blue - + Dark Purplish Blue - + Very Pale Purplish Blue - + Pale Purplish Blue - + Grayish Purplish Blue - + Vivid Violet - + Brilliant Violet - + Strong Violet - + Deep Violet - + Very Light Violet - + Light Violet - + Moderate Violet - + Dark Violet - + Very Pale Violet - + Pale Violet - + Grayish Violet - + Vivid Purple - + Brilliant Purple - + Strong Purple - + Deep Purple - + Very Deep Purple - + Very Light Purple - + Light Purple - + Moderate Purple - + Dark Purple - + Very Dark Purple - + Very Pale Purple - + Pale Purple - + Grayish Purple - + Dark Grayish Purple - + Blackish Purple - + Purplish White - + Light Purplish Gray - + Purplish Gray - + Dark Purplish Gray - + Purplish Black - + Vivid Reddish Purple - + Strong Reddish Purple - + Deep Reddish Purple - + Very Deep Reddish Purple - + Light Reddish Purple - + Moderate Reddish Purple - + Dark Reddish Purple - + Very Dark Reddish Purple - + Pale Reddish Purple - + Grayish Reddish Purple - + Brilliant Purplish Pink - + Strong Purplish Pink - + Deep Purplish Pink - + Light Purplish Pink - + Moderate Purplish Pink - + Dark Purplish Pink - + Pale Purplish Pink - + Grayish Purplish Pink - + Vivid Purplish Red - + Strong Purplish Red - + Deep Purplish Red - + Very Deep Purplish Red - + Moderate Purplish Red - + Dark Purplish Red - + Very Dark Purplish Red - + Light Grayish Purplish Red - + Grayish Purplish Red - + White - + Light Gray - + Medium Gray - + Dark Gray - + Black @@ -3329,60 +3335,60 @@ ScribbleArea - + Warning 警告 - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). 選択中のレイヤーは非表示に設定されています。このレイヤーを表示するか他のレイヤーを選択して下さい。 - + Delete Selection Undo Step: clear the selection area. - - + + Clear Image Undo step text 画像をクリア - + There is a gap in your drawing (or maybe you have zoomed too much). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). - + Out of bound. 有効範囲の外です。 - + Could not find a closed path. 閉じられたパスがありません。 - + Could not find the root index. - + %1<br><br>Error: %2 %1<br><br>エラー: %2 - + Flood fill error 塗りつぶし中にエラーが発生しました @@ -3587,12 +3593,12 @@ TimeLineCells - + Layer Properties - + Layer name: @@ -3629,6 +3635,46 @@ Preferences + + + Drawing + + + + + When drawing on an empty frame: + + + + + Create a new (blank) key-frame and start drawing on it. + + + + + Create a new (blank) key-frame + + + + + Duplicate the previous key-frame and start drawing on the duplicate. + + + + + Duplicate the previous key-frame + + + + + Keep drawing on the previous key-frame + + + + + <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + Frame size diff --git a/translations/pencil_pl.ts b/translations/pencil_pl.ts index ec59b6f54..4716ee95b 100644 --- a/translations/pencil_pl.ts +++ b/translations/pencil_pl.ts @@ -1,6 +1,4 @@ - - - + AboutDialog @@ -229,7 +227,7 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">re Color Wheel - Color Wheel's window title + Color Wheel's window title Koło kolorów @@ -4008,4 +4006,4 @@ jeżeli to nie pomoże, to spróbuj powiększyć i sprawdź, czy ścieżki są p Szybkie wymiarowanie - + \ No newline at end of file diff --git a/translations/pencil_pt.ts b/translations/pencil_pt.ts index d24df45d6..82294336f 100644 --- a/translations/pencil_pt.ts +++ b/translations/pencil_pt.ts @@ -148,57 +148,57 @@ BaseTool - + Pencil Lápis - + Eraser Borracha - + Select Seleccionar - + Move Mover - + Hand Mão - + Smudge Espalhar - + Pen Caneta - + Polyline Polilinha - + Bucket Balde - + Eyedropper Conta-gotas - + Brush Pincel @@ -360,8 +360,8 @@ ColorPaletteWidget - - + + Colour name Nome da cor @@ -1278,7 +1278,7 @@ - + Play Reproduzir @@ -1496,22 +1496,22 @@ Mover Quadro para Trás - + color palette:<br>use <b>(C)</b><br>toggle at cursor Paleta de cores:<br>Utilize <b>(C)</b><br>para alternar no cursor - + Lock Windows Bloquear Janelas - + Open Recent Abrir Recente - + You have successfully cleared the list @@ -1519,85 +1519,91 @@ Acabou de limpar a lista com sucesso - - - - + + + + + Warning Aviso - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil não consegue ler este arquivo. Se você quiser importar imagens, use o comando Importar. - + Opening document... Abrindo documento... - - - + + + Abort Abortar - + Saving document... Gravando documento... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>Ocorreu um erro e seu ficheiro pode não ter sido gravado com sucesso. Se você achar que é um problema com Pencil2D, por favor crie um tópico em: <br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Por favor, certifique-se de incluir os seguintes detalhes: - + This animation has been modified. Do you want to save your changes? Esta animação foi modificada. Deseja gravar as alterações? - + The animation is not saved yet. Do you want to save now? A animação não foi gravada. Quer gravá-la agora? - + Never ask again AutoSave reminder button Não voltar a perguntar - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Não é possível importar imagem. <br><b>DICA:</b> Use uma Camada Bitmap para importar bitmaps. - + Importing image sequence... Importando sequência de imagens... - - + + was unable to import + + + + + Undo Menu item text Desfazer - + Redo Menu item text Refazer - + Stop Parar @@ -1605,122 +1611,122 @@ Deseja gravar as alterações? Object - + Black Preto - + Red Vermelho - + Dark Red Vermelho escuro - + Orange Laranja - + Dark Orange Laranja escuro - + Yellow Amarelo - + Dark Yellow Amarelo escuro - + Green Verde - + Dark Green Verde escuro - + Cyan Ciano - + Dark Cyan Ciano escuro - + Blue Azul - + Dark Blue Azul escuro - + White Branco - + Very Light Grey Cinza muito claro - + Light Grey Cinza claro - + Grey Cinza - + Dark Grey Cinza escuro - + Light Skin Pele clara - + Light Skin - shade Pele clara - sombra - + Skin Pele - + Skin - shade Pele - sombra - + Dark Skin Pele escura - + Dark Skin - shade Pele escura - sombra @@ -1855,26 +1861,26 @@ Deseja gravar as alterações? Aviso: O formato de saída não foi especificado ou não é suportado. Utilizar PNG. - + Warning: Transparency is not currently supported in movie files Command line warning Aviso: Transparência não é actualmente suportada em ficheiros de filme - + Exporting movie... Command line task progress Exportando filme... - - + + Done. Command line task done Concluído. - + Exporting image sequence... Command line task progress Exportando Sequência de Imagens @@ -1935,8 +1941,8 @@ Deseja gravar as alterações? - Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - Imagens (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) + Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + @@ -1979,1337 +1985,1337 @@ Deseja gravar as alterações? Ficheiro de Animação Pencil PCLX(*.pclx);;Antigo Ficheiro de Animação Pencil PCL(*.pcl) - + Vivid Pink Cor de Rosa Vivo - + Strong Pink Cor de Rosa Forte - + Deep Pink Cor de Rosa Intenso - + Light Pink Cor de Rosa Claro - + Moderate Pink Cor de Rosa Médio - + Dark Pink Cor de Rosa Escuro - + Pale Pink Cor de Rosa Pálido - + Grayish Pink Cor de Rosa Acinzentado - + Pinkish White Branco Rosáceo - + Pinkish Gray Cinzento Rosáceo - + Vivid Red Vermelho Vivo - + Strong Red Vermelho Forte - + Deep Red Vermelho Intenso - + Very Deep Red Vermelho Muito Intenso - + Moderate Red Vermelho Moderado - + Dark Red Vermelho Escuro - + Very Dark Red Vermelho Muito Escuro - + Light Grayish Red Vermelho Claro Acinzentado - + Grayish Red Vermelho Acinzentado - + Dark Grayish Red Vermelho Escuro Acinzentado - + Blackish Red Vermelho Enegrecido - + Reddish Gray Cinzento Avermelhado - + Dark Reddish Gray Cinzento Avermelhado Escuro - + Reddish Black Preto Avermelhado - + Vivid Yellowish Pink Rosa Amarelado Vivo - + Strong Yellowish Pink Rosa Amarelado Forte - + Deep Yellowish Pink Rosa Amarelado Intenso - + Light Yellowish Pink Rosa Amarelado Suave - + Moderate Yellowish Pink Roa Amarelado Moderado - + Dark Yellowish Pink Rosa Amarelado Escuro - + Pale Yellowish Pink Rosa Amarelado Pálido - + Grayish Yellowish Pink Rosa Amarelado Acinzentado - + Brownish Pink Rosa Acastanhado - + Vivid Reddish Orange Laranja Avermelhado Brilhante - + Strong Reddish Orange Laranja Avermelhado Forte - + Deep Reddish Orange Laranja Avermelhado Intenso - + Moderate Reddish Orange Laranja Avermelhado Moderado - + Dark Reddish Orange Laranja Avermelhado Escuro - + Grayish Reddish Orange Laranja Avermelhado Acinzentado - + Strong Reddish Brown Castanho Avermelhado Forte - + Deep Reddish Brown Castanho Avermelhado Intenso - + Light Reddish Brown Castanho Avermelhado Suave - + Moderate Reddish Brown Castanho Avermelhado Moderado - + Dark Reddish Brown Castanho Avermelhado Escuro - + Light Grayish Reddish Brown Castanho Avermelhado Acinzentado Suave - + Grayish Reddish Brown Castanho Avermelhado Acinzentado - + Dark Grayish Reddish Brown Castanho Avermelhado Acinzentado Escuro - + Vivid Orange Laranja Vivo - + Brilliant Orange Laranja Brilhante - + Strong Orange Laranja Forte - + Deep Orange Laranja Intenso - + Light Orange Laranja Claro - + Moderate Orange Laranja Moderado - + Brownish Orange Laranja Acastanhado - + Strong Brown Castanho Forte - + Deep Brown Castanho Intenso - + Light Brown Castanho Claro - + Moderate Brown Castanho Moderado - + Dark Brown Castanho Escuro - + Light Grayish Brown Castanho Claro Acinzentado - + Grayish Brown Castanho Acinzentado - + Dark Grayish Brown Castanho Escuro Acinzentado - + Light Brownish Gray Cinzento Claro Acastanhado - + Brownish Gray Cinzento Acastanhado - + Brownish Black Preto Acastanhado - + Vivid Orange Yellow Amarelo-Laranja Vivo - + Brilliant Orange Yellow Amarelo-Laranja Brilhante - + Strong Orange Yellow Amarelo-Laranja Forte - + Deep Orange Yellow Amarelo-Laranja Intenso - + Light Orange Yellow Amarelo-Laranja Claro - + Moderate Orange Yellow Amarelo-Laranja Moderado - + Dark Orange Yellow Amarelo-Laranja Escuro - + Pale Orange Yellow Amarelo-Laranja Pálido - + Strong Yellowish Brown Castanho Amarelado Forte - + Deep Yellowish Brown Castanho Amarelado Intenso - + Light Yellowish Brown Castanho Amarelado Claro - + Moderate Yellowish Brown Castanho Amarelado Moderado - + Dark Yellowish Brown Castanho Amarelado Escuro - + Light Grayish Yellowish Brown Castanho Amarelado Claro Acinzentado - + Grayish Yellowish Brown Castanho Amarelado Acinzentado - + Dark Grayish Yellowish Brown Castanho Amarelado Escuro Acinzentado - + Vivid Yellow Amarelo Vivo - + Brilliant Yellow Amarelo Brilhante - + Strong Yellow Amarelo Forte - + Deep Yellow Amarelo Intenso - + Light Yellow Amarelo Claro - + Moderate Yellow Amarelo Moderado - + Dark Yellow Amarelo Escuro - + Pale Yellow Amarelo Pálido - + Grayish Yellow Amarelo Acinzentado - + Dark Grayish Yellow Amarelo Escuro Acinzentado - + Yellowish White Branco Amarelado - + Yellowish Gray Cinzento Amarelado - + Light Olive Brown Castanho Oliva Claro - + Moderate Olive Brown Castanho Oliva Moderado - + Dark Olive Brown Castanho Oliva Escuro - + Vivid Greenish Yellow Amarelo Esverdeado Vivo - + Brilliant Greenish Yellow Amarelo Esverdeado Brilhante - + Strong Greenish Yellow Amarelo Esverdeado Forte - + Deep Greenish Yellow Amarelo Esverdeado Intenso - + Light Greenish Yellow Amarelo Esverdeado Claro - + Moderate Greenish Yellow Amarelo Esverdeado Moderado - + Dark Greenish Yellow Amarelo Esverdeado Escuro - + Pale Greenish Yellow Amarelo Esverdeado Pálido - + Grayish Greenish Yellow Amarelo Esverdeado Acinzentado - + Light Olive Oliva Suave - + Moderate Olive Oliva Moderado - + Dark Olive Oliva Escuro - + Light Grayish Olive Oliva Acinzentado Suave - + Grayish Olive Oliva Acinzentado - + Dark Grayish Olive Oliva Acinzentado Escuro - + Light Olive Gray Cinzento Oliva Suave - + Olive Gray Cinzento Oliva - + Olive Black Preto Oliva - + Vivid Yellow Green Verde Amarelo Vivo - + Brilliant Yellow Green Verde Amarelo Brilhante - + Strong Yellow Green Verde Amarelo Forte - + Deep Yellow Green Verde Amarelo Intenso - + Light Yellow Green Verde Amarelo Suave - + Moderate Yellow Green Verde Amarelo Moderado - + Pale Yellow Green Verde Amarelo Pálido - + Grayish Yellow Green Verde Amarelo Acinzentado - + Strong Olive Green Verde Oliva Forte - + Deep Olive Green Verde Oliva Intenso - + Moderate Olive Green Verde Oliva Moderado - + Dark Olive Green Verde Oliva Escuro - + Grayish Olive Green Verde Oliva Acinzentado - + Dark Grayish Olive Green Verde Oliva Acinzentado Escuro - + Vivid Yellowish Green Verde Amarelado Vivo - + Brilliant Yellowish Green Verde Amarelado Brilhante - + Strong Yellowish Green Verde Amarelado Forte - + Deep Yellowish Green Verde Amarelado Intenso - + Very Deep Yellowish Green Verde Amarelado Muito Intenso - + Very Light Yellowish Green Verde Amarelado Muito Suave - + Light Yellowish Green Verde Amarelado Suave - + Moderate Yellowish Green Verde Amarelado Moderado - + Dark Yellowish Green Verde Amarelado Escuro - + Very Dark Yellowish Green Verde Amarelado Muito Escuro - + Vivid Green Verde Vivo - + Brilliant Green Verde Brilhante - + Strong Green Verde Forte - + Deep Green Verde Intenso - + Very Light Green Verde Muito Suave - + Light Green Verde Suave - + Moderate Green Verde Moderado - + Dark Green Verde Escuro - + Very Dark Green Verde Muito Escuro - + Very Pale Green Verde Muito Pálido - + Pale Green Verde Pálido - + Grayish Green Verde Acinzentado - + Dark Grayish Green Verde Acinzentado Escuro - + Blackish Green Verde Enegrecido - + Greenish White Branco Esverdeado - + Light Greenish Gray Cinzento Esverdeado Suave - + Greenish Gray Cinzento Esverdeado - + Dark Greenish Gray Cinzento Esverdeado Escuro - + Greenish Black Preto Esverdeado - + Vivid Bluish Green Verde Azulado Vivo - + Brilliant Bluish Green Verde Azulado Brilhante - + Strong Bluish Green Verde Azulado Forte - + Deep Bluish Green Verde Azulado Intenso - + Very Light Bluish Green Verde Azulado Muito Suave - + Light Bluish Green Verde Azulado Suave - + Moderate Bluish Green Verde Azulado Moderado - + Dark Bluish Green Verde Azulado Escuro - + Very Dark Bluish Green Verde Azulado Muito Escuro - + Vivid Greenish Blue Azul Esverdeado Vivo - + Brilliant Greenish Blue Azul Esverdeado Brilhante - + Strong Greenish Blue Azul Esverdeado Forte - + Deep Greenish Blue Azul Esverdeado Intenso - + Very Light Greenish Blue Azul Esverdeado Muito Suave - + Light Greenish Blue Azul Esverdeado Suave - + Moderate Greenish Blue Azul Esverdeado Moderado - + Dark Greenish Blue Azul Esverdeado Escuro - + Very Dark Greenish Blue Azul Esverdeado Muito Escuro - + Vivid Blue Azul Vivo - + Brilliant Blue Azul Brilhante - + Strong Blue Azul Forte - + Deep Blue Azul Intenso - + Very Light Blue Azul Muito Suave - + Light Blue Azul Suave - + Moderate Blue Azul Moderado - + Dark Blue Azul Escuro - + Very Pale Blue Azul Muito Pálido - + Pale Blue Azul Pálido - + Grayish Blue Azul Acinzentado - + Dark Grayish Blue Azul Acinzentado Escuro - + Blackish Blue Azul Enegrecido - + Bluish White Branco Azulado - + Light Bluish Gray Cinzento Azulado Suave - + Bluish Gray Cinzento Azulado - + Dark Bluish Gray Cinzento Azulado Escuro - + Bluish Black Preto Azulado - + Vivid Purplish Blue Azul Púrpura Vivo - + Brilliant Purplish Blue Azul Púrpura Brilhante - + Strong Purplish Blue Azul Púrpura Forte - + Deep Purplish Blue Azul Púrpura Intenso - + Very Light Purplish Blue Azul Púrpura Muito Suave - + Light Purplish Blue Azul Púrpura Suave - + Moderate Purplish Blue Azul Púrpura Moderado - + Dark Purplish Blue Azul Púrpura Escuro - + Very Pale Purplish Blue Azul Púrpura Muito Pálido - + Pale Purplish Blue Azul Púrpura Pálido - + Grayish Purplish Blue Azul Púrpura Acinzentado - + Vivid Violet Violeta Vivo - + Brilliant Violet Violeta Brilhante - + Strong Violet Violeta Forte - + Deep Violet Violeta Intenso - + Very Light Violet Violeta Muito Suave - + Light Violet Violeta Suave - + Moderate Violet Violeta Moderado - + Dark Violet Violeta Escuro - + Very Pale Violet Violeta Muito Pálido - + Pale Violet Violeta Pálido - + Grayish Violet Violeta Acinzentado - + Vivid Purple Roxo Vivo - + Brilliant Purple Roxo Brilhante - + Strong Purple Roxo Forte - + Deep Purple Roxo Intenso - + Very Deep Purple Roxo Muito Intenso - + Very Light Purple Roxo Muito Suave - + Light Purple Roxo Suave - + Moderate Purple Roxo Moderado - + Dark Purple Roxo Escuro - + Very Dark Purple Roxo Muito Escuro - + Very Pale Purple Roxo Muito Pálido - + Pale Purple Roxo Pálido - + Grayish Purple Roxo Acinzentado - + Dark Grayish Purple Roxo Acinzentado Escuro - + Blackish Purple Roxo Enegrecido - + Purplish White Branco Arroxado - + Light Purplish Gray Cinzento Arroxado Suave - + Purplish Gray Cinzento Arroxado - + Dark Purplish Gray Cinzento Arroxado Escuro - + Purplish Black Preto Arroxado - + Vivid Reddish Purple Roxo Avermelhado Vivo - + Strong Reddish Purple Roxo Avermelhado Forte - + Deep Reddish Purple Roxo Avermelhado Intenso - + Very Deep Reddish Purple Roxo Avermelhado Muito Intenso - + Light Reddish Purple Roxo Avermelhado Suave - + Moderate Reddish Purple Roxo Avermelhado Moderado - + Dark Reddish Purple Roxo Avermelhado Escuro - + Very Dark Reddish Purple Roxo Avermelhado Muito Escuro - + Pale Reddish Purple Roxo Avermelhado Pálido - + Grayish Reddish Purple Roxo Avermelhado Acinzentado - + Brilliant Purplish Pink Rosa Arroxado Brilhante - + Strong Purplish Pink Rosa Arroxado Forte - + Deep Purplish Pink Rosa Arroxado Intenso - + Light Purplish Pink Rosa Arroxado Suave - + Moderate Purplish Pink Rosa Arroxado Moderado - + Dark Purplish Pink Rosa Arroxado Escuro - + Pale Purplish Pink Rosa Arroxado Pálido - + Grayish Purplish Pink Rosa Arroxado Acinzentado - + Vivid Purplish Red Vermelho Arroxado Vivo - + Strong Purplish Red Vermelho Arroxado Forte - + Deep Purplish Red Vermelho Arroxado Intenso - + Very Deep Purplish Red Vermelho Arroxado Muito Intenso - + Moderate Purplish Red Vermelho Arroxado Moderado - + Dark Purplish Red Vermelho Arroxado Escuro - + Very Dark Purplish Red Vermelho Arroxado Muito Escuro - + Light Grayish Purplish Red Vermelho Arroxado Acinzentado Suave - + Grayish Purplish Red Vermelho Arroxado Acinzentado - + White Branco - + Light Gray Cinzento Claro - + Medium Gray Cinzento Médio - + Dark Gray Cinzento escuro - + Black Preto @@ -3330,60 +3336,60 @@ Deseja gravar as alterações? ScribbleArea - + Warning Aviso - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Você está desenhando em uma camada oculta! Por favor, seleccione outra camada (ou torne a camada actual visível). - + Delete Selection Undo Step: clear the selection area. Excluir selecção - - + + Clear Image Undo step text Limpar Imagem - + There is a gap in your drawing (or maybe you have zoomed too much). Há uma abertura no seu desenho (ou talvez tenha aumentado o zoom demasiado). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). Desculpe! Isto nem sempre funciona. Por favor tente novamente (aumente um pouco o zoom, clique em outro lugar... )<br>Caso não funcione, aumente um pouco o zoom e certifique-se que os caminhos estão conectados pressionando F1). - + Out of bound. Fora do limite - + Could not find a closed path. Não é possível encontrar um caminho fechado. - + Could not find the root index. Não é possível encontrar o índice principal - + %1<br><br>Error: %2 %1<br><br>Erro: %2 - + Flood fill error Erro de preenchimento @@ -3588,12 +3594,12 @@ Deseja gravar as alterações? TimeLineCells - + Layer Properties Propriedades da Camada - + Layer name: Nome da Camada: @@ -3630,6 +3636,46 @@ Deseja gravar as alterações? Preferences Comprimento Linha do Tempo + + + Drawing + + + + + When drawing on an empty frame: + + + + + Create a new (blank) key-frame and start drawing on it. + + + + + Create a new (blank) key-frame + + + + + Duplicate the previous key-frame and start drawing on the duplicate. + + + + + Duplicate the previous key-frame + + + + + Keep drawing on the previous key-frame + + + + + <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + Frame size diff --git a/translations/pencil_pt_BR.ts b/translations/pencil_pt_BR.ts index 9569787bb..68eb85ff1 100644 --- a/translations/pencil_pt_BR.ts +++ b/translations/pencil_pt_BR.ts @@ -148,57 +148,57 @@ BaseTool - + Pencil Lápis - + Eraser Borracha - + Select Selecionar - + Move Mover - + Hand Mão - + Smudge Borrar - + Pen Caneta - + Polyline Polilinha - + Bucket Balde - + Eyedropper Conta-gotas - + Brush Pincel @@ -360,8 +360,8 @@ ColorPaletteWidget - - + + Colour name Nome da cor @@ -1278,7 +1278,7 @@ - + Play Reproduzir @@ -1496,22 +1496,22 @@ Mover Quadro para Trás - + color palette:<br>use <b>(C)</b><br>toggle at cursor Paleta de cores:<br>Use <b>(C)</b><br>para alternar no cursor - + Lock Windows Bloquear Janelas - + Open Recent Abrir Recente - + You have successfully cleared the list @@ -1519,86 +1519,92 @@ Você limpou a lista com sucesso - - - - + + + + + Warning Aviso - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil não consegue ler este arquivo. Se você quiser importar imagens, use o comando Importar. - + Opening document... Abrindo documento... - - - + + + Abort Abortar - + Saving document... Salvando documento... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>Um erro ocorreu e seu arquivo pode não ter sido salvo com sucesso. Se você acredita que é um problema com Pencil2D, por favor crie um tópico em: <br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Por favor, certifique-se de incluir os seguintes detalhes: - + This animation has been modified. Do you want to save your changes? Esta animação foi modificada. Você deseja salvar suas alterações? - + The animation is not saved yet. Do you want to save now? A animação não foi salva. Gostaria de salvar agora? - + Never ask again AutoSave reminder button Não pergunte novamente - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Impossível importar imagem. <br><b>DICA:</b> Use uma camada Bitmap para importar bitmaps. - + Importing image sequence... Importando sequência de imagens... - - + + was unable to import + não é possivel importar + + + + Undo Menu item text Desfazer - + Redo Menu item text Refazer - + Stop Parar @@ -1606,122 +1612,122 @@ Gostaria de salvar agora? Object - + Black Preto - + Red Vermelho - + Dark Red Vermelho escuro - + Orange Laranja - + Dark Orange Laranja escuro - + Yellow Amarelo - + Dark Yellow Amarelo escuro - + Green Verde - + Dark Green Verde escuro - + Cyan Ciano - + Dark Cyan Ciano escuro - + Blue Azul - + Dark Blue Azul escuro - + White Branco - + Very Light Grey Cinza muito claro - + Light Grey Cinza claro - + Grey Cinza - + Dark Grey Cinza escuro - + Light Skin Pele clara - + Light Skin - shade Pele clara - sombra - + Skin Pele - + Skin - shade Pele - sombra - + Dark Skin Pele escura - + Dark Skin - shade Pele escura - sombra @@ -1856,26 +1862,26 @@ Gostaria de salvar agora? Aviso: O formato de saída não foi especificado ou não é suportado. Utilizando PNG. - + Warning: Transparency is not currently supported in movie files Command line warning Aviso: Transparência não é suportada atualmente em arquivos de vídeo - + Exporting movie... Command line task progress Exportando vídeo... - - + + Done. Command line task done Concluído. - + Exporting image sequence... Command line task progress Exportando sequência de imagens... @@ -1936,8 +1942,8 @@ Gostaria de salvar agora? - Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - Imagens (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) + Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + Imagens (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) @@ -1980,1337 +1986,1337 @@ Gostaria de salvar agora? Arquivo de Animação Pencil PCLX(*.pclx);;Arquivo Antigo de Animação Pencil PCL(*.pcl) - + Vivid Pink Cor de Rosa Vívido - + Strong Pink Cor de Rosa Forte - + Deep Pink Cor de Rosa Escuro - + Light Pink Cor de Rosa Claro - + Moderate Pink Cor de Rosa Médio - + Dark Pink Cor de Rosa Escuro - + Pale Pink Cor de Rosa Pálido - + Grayish Pink Cor de Rosa Acinzentado - + Pinkish White Branco Rosado - + Pinkish Gray Cinza Rosado - + Vivid Red Vermelho Vivo - + Strong Red Vermelho Forte - + Deep Red Vermelho Profundo - + Very Deep Red Vermelho Muito Intenso - + Moderate Red Vermelho Moderado - + Dark Red Vermelho Escuro - + Very Dark Red Vermelho Muito Escuro - + Light Grayish Red Vermelho Claro Acinzentado - + Grayish Red Vermelho Acinzentado - + Dark Grayish Red Vermelho Escuro Acinzentado - + Blackish Red Vermelho Escurecido - + Reddish Gray Cinza Avermelhado - + Dark Reddish Gray Cinza Avermelhado Escuro - + Reddish Black Preto Avermelhado - + Vivid Yellowish Pink Rosa Amarelado Vivo - + Strong Yellowish Pink Rosa Amarelado Forte - + Deep Yellowish Pink Rosa Amarelado Intenso - + Light Yellowish Pink Rosa Amarelado Suave - + Moderate Yellowish Pink Rosa Amarelado Moderado - + Dark Yellowish Pink Rosa Amarelado Escuro - + Pale Yellowish Pink Rosa Amarelado Pálido - + Grayish Yellowish Pink Rosa Amarelado Acinzentado - + Brownish Pink Rosa Acastanhado - + Vivid Reddish Orange Laranja Avermelhado Brilhante - + Strong Reddish Orange Laranja Avermelhado Forte - + Deep Reddish Orange Laranja Avermelhado Intenso - + Moderate Reddish Orange Laranja Avermelhado Moderado - + Dark Reddish Orange Laranja Avermelhado Escuro - + Grayish Reddish Orange Laranja Avermelhado Acinzentado - + Strong Reddish Brown Castanho Avermelhado Forte - + Deep Reddish Brown Castanho Avermelhado Intenso - + Light Reddish Brown Castanho Avermelhado Suave - + Moderate Reddish Brown Castanho Avermelhado Moderado - + Dark Reddish Brown Castanho Avermelhado Escuro - + Light Grayish Reddish Brown Castanho Avermelhado Acinzentado Suave - + Grayish Reddish Brown Castanho Avermelhado Acinzentado - + Dark Grayish Reddish Brown Castanho Avermelhado Acinzentado Escuro - + Vivid Orange Laranja Vivo - + Brilliant Orange Laranja Brilhante - + Strong Orange Laranja Forte - + Deep Orange Laranja Profundo - + Light Orange Laranja Claro - + Moderate Orange Laranja Moderado - + Brownish Orange Laranja Acastanhado - + Strong Brown Castanho Forte - + Deep Brown Castanho Profundo - + Light Brown Castanho Claro - + Moderate Brown Castanho Moderado - + Dark Brown Castanho Escuro - + Light Grayish Brown Castanho Claro Acinzentado - + Grayish Brown Castanho Acinzentado - + Dark Grayish Brown Castanho Escuro Acinzentado - + Light Brownish Gray Cinza Claro Acastanhado - + Brownish Gray Cinza Acastanhado - + Brownish Black Preto Acastanhado - + Vivid Orange Yellow Amarelo-Laranja Vivo - + Brilliant Orange Yellow Amarelo-Laranja Brilhante - + Strong Orange Yellow Amarelo-Laranja Forte - + Deep Orange Yellow Amarelo-Laranja Profundo - + Light Orange Yellow Amarelo-Laranja Claro - + Moderate Orange Yellow Amarelo-Laranja Moderado - + Dark Orange Yellow Amarelo-Laranja Escuro - + Pale Orange Yellow Amarelo-Laranja Pálido - + Strong Yellowish Brown Castanho Amarelado Forte - + Deep Yellowish Brown Castanho Amarelado Profundo - + Light Yellowish Brown Castanho Amarelado Claro - + Moderate Yellowish Brown Castanho Amarelado Moderado - + Dark Yellowish Brown Castanho Amarelado Escuro - + Light Grayish Yellowish Brown Castanho Amarelado Claro Acinzentado - + Grayish Yellowish Brown Castanho Amarelado Acinzentado - + Dark Grayish Yellowish Brown Castanho Amarelado Escuro Acinzentado - + Vivid Yellow Amarelo Vivo - + Brilliant Yellow Amarelo Brilhante - + Strong Yellow Amarelo Forte - + Deep Yellow Amarelo Profundo - + Light Yellow Amarelo Claro - + Moderate Yellow Amarelo Moderado - + Dark Yellow Amarelo Escuro - + Pale Yellow Amarelo Pálido - + Grayish Yellow Amarelo Acinzentado - + Dark Grayish Yellow Amarelo Escuro Acinzentado - + Yellowish White Branco Amarelado - + Yellowish Gray Cinza Amarelado - + Light Olive Brown Castanho Oliva Claro - + Moderate Olive Brown Castanho Oliva Moderado - + Dark Olive Brown Castanho Oliva Escuro - + Vivid Greenish Yellow Amarelo Esverdeado Vivo - + Brilliant Greenish Yellow Amarelo Esverdeado Brilhante - + Strong Greenish Yellow Amarelo Esverdeado Forte - + Deep Greenish Yellow Amarelo Esverdeado Intenso - + Light Greenish Yellow Amarelo Esverdeado Claro - + Moderate Greenish Yellow Amarelo Esverdeado Moderado - + Dark Greenish Yellow Amarelo Esverdeado Escuro - + Pale Greenish Yellow Amarelo Esverdeado Pálido - + Grayish Greenish Yellow Amarelo Esverdeado Acinzentado - + Light Olive Oliva Suave - + Moderate Olive Oliva Moderado - + Dark Olive Oliva Escuro - + Light Grayish Olive Oliva Acinzentado Suave - + Grayish Olive Oliva Acinzentado - + Dark Grayish Olive Oliva Acinzentado Escuro - + Light Olive Gray Cinza Oliva Suave - + Olive Gray Cinza Oliva - + Olive Black Preto Oliva - + Vivid Yellow Green Verde Amarelo Vivo - + Brilliant Yellow Green Verde Amarelo Brilhante - + Strong Yellow Green Verde Amarelo Forte - + Deep Yellow Green Verde Amarelo Forte - + Light Yellow Green Verde Amarelo Suave - + Moderate Yellow Green Verde Amarelo Moderado - + Pale Yellow Green Verde Amarelo Pálido - + Grayish Yellow Green Verde Amarelo Acinzentado - + Strong Olive Green Verde Oliva Forte - + Deep Olive Green Verde Oliva Intenso - + Moderate Olive Green Verde Oliva Moderado - + Dark Olive Green Verde Oliva Escuro - + Grayish Olive Green Verde Oliva Acinzentado - + Dark Grayish Olive Green Verde Oliva Acinzentado Escuro - + Vivid Yellowish Green Verde Amarelado Vivo - + Brilliant Yellowish Green Verde Amarelado Brilhante - + Strong Yellowish Green Verde Amarelado Forte - + Deep Yellowish Green Verde Amarelado Intenso - + Very Deep Yellowish Green Verde Amarelado Muito Intenso - + Very Light Yellowish Green Verde Amarelado Muito Suave - + Light Yellowish Green Verde Amarelado Suave - + Moderate Yellowish Green Verde Amarelado Moderado - + Dark Yellowish Green Verde Amarelado Escuro - + Very Dark Yellowish Green Verde Amarelado Muito Escuro - + Vivid Green Verde Vivo - + Brilliant Green Verde Brilhante - + Strong Green Verde Forte - + Deep Green Verde Intenso - + Very Light Green Verde Muito Suave - + Light Green Verde Suave - + Moderate Green Verde Moderado - + Dark Green Verde Escuro - + Very Dark Green Verde Muito Escuro - + Very Pale Green Verde Muito Pálido - + Pale Green Verde Pálido - + Grayish Green Verde Acinzentado - + Dark Grayish Green Verde Acinzentado Escuro - + Blackish Green Verde Escurecido - + Greenish White Branco Esverdeado - + Light Greenish Gray Cinza Esverdeado Suave - + Greenish Gray Cinza Esverdeado - + Dark Greenish Gray Cinza Esverdeado Escuro - + Greenish Black Preto Esverdeado - + Vivid Bluish Green Verde Azulado Vivo - + Brilliant Bluish Green Verde Azulado Brilhante - + Strong Bluish Green Verde Azulado Forte - + Deep Bluish Green Verde Azulado Intenso - + Very Light Bluish Green Verde Azulado Muito Suave - + Light Bluish Green Verde Azulado Suave - + Moderate Bluish Green Verde Azulado Moderado - + Dark Bluish Green Verde Azulado Escuro - + Very Dark Bluish Green Verde Azulado Muito Escuro - + Vivid Greenish Blue Azul Esverdeado Vivo - + Brilliant Greenish Blue Azul Esverdeado Brilhante - + Strong Greenish Blue Azul Esverdeado Forte - + Deep Greenish Blue Azul Esverdeado Intenso - + Very Light Greenish Blue Azul Esverdeado Muito Suave - + Light Greenish Blue Azul Esverdeado Suave - + Moderate Greenish Blue Azul Esverdeado Moderado - + Dark Greenish Blue Azul Esverdeado Escuro - + Very Dark Greenish Blue Azul Esverdeado Muito Escuro - + Vivid Blue Azul Vivo - + Brilliant Blue Azul Brilhante - + Strong Blue Azul Forte - + Deep Blue Azul Intenso - + Very Light Blue Azul Muito Suave - + Light Blue Azul Suave - + Moderate Blue Azul Moderado - + Dark Blue Azul Escuro - + Very Pale Blue Azul Muito Pálido - + Pale Blue Azul Pálido - + Grayish Blue Azul Acinzentado - + Dark Grayish Blue Azul Acinzentado Escuro - + Blackish Blue Azul Escurecido - + Bluish White Branco Azulado - + Light Bluish Gray Cinza Azulado Suave - + Bluish Gray Cinza Azulado - + Dark Bluish Gray Cinza Azulado Escuro - + Bluish Black Preto Azulado - + Vivid Purplish Blue Azul Púrpura Vivo - + Brilliant Purplish Blue Azul Púrpura Brilhante - + Strong Purplish Blue Azul Púrpura Forte - + Deep Purplish Blue Azul Púrpura Intenso - + Very Light Purplish Blue Azul Púrpura Muito Suave - + Light Purplish Blue Azul Púrpura Suave - + Moderate Purplish Blue Azul Púrpura Moderado - + Dark Purplish Blue Azul Púrpura Escuro - + Very Pale Purplish Blue Azul Púrpura Muito Pálido - + Pale Purplish Blue Azul Púrpura Pálido - + Grayish Purplish Blue Azul Púrpura Acinzentado - + Vivid Violet Violeta Vivo - + Brilliant Violet Violeta Brilhante - + Strong Violet Violeta Forte - + Deep Violet Violeta Intenso - + Very Light Violet Violeta Muito Suave - + Light Violet Violeta Suave - + Moderate Violet Violeta Moderado - + Dark Violet Violeta Escuro - + Very Pale Violet Violeta Muito Pálido - + Pale Violet Violeta Pálido - + Grayish Violet Violeta Acinzentado - + Vivid Purple Roxo Vivo - + Brilliant Purple Roxo Brilhante - + Strong Purple Roxo Forte - + Deep Purple Roxo Intenso - + Very Deep Purple Roxo Muito Intenso - + Very Light Purple Roxo Muito Suave - + Light Purple Roxo Suave - + Moderate Purple Roxo Moderado - + Dark Purple Roxo Escuro - + Very Dark Purple Roxo Muito Escuro - + Very Pale Purple Roxo Muito Pálido - + Pale Purple Roxo Pálido - + Grayish Purple Roxo Acinzentado - + Dark Grayish Purple Roxo Acinzentado Escuro - + Blackish Purple Roxo Escurecido - + Purplish White Branco Arroxado - + Light Purplish Gray Cinza Arroxado Suave - + Purplish Gray Cinza Arroxado - + Dark Purplish Gray Cinza Arroxado Escuro - + Purplish Black Preto Arroxado - + Vivid Reddish Purple Roxo Avermelhado Vivo - + Strong Reddish Purple Roxo Avermelhado Forte - + Deep Reddish Purple Roxo Avermelhado Intenso - + Very Deep Reddish Purple Roxo Avermelhado Muito Intenso - + Light Reddish Purple Roxo Avermelhado Suave - + Moderate Reddish Purple Roxo Avermelhado Moderado - + Dark Reddish Purple Roxo Avermelhado Escuro - + Very Dark Reddish Purple Roxo Avermelhado Muito Escuro - + Pale Reddish Purple Roxo Avermelhado Pálido - + Grayish Reddish Purple Roxo Avermelhado Acinzentado - + Brilliant Purplish Pink Rosa Arroxado Brilhante - + Strong Purplish Pink Rosa Arroxado Forte - + Deep Purplish Pink Rosa Arroxado Intenso - + Light Purplish Pink Rosa Arroxado Suave - + Moderate Purplish Pink Rosa Arroxado Moderado - + Dark Purplish Pink Rosa Arroxado Escuro - + Pale Purplish Pink Rosa Arroxado Pálido - + Grayish Purplish Pink Rosa Arroxado Acinzentado - + Vivid Purplish Red Vermelho Arroxado Vivo - + Strong Purplish Red Vermelho Arroxado Forte - + Deep Purplish Red Vermelho Arroxado Intenso - + Very Deep Purplish Red Vermelho Arroxado Muito Intenso - + Moderate Purplish Red Vermelho Arroxado Moderado - + Dark Purplish Red Vermelho Arroxado Escuro - + Very Dark Purplish Red Vermelho Arroxado Muito Escuro - + Light Grayish Purplish Red Vermelho Arroxado Acinzentado Suave - + Grayish Purplish Red Vermelho Arroxado Acinzentado - + White Branco - + Light Gray Cinza Claro - + Medium Gray Cinza Médio - + Dark Gray Cinza escuro - + Black Preto @@ -3331,60 +3337,60 @@ Gostaria de salvar agora? ScribbleArea - + Warning Aviso - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Você está desenhando em uma camada oculta! Por favor, selecione outra camada (ou torne a camada atual visível). - + Delete Selection Undo Step: clear the selection area. Apagar seleção - - + + Clear Image Undo step text Limpar Imagem - + There is a gap in your drawing (or maybe you have zoomed too much). Há um espaço no seu desenho (ou talvez você tenha aumentado o zoom demais). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). Desculpe! Isto nem sempre funciona. Por favor tente novamente (aumente um pouco o zoom, clique em outro lugar... )<br>Caso não funcione, aumente um pouco o zoom e tenha a certeza que os caminhos estão conectados pressionando F1 - + Out of bound. Fora do limite - + Could not find a closed path. Não encontro um caminho fechado. - + Could not find the root index. Não encontro o índice principal - + %1<br><br>Error: %2 %1<br><br>Erro: %2 - + Flood fill error Erro de preenchimento @@ -3589,12 +3595,12 @@ Gostaria de salvar agora? TimeLineCells - + Layer Properties Propriedades da camada - + Layer name: Nome da camada: @@ -3631,6 +3637,46 @@ Gostaria de salvar agora? Preferences Tamanho da linha do tempo: + + + Drawing + Desenhando + + + + When drawing on an empty frame: + Ao desenhar em um quadro vazio: + + + + Create a new (blank) key-frame and start drawing on it. + Criar um novo quadro-chave (em branco) e começar a desenhar nele. + + + + Create a new (blank) key-frame + Criar um novo quadro chave (em branco) + + + + Duplicate the previous key-frame and start drawing on the duplicate. + Duplicar o quadro-chave anterior e começar a desenhar na duplicata + + + + Duplicate the previous key-frame + Duplicar o quadro-chave anterior + + + + Keep drawing on the previous key-frame + Continuar desenhando no quadro-chave anterior + + + + <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + <html><head/><body><p>(Aplicável para as ferramentas Lápis, Borracha, Caneta, Polilinha, Balde e Pincel)</p></body></html> + Frame size diff --git a/translations/pencil_ru.ts b/translations/pencil_ru.ts index 9eae6aa96..62833bc6d 100644 --- a/translations/pencil_ru.ts +++ b/translations/pencil_ru.ts @@ -148,57 +148,57 @@ BaseTool - + Pencil Карандаш - + Eraser Ластик - + Select Выделение - + Move Перемещение - + Hand Рука - + Smudge Коррекция - + Pen Перо - + Polyline Ломаная - + Bucket Заливка - + Eyedropper Пипетка - + Brush Кисть @@ -360,8 +360,8 @@ ColorPaletteWidget - - + + Colour name Параметры образца @@ -1278,7 +1278,7 @@ - + Play Воспроизведение @@ -1496,22 +1496,22 @@ Переместить кадр назад - + color palette:<br>use <b>(C)</b><br>toggle at cursor - + Lock Windows Закрепить окна - + Open Recent Последние документы - + You have successfully cleared the list @@ -1520,87 +1520,93 @@ Вы успешно очистили список - - - - + + + + + Warning Предупреждение - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil не удалось открыть данный файл. >br<Подсказка: для изображений воспользуйтесь командой Файл -> Импорт - + Opening document... Открытие документа... - - - + + + Abort Отмена - + Saving document... Сохранение документа... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: - + This animation has been modified. Do you want to save your changes? Эта анимация была изменена. Вы хотите сохранить свои изменения? - + The animation is not saved yet. Do you want to save now? Анимация еще не сохранена. Вы хотите сохранить ее сейчас? - + Never ask again AutoSave reminder button Больше не спрашивать - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. - + Importing image sequence... - - + + was unable to import + + + + + Undo Menu item text - + Redo Menu item text - + Stop Стоп @@ -1608,122 +1614,122 @@ Object - + Black Чёрный - + Red Красный - + Dark Red Тёмно-красный - + Orange Оранжевый - + Dark Orange Тёмно-оранжевый - + Yellow Жёлтый - + Dark Yellow Тёмно-жёлтый - + Green Зелёный - + Dark Green Тёмно-зелёный - + Cyan Сине-зелёный - + Dark Cyan Тёмный сине-зелёный - + Blue Синий - + Dark Blue Тёмно-синий - + White Белый - + Very Light Grey Серый 12% - + Light Grey Серый 25% - + Grey Серый 37% - + Dark Grey Серый 50% - + Light Skin Цвет кожи, светлый - + Light Skin - shade Цвет кожи, светлый с тенью - + Skin Цвет кожи - + Skin - shade Цвет кожи, с тенью - + Dark Skin Цвет кожи, тёмный - + Dark Skin - shade Цвет кожи, тёмный с тенью @@ -1858,26 +1864,26 @@ - + Warning: Transparency is not currently supported in movie files Command line warning - + Exporting movie... Command line task progress - - + + Done. Command line task done - + Exporting image sequence... Command line task progress @@ -1938,8 +1944,8 @@ - Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - Изображения (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) + Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + @@ -1982,1337 +1988,1337 @@ Файл анимации PCLX(*.pclx);;Старый файл анимации PCL(*.pcl) - + Vivid Pink Яркий розовый - + Strong Pink Сильный розовый - + Deep Pink Глубокий розовый - + Light Pink Светло-розовый - + Moderate Pink Умеренный розовый - + Dark Pink Темно-розовый - + Pale Pink Бледно-розовый - + Grayish Pink Серовато-розовый - + Pinkish White Розово-белый - + Pinkish Gray Розово-серый - + Vivid Red Яркий красный - + Strong Red Сильный красный - + Deep Red Глубокий красный - + Very Deep Red Очень глубокий красный - + Moderate Red Умеренный красный - + Dark Red Темно-красный - + Very Dark Red Очень темный красный - + Light Grayish Red Светло-серовато-красный - + Grayish Red Серовато-красный - + Dark Grayish Red Темно-серовато-красный - + Blackish Red Чернильно-красный - + Reddish Gray Красновато-серый - + Dark Reddish Gray Темно-красновато-серый - + Reddish Black Красноватый черный - + Vivid Yellowish Pink Яркий желтовато-розовый - + Strong Yellowish Pink Сильный желтовато-розовый - + Deep Yellowish Pink Глубокий желтовато-розовый - + Light Yellowish Pink Светло-желтовато-розовый - + Moderate Yellowish Pink Умеренный желтовато-розовый - + Dark Yellowish Pink Темный желтовато-розовый - + Pale Yellowish Pink Бледно-желтовато-розовый - + Grayish Yellowish Pink Сероватый желтовато-розовый - + Brownish Pink Буровато-розовый - + Vivid Reddish Orange Яркий красноватый оранжевый - + Strong Reddish Orange Сильный красноватый оранжевый - + Deep Reddish Orange Глубокий красноватый оранжевый - + Moderate Reddish Orange Умеренный красноватый оранжевый - + Dark Reddish Orange Темный красноватый оранжевый - + Grayish Reddish Orange Сероватый красновато-оранжевый - + Strong Reddish Brown Сильный красновато-коричневый - + Deep Reddish Brown Глубокий красновато-коричневый - + Light Reddish Brown Светлый красновато-коричневый - + Moderate Reddish Brown Умеренный красновато-коричневый - + Dark Reddish Brown Темный красновато-коричневый - + Light Grayish Reddish Brown Светло-серый красновато-коричневый - + Grayish Reddish Brown Сероватый красновато-коричневый - + Dark Grayish Reddish Brown Темно-серый красновато-коричневый - + Vivid Orange Яркий оранжевый - + Brilliant Orange Блестящий оранжевый - + Strong Orange Сильный оранжевый - + Deep Orange Глубокий оранжевый - + Light Orange - + Moderate Orange - + Brownish Orange - + Strong Brown - + Deep Brown - + Light Brown - + Moderate Brown - + Dark Brown Темно-коричневый - + Light Grayish Brown - + Grayish Brown - + Dark Grayish Brown - + Light Brownish Gray - + Brownish Gray - + Brownish Black - + Vivid Orange Yellow - + Brilliant Orange Yellow - + Strong Orange Yellow - + Deep Orange Yellow - + Light Orange Yellow - + Moderate Orange Yellow - + Dark Orange Yellow - + Pale Orange Yellow - + Strong Yellowish Brown - + Deep Yellowish Brown - + Light Yellowish Brown - + Moderate Yellowish Brown - + Dark Yellowish Brown - + Light Grayish Yellowish Brown - + Grayish Yellowish Brown - + Dark Grayish Yellowish Brown - + Vivid Yellow - + Brilliant Yellow - + Strong Yellow - + Deep Yellow - + Light Yellow - + Moderate Yellow - + Dark Yellow Темно-желтый - + Pale Yellow - + Grayish Yellow - + Dark Grayish Yellow - + Yellowish White - + Yellowish Gray - + Light Olive Brown - + Moderate Olive Brown - + Dark Olive Brown - + Vivid Greenish Yellow - + Brilliant Greenish Yellow - + Strong Greenish Yellow - + Deep Greenish Yellow - + Light Greenish Yellow - + Moderate Greenish Yellow - + Dark Greenish Yellow - + Pale Greenish Yellow - + Grayish Greenish Yellow - + Light Olive - + Moderate Olive - + Dark Olive - + Light Grayish Olive - + Grayish Olive - + Dark Grayish Olive - + Light Olive Gray - + Olive Gray - + Olive Black - + Vivid Yellow Green - + Brilliant Yellow Green - + Strong Yellow Green - + Deep Yellow Green - + Light Yellow Green - + Moderate Yellow Green - + Pale Yellow Green - + Grayish Yellow Green - + Strong Olive Green - + Deep Olive Green - + Moderate Olive Green - + Dark Olive Green - + Grayish Olive Green - + Dark Grayish Olive Green - + Vivid Yellowish Green - + Brilliant Yellowish Green - + Strong Yellowish Green - + Deep Yellowish Green - + Very Deep Yellowish Green - + Very Light Yellowish Green - + Light Yellowish Green - + Moderate Yellowish Green - + Dark Yellowish Green - + Very Dark Yellowish Green - + Vivid Green - + Brilliant Green - + Strong Green - + Deep Green - + Very Light Green - + Light Green - + Moderate Green - + Dark Green - + Very Dark Green - + Very Pale Green - + Pale Green - + Grayish Green - + Dark Grayish Green - + Blackish Green - + Greenish White - + Light Greenish Gray - + Greenish Gray - + Dark Greenish Gray - + Greenish Black - + Vivid Bluish Green - + Brilliant Bluish Green - + Strong Bluish Green - + Deep Bluish Green - + Very Light Bluish Green - + Light Bluish Green - + Moderate Bluish Green - + Dark Bluish Green - + Very Dark Bluish Green - + Vivid Greenish Blue - + Brilliant Greenish Blue - + Strong Greenish Blue - + Deep Greenish Blue - + Very Light Greenish Blue - + Light Greenish Blue - + Moderate Greenish Blue - + Dark Greenish Blue - + Very Dark Greenish Blue - + Vivid Blue - + Brilliant Blue - + Strong Blue - + Deep Blue - + Very Light Blue - + Light Blue Светло-синий - + Moderate Blue Умеренный синий - + Dark Blue Темно-синий - + Very Pale Blue - + Pale Blue - + Grayish Blue - + Dark Grayish Blue - + Blackish Blue - + Bluish White - + Light Bluish Gray - + Bluish Gray - + Dark Bluish Gray - + Bluish Black - + Vivid Purplish Blue - + Brilliant Purplish Blue - + Strong Purplish Blue - + Deep Purplish Blue - + Very Light Purplish Blue - + Light Purplish Blue - + Moderate Purplish Blue - + Dark Purplish Blue - + Very Pale Purplish Blue - + Pale Purplish Blue - + Grayish Purplish Blue - + Vivid Violet Яркий фиолетовый - + Brilliant Violet - + Strong Violet - + Deep Violet - + Very Light Violet - + Light Violet - + Moderate Violet - + Dark Violet - + Very Pale Violet - + Pale Violet - + Grayish Violet - + Vivid Purple - + Brilliant Purple - + Strong Purple - + Deep Purple - + Very Deep Purple - + Very Light Purple - + Light Purple - + Moderate Purple - + Dark Purple - + Very Dark Purple - + Very Pale Purple - + Pale Purple - + Grayish Purple - + Dark Grayish Purple - + Blackish Purple - + Purplish White - + Light Purplish Gray - + Purplish Gray - + Dark Purplish Gray - + Purplish Black - + Vivid Reddish Purple - + Strong Reddish Purple - + Deep Reddish Purple - + Very Deep Reddish Purple - + Light Reddish Purple - + Moderate Reddish Purple - + Dark Reddish Purple - + Very Dark Reddish Purple - + Pale Reddish Purple - + Grayish Reddish Purple - + Brilliant Purplish Pink - + Strong Purplish Pink - + Deep Purplish Pink - + Light Purplish Pink - + Moderate Purplish Pink - + Dark Purplish Pink - + Pale Purplish Pink - + Grayish Purplish Pink - + Vivid Purplish Red - + Strong Purplish Red - + Deep Purplish Red - + Very Deep Purplish Red - + Moderate Purplish Red - + Dark Purplish Red - + Very Dark Purplish Red - + Light Grayish Purplish Red - + Grayish Purplish Red - + White Белый - + Light Gray Светло-серый - + Medium Gray Средний серый - + Dark Gray Темно-серый - + Black Чёрный @@ -3333,60 +3339,60 @@ ScribbleArea - + Warning Предупреждение - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Вы рисуете на скрытом слое! Пожалуйста, выберите другой слой или сделайте текущий видимым. - + Delete Selection Undo Step: clear the selection area. Удалить выделение - - + + Clear Image Undo step text Очистить изображение - + There is a gap in your drawing (or maybe you have zoomed too much). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). - + Out of bound. Вне границы. - + Could not find a closed path. - + Could not find the root index. - + %1<br><br>Error: %2 %1<br><br>Ошибка: %2 - + Flood fill error Ошибка заливки @@ -3591,12 +3597,12 @@ TimeLineCells - + Layer Properties Свойства слоя - + Layer name: Имя слоя: @@ -3633,6 +3639,46 @@ Preferences Длина временной шкалы: + + + Drawing + + + + + When drawing on an empty frame: + + + + + Create a new (blank) key-frame and start drawing on it. + + + + + Create a new (blank) key-frame + + + + + Duplicate the previous key-frame and start drawing on the duplicate. + + + + + Duplicate the previous key-frame + + + + + Keep drawing on the previous key-frame + + + + + <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + Frame size diff --git a/translations/pencil_sl.ts b/translations/pencil_sl.ts index 90a1abeef..521a00b26 100644 --- a/translations/pencil_sl.ts +++ b/translations/pencil_sl.ts @@ -148,57 +148,57 @@ BaseTool - + Pencil Svinčnik - + Eraser Radirka - + Select Izbor - + Move Premakni - + Hand Roka - + Smudge Zamaži - + Pen Penkalo - + Polyline Večsegmentna črta - + Bucket Vedro - + Eyedropper Kapalka - + Brush Čopič @@ -360,8 +360,8 @@ ColorPaletteWidget - - + + Colour name Ime barve @@ -1278,7 +1278,7 @@ - + Play Predvajaj @@ -1496,22 +1496,22 @@ Premakni razdelek nazaj - + color palette:<br>use <b>(C)</b><br>toggle at cursor barvna paleta:<br>uporabi<b>(C)</b><br>izmenjaj pri kazalcu - + Lock Windows Zakleni okna - + Open Recent Odpri nedavne - + You have successfully cleared the list @@ -1520,86 +1520,92 @@ Uspešno ste izbpraznili seznam - - - - + + + + + Warning Opozorilo - - + + Pencil cannot read this file. If you want to import images, use the command import. Svinčnik ne more prebrati te datoteke. Če želite uvoziti slike uporabite ukaz za uvoz. - + Opening document... Odpiranje dokumenta... - - - + + + Abort Prekini - + Saving document... Shranjevanje dokumenta... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>Pojavila se je napaka in vaša datoteka morda ni pravilno shranjena. Če sumite, da napaka kaže na problem s Svinčnikom2D kreirajtenovo poročilo na:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Prosimo, da v svoje poročilo vključite naslednje podatke: - + This animation has been modified. Do you want to save your changes? Ta animacija je bila spremenjena. Želite shraniti spremembe? - + The animation is not saved yet. Do you want to save now? Animacija še ni shranjena. Želite shraniti sedaj? - + Never ask again AutoSave reminder button Ne sprašuj več - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Ni mogoče uvoziti slike.<br><b>Namig:</b>Uporabite bitni sloj za uvoz bitnih slik. - + Importing image sequence... Uvažanje zaporedja sličic... - - + + was unable to import + + + + + Undo Menu item text Korak nazaj - + Redo Menu item text Korak naprej - + Stop Stop @@ -1607,122 +1613,122 @@ Uspešno ste izbpraznili seznam Object - + Black Črna - + Red Rdeča - + Dark Red Temno rdeča - + Orange Oranžna - + Dark Orange Temno oranžna - + Yellow Rumena - + Dark Yellow Temno rumena - + Green Zelena - + Dark Green Temno zelena - + Cyan Sinja - + Dark Cyan Temno sinja - + Blue Modra - + Dark Blue Temno modra - + White Bela - + Very Light Grey Zelo svetlo siva - + Light Grey Svetlo siva - + Grey Siva - + Dark Grey Temno siva - + Light Skin Svetla koža - + Light Skin - shade Svetla koža-senca - + Skin Koža - + Skin - shade Koža-senca - + Dark Skin Temna koža - + Dark Skin - shade Temna koža-senca @@ -1857,26 +1863,26 @@ Uspešno ste izbpraznili seznam Opozorilo: Izhodna oblika ni določena ali je nepodprta. Uporabljam PNG. - + Warning: Transparency is not currently supported in movie files Command line warning Opozorilo: Prosojnost v posnetkih trenutno ni podprta - + Exporting movie... Command line task progress Izvažanje posnetka... - - + + Done. Command line task done Narejeno. - + Exporting image sequence... Command line task progress Izvažanje zaporedja sličic... @@ -1937,8 +1943,8 @@ Uspešno ste izbpraznili seznam - Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - Slike (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) + Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + @@ -1981,1337 +1987,1337 @@ Uspešno ste izbpraznili seznam Svinčnikova animacija PCLX(*.pclx);;Stara Svinčnikova animacija PCL(*.pcl) - + Vivid Pink Kričeče roza - + Strong Pink Močno roza - + Deep Pink Globoko roza - + Light Pink Svetlo roza - + Moderate Pink Zmerno roza - + Dark Pink Temno roza - + Pale Pink Bledo roza - + Grayish Pink Sivkasto roza - + Pinkish White Rozasto bela - + Pinkish Gray Rozasto siva - + Vivid Red Kričeče rdeča - + Strong Red Močno rdeča - + Deep Red Globoko rdeča - + Very Deep Red Zelo globoko rdeča - + Moderate Red Zmerno rdeča - + Dark Red Temno rdeča - + Very Dark Red Zelo temno rdeča - + Light Grayish Red Svetlo sivkasto rdeča - + Grayish Red Sivkasto rdeča - + Dark Grayish Red Temno sivkasto rdeča - + Blackish Red Črninsko rdeča - + Reddish Gray Rdečkasto siva - + Dark Reddish Gray Temno rdečkasto siva - + Reddish Black Rdečkasto črna - + Vivid Yellowish Pink Kričeče rumenkasto roza - + Strong Yellowish Pink Močno rumenkasto roza - + Deep Yellowish Pink Globoko rumenkasto roza - + Light Yellowish Pink Svetlo rumenkasto roza - + Moderate Yellowish Pink Zmerno rumenkasto roza - + Dark Yellowish Pink Temno rumenkasto roza - + Pale Yellowish Pink Bledo rumenkasto roza - + Grayish Yellowish Pink Sivo rumenkasto roza - + Brownish Pink Rjavkasto roza - + Vivid Reddish Orange Kričeče rdečkasto oranžna - + Strong Reddish Orange Močno rdečkasto oranžna - + Deep Reddish Orange Globoko rdečkasto oranžna - + Moderate Reddish Orange Zmerno rdečkasto oranžna - + Dark Reddish Orange Temno rdečkasto oranžna - + Grayish Reddish Orange Sivkasto rdečkasto oranžna - + Strong Reddish Brown Močno rdečkasto rjava - + Deep Reddish Brown Globoko rdečkasto rjava - + Light Reddish Brown Svetlo rdečkasto rjava - + Moderate Reddish Brown Zmerno rdečkasto rjava - + Dark Reddish Brown Temno rdečkasto rjava - + Light Grayish Reddish Brown Svetlo sivkasto rdečkasto rjava - + Grayish Reddish Brown Sivkasto rdečkasto rjava - + Dark Grayish Reddish Brown Temno sivkasto rdečkasto rjava - + Vivid Orange Kričeče oranžna - + Brilliant Orange Sijajno oranžna - + Strong Orange Močno oranžna - + Deep Orange Globoko oranžna - + Light Orange Svetlo oranžna - + Moderate Orange Zmerno oranžna - + Brownish Orange Rjavkasto oranžna - + Strong Brown Močno rjava - + Deep Brown Globoko rjava - + Light Brown Svetlo rjava - + Moderate Brown Zmerno rjava - + Dark Brown Temno rjava - + Light Grayish Brown Svetlo sivkasto rjava - + Grayish Brown Sivkasto rjava - + Dark Grayish Brown Temno sivkasto rjava - + Light Brownish Gray Svetlo rjavkasto siva - + Brownish Gray Rjavkasto siva - + Brownish Black Rjavkasto črna - + Vivid Orange Yellow Kričeče oranžno rumena - + Brilliant Orange Yellow Sijajno oranžno rumena - + Strong Orange Yellow Močno oranžno rumena - + Deep Orange Yellow Globoko oranžno rumena - + Light Orange Yellow Svetlo oranžno rumena - + Moderate Orange Yellow Zmerno oranžno rumena - + Dark Orange Yellow Temno oranžno rumena - + Pale Orange Yellow Bledo oranžno rumena - + Strong Yellowish Brown Močno rumenkasto rjava - + Deep Yellowish Brown Globoko rumenkasto rjava - + Light Yellowish Brown Svetlo rumenkasto rjava - + Moderate Yellowish Brown Zmerno rumenkasto rjava - + Dark Yellowish Brown Temno rumenkasto rjava - + Light Grayish Yellowish Brown Svetlo sivkasto rumenkasto rjava - + Grayish Yellowish Brown Sivkasto rumenkasto rjava - + Dark Grayish Yellowish Brown Temno sivkasto rumenkasto rjava - + Vivid Yellow Kričeče rumena - + Brilliant Yellow Sijajno rumena - + Strong Yellow Močno rumena - + Deep Yellow Globoko rumena - + Light Yellow Svetlo rumena - + Moderate Yellow Zmerno rumena - + Dark Yellow Temno rumena - + Pale Yellow Bledo rumena - + Grayish Yellow Sivkasto rumena - + Dark Grayish Yellow Temno sivkasto rumena - + Yellowish White Rumenkasto bela - + Yellowish Gray Rumenkasto siva - + Light Olive Brown Svetlo olivno rjava - + Moderate Olive Brown Zmerno olivno rjava - + Dark Olive Brown Temno olivno rjava - + Vivid Greenish Yellow Kričeče zelenkasto rumena - + Brilliant Greenish Yellow Sijajno zelenkasto rumena - + Strong Greenish Yellow Močno zelenkasto rumena - + Deep Greenish Yellow Globoko zelenkasto rumena - + Light Greenish Yellow Svetlo zelenkasto rumena - + Moderate Greenish Yellow Zmerno zelenkasto rumena - + Dark Greenish Yellow Temno zelenkasto rumena - + Pale Greenish Yellow Bledo zelenkasto rumena - + Grayish Greenish Yellow Svikasto zelenkasto rumena - + Light Olive Svetlo olivna - + Moderate Olive Zmerno olivna - + Dark Olive Temno olivna - + Light Grayish Olive Svetlo sivkasto olivna - + Grayish Olive Sivkasto olivna - + Dark Grayish Olive Temno sivkasto olivna - + Light Olive Gray Svetlo olivno siva - + Olive Gray Olivno siva - + Olive Black Olivno črna - + Vivid Yellow Green Kričeče rumeno zelena - + Brilliant Yellow Green Sijajno rumeno zelena - + Strong Yellow Green Močno rumeno zelena - + Deep Yellow Green Globoko rumeno zelena - + Light Yellow Green Svetlo rumeno zelena - + Moderate Yellow Green Zmerno rumeno zelena - + Pale Yellow Green Bledo rumeno zelena - + Grayish Yellow Green Sivkasto rumeno zelena - + Strong Olive Green Močno olivno zelena - + Deep Olive Green Globoko olivno zelena - + Moderate Olive Green Zmerno olivno zelena - + Dark Olive Green Temno olivno zelena - + Grayish Olive Green Sivo olivno zelena - + Dark Grayish Olive Green Temno sivkasto olivno zelena - + Vivid Yellowish Green Kričeče rumenkasto zelena - + Brilliant Yellowish Green Sijajno rumenkasto zelena - + Strong Yellowish Green Močno rumenkasto zelena - + Deep Yellowish Green Globoko rumenkasto zelena - + Very Deep Yellowish Green Zelo globoko rumenkasto zelena - + Very Light Yellowish Green Zelo svetlo rumenkasto zelena - + Light Yellowish Green Svetlo rumenkasto zelena - + Moderate Yellowish Green Zmerno rumenkasto zelena - + Dark Yellowish Green Temno rumenkasto zelena - + Very Dark Yellowish Green Zelo temno rumenkasto zelena - + Vivid Green Kričeče zelena - + Brilliant Green Sijajno zelena - + Strong Green Močno zelena - + Deep Green Globoko zelena - + Very Light Green Zelo svetlo zelena - + Light Green Svetlo zelena - + Moderate Green Zmerno zelena - + Dark Green Temno zelena - + Very Dark Green Zelo temno zelena - + Very Pale Green Zelo bledo zelena - + Pale Green Bledo zelena - + Grayish Green Sivkasto zelena - + Dark Grayish Green Temno sivkasto zelena - + Blackish Green Črninsko zelena - + Greenish White Zelenkasto bela - + Light Greenish Gray Svetlo zelenkasto siva - + Greenish Gray Zelenkasto siva - + Dark Greenish Gray Temno zelenkasto siva - + Greenish Black Zelenkasto črna - + Vivid Bluish Green Kričeče modrikasto zelena - + Brilliant Bluish Green Sijajno modrikasto zelena - + Strong Bluish Green Močno modrikasto zelena - + Deep Bluish Green Globoko modrikasto zelena - + Very Light Bluish Green Zelo svetlo modrikasto zelena - + Light Bluish Green Svetlo modrikasto zelena - + Moderate Bluish Green Zmerno modrikasto zelena - + Dark Bluish Green Temno modrikasto zelena - + Very Dark Bluish Green Zelo temno modrikasto zelena - + Vivid Greenish Blue Kričeče zelenkasto modra - + Brilliant Greenish Blue Sijajno zelenkasto modra - + Strong Greenish Blue Močno zelenkasto modra - + Deep Greenish Blue Globoko zelenkasto modra - + Very Light Greenish Blue Zelo svetlo zelenkasto modra - + Light Greenish Blue Svetlo zelenkasto modra - + Moderate Greenish Blue Zmerno zelenkasto modra - + Dark Greenish Blue Temno zelenkasto modra - + Very Dark Greenish Blue Zelo temno zelenkasto modra - + Vivid Blue Kričeče modra - + Brilliant Blue Sijajno modra - + Strong Blue Močno modra - + Deep Blue Globoko modra - + Very Light Blue Zelo svetlo modra - + Light Blue Svetlo modra - + Moderate Blue Zmerno modra - + Dark Blue Temno modra - + Very Pale Blue Zelo bledo modra - + Pale Blue Bledo modra - + Grayish Blue Sivkasto modra - + Dark Grayish Blue Temno sivkasto modra - + Blackish Blue Črninsko modra - + Bluish White Modrikasto bela - + Light Bluish Gray Svetlo modrikasto siva - + Bluish Gray Modrikasto siva - + Dark Bluish Gray Temno modrikasto siva - + Bluish Black Modrikasto črna - + Vivid Purplish Blue Kričeče vijoličasto modra - + Brilliant Purplish Blue Sijajno vijoličasto modra - + Strong Purplish Blue Močno vijoličasto modra - + Deep Purplish Blue Globoko vijoličasto modra - + Very Light Purplish Blue Zelo svetlo vijoličasto modra - + Light Purplish Blue Svetlo vijoličasto modra - + Moderate Purplish Blue Zmerno vijoličasto modra - + Dark Purplish Blue Temno vijoličasto modra - + Very Pale Purplish Blue Zelo bledo vijoličasto modra - + Pale Purplish Blue Bledo vijoličasto modra - + Grayish Purplish Blue Sivkasto vijoličasto modra - + Vivid Violet Kričeče vijola - + Brilliant Violet Sijajno vijola - + Strong Violet Močno vijola - + Deep Violet Globoko vijola - + Very Light Violet Zelo svetlo vijola - + Light Violet Svetlo vijola - + Moderate Violet Zmerno vijola - + Dark Violet Temno vijola - + Very Pale Violet Zelo bledo vijola - + Pale Violet Bledo vijola - + Grayish Violet Sivkasto vijola - + Vivid Purple Kričeče vijolična - + Brilliant Purple Sijajno vijolična - + Strong Purple Močno vijolična - + Deep Purple Globoko vijolična - + Very Deep Purple Zelo globoko vijolična - + Very Light Purple Zelo svetlo vijolična - + Light Purple Svetlo vijolična - + Moderate Purple Zmerno vijolična - + Dark Purple Temno vijolična - + Very Dark Purple Zelo temno vijolična - + Very Pale Purple Zelo bledo vijolična - + Pale Purple Bledo vijolična - + Grayish Purple Sivkasto vijolična - + Dark Grayish Purple Temno sivkasto vijolična - + Blackish Purple Črninsko vijolična - + Purplish White Vijoličasto bela - + Light Purplish Gray Svetlo vijoličasto siva - + Purplish Gray Vijoličasto siva - + Dark Purplish Gray Temno vijoličasto siva - + Purplish Black Vijoličasto črna - + Vivid Reddish Purple Kričeče rdečkasto vijolična - + Strong Reddish Purple Močno rdečkasto vijolična - + Deep Reddish Purple Globoko rdečkasto vijolična - + Very Deep Reddish Purple Zelo globoko rdečkasto vijolična - + Light Reddish Purple Svetlo rdečkasto vijolična - + Moderate Reddish Purple Zmerno rdečkasto vijolična - + Dark Reddish Purple Temno rdečkasto vijolična - + Very Dark Reddish Purple Zelo temno rdečkasto vijolična - + Pale Reddish Purple Bledo rdečkasto vijolična - + Grayish Reddish Purple Sivkasto rdečkasto vijolična - + Brilliant Purplish Pink Sijajno vijoličasto roza - + Strong Purplish Pink Močno vijoličasto roza - + Deep Purplish Pink Globoko vijoličasto roza - + Light Purplish Pink Svetlo vijoličasto roza - + Moderate Purplish Pink Zmerno vijoličasto roza - + Dark Purplish Pink Temno vijoličasto roza - + Pale Purplish Pink Bledo vijoličasto roza - + Grayish Purplish Pink Sivkasto vijoličasto roza - + Vivid Purplish Red Kričeče vijoličasto rdeča - + Strong Purplish Red Močno vijoličasto rdeča - + Deep Purplish Red Globoko vijoličasto rdeča - + Very Deep Purplish Red Zelo globoko vijoličasto rdeča - + Moderate Purplish Red Zmerno vijoličasto rdeča - + Dark Purplish Red Temno vijoličasto rdeča - + Very Dark Purplish Red Zelo temno vijoličasto rdeča - + Light Grayish Purplish Red Svetlo sivkasto vijoličasto rdeča - + Grayish Purplish Red Sivkasto vijoličasto rdeča - + White Bela - + Light Gray Svetlo siva - + Medium Gray Srednje siva - + Dark Gray Temno siva - + Black Črna @@ -3332,60 +3338,60 @@ Uspešno ste izbpraznili seznam ScribbleArea - + Warning Opozorilo - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Rišete po skritem sloju! Izberite drug sloj (ali spremenite trenutni sloj v vidnega). - + Delete Selection Undo Step: clear the selection area. Izbriši označeno - - + + Clear Image Undo step text Počisti sliko - + There is a gap in your drawing (or maybe you have zoomed too much). V risbi je razmik (ali pa je preveč približana). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). Žal, to vedno ne deluje. Poizkusite znova (malce približajte ali oddaljite, kliknite na drugo lokacijo,...)<br>Če ne deluje malce približajte ali oddaljite in preverite če so poti spojene s pritiskom na F1.). - + Out of bound. Izven mej. - + Could not find a closed path. Ne najdem zaprte poti. - + Could not find the root index. Ne najdem korenskega kazala. - + %1<br><br>Error: %2 %1<br><br>Napaka: %2 - + Flood fill error Napaka pri polnenju. @@ -3590,12 +3596,12 @@ Uspešno ste izbpraznili seznam TimeLineCells - + Layer Properties Lastnosti sloja - + Layer name: Ime sloja: @@ -3632,6 +3638,46 @@ Uspešno ste izbpraznili seznam Preferences Dolžina časovnice: + + + Drawing + + + + + When drawing on an empty frame: + + + + + Create a new (blank) key-frame and start drawing on it. + + + + + Create a new (blank) key-frame + + + + + Duplicate the previous key-frame and start drawing on the duplicate. + + + + + Duplicate the previous key-frame + + + + + Keep drawing on the previous key-frame + + + + + <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + Frame size diff --git a/translations/pencil_vi.ts b/translations/pencil_vi.ts index 454696b6a..d2a17b95a 100644 --- a/translations/pencil_vi.ts +++ b/translations/pencil_vi.ts @@ -148,57 +148,57 @@ BaseTool - + Pencil Bút chì - + Eraser Tẩy xóa - + Select Công cụ chọn - + Move Di chuyển - + Hand Bàn tay - + Smudge Làm mờ - + Pen Bút mực - + Polyline Polyline - + Bucket Tô màu - + Eyedropper Chọn màu - + Brush Cọ vẽ @@ -360,8 +360,8 @@ ColorPaletteWidget - - + + Colour name Tên màu @@ -1278,7 +1278,7 @@ - + Play Chạy @@ -1496,22 +1496,22 @@ Di chuyển Frame về sau - + color palette:<br>use <b>(C)</b><br>toggle at cursor <b>Bảng màu:<br>Sử dụng(C)</b><br>bật tắt con trỏ - + Lock Windows Khóa cửa sổ hiển thị - + Open Recent Mở file gần Đây - + You have successfully cleared the list @@ -1520,86 +1520,92 @@ Bạn Đã xóa thành công danh sách - - - - + + + + + Warning Cảnh báo - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil không thể mở file này. Nếu như bạn muốn nhập vào hình ảnh, hãy sử dụng chức nhăn "Nhập vào" - + Opening document... Đang mở file... - - - + + + Abort Từ chối - + Saving document... Đang lưu file... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>Có lỗi phát sinh và file của bạn không thể lưu lại. Nếu bạn cho rằng Đây là lỗi thuộc về Pencil2D, hãy thông báo cho chúng tôi biết tại<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Hãy chắc rằng bạn Đã gửi những chi tiết lỗi sau Đây cho chúng tôi: - + This animation has been modified. Do you want to save your changes? File hoạt hình Đã Được thay Đổi Bạn có chắc rằng muốn lưu lại những thay Đổi này? - + The animation is not saved yet. Do you want to save now? File này chưa Được lưu. Bạn có muốn lưu ngay không? - + Never ask again AutoSave reminder button Đừng hỏi lại - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Không thể nhập vào hình ảnh.<br><b>Cách giải quyết:</b>Hãy sử dụng Layer Bitmap Để nhập vào ảnh Bitmaps. - + Importing image sequence... - - + + was unable to import + + + + + Undo Menu item text - + Redo Menu item text - + Stop Ngừng ngay @@ -1607,122 +1613,122 @@ Bạn có muốn lưu ngay không? Object - + Black Trở lại - + Red Đỏ - + Dark Red Đỏ Đậm - + Orange Cam - + Dark Orange Cam Đậm - + Yellow Vàng - + Dark Yellow Vàng Đậm - + Green Xanh lá cây - + Dark Green Xanh lá cây Đậm - + Cyan Lục lam - + Dark Cyan Lục lam sậm - + Blue Xanh dương - + Dark Blue Xanh dương Đậm - + White Trắng - + Very Light Grey Xám nhạt - + Light Grey Xám nhẹ - + Grey Xám - + Dark Grey Xám Đậm - + Light Skin Màu da sáng - + Light Skin - shade Màu da sáng Đổ bóng - + Skin Màu da - + Skin - shade Bóng da - + Dark Skin Da sậm - + Dark Skin - shade Bóng da sậm @@ -1857,26 +1863,26 @@ Bạn có muốn lưu ngay không? - + Warning: Transparency is not currently supported in movie files Command line warning - + Exporting movie... Command line task progress - - + + Done. Command line task done - + Exporting image sequence... Command line task progress @@ -1937,8 +1943,8 @@ Bạn có muốn lưu ngay không? - Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) - Images - Hình ảnh (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) + Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + @@ -1981,1337 +1987,1337 @@ Bạn có muốn lưu ngay không? File diễn hoạt của Pencil PCLX(*.pclx);;Old Pencil Animation File PCL(*.pcl) - + Vivid Pink Màu hồng sáng - + Strong Pink Hồng Đậm - + Deep Pink Hồng chói - + Light Pink Hồng nhạt - + Moderate Pink Hồng chuẩn - + Dark Pink Hồng tối - + Pale Pink Hồng nhạt hơn - + Grayish Pink Hồng xám - + Pinkish White Hồng trắng - + Pinkish Gray Xám trắng - + Vivid Red Đỏ sáng - + Strong Red Đỏ Đậm - + Deep Red Đỏ chói - + Very Deep Red Rất Đỏ Đậm - + Moderate Red Đỏ chuẩn - + Dark Red Đỏ tối - + Very Dark Red Đỏ rất tối - + Light Grayish Red Đỏ xám nhẹ - + Grayish Red Đỏ xám - + Dark Grayish Red Đỏ xám tối - + Blackish Red Đỏ Đen - + Reddish Gray Đỏ xám pha - + Dark Reddish Gray Đỏ xám tối pha - + Reddish Black Đỏ Đen pha - + Vivid Yellowish Pink Vàng hồng chói - + Strong Yellowish Pink Vàng hồng Đậm - + Deep Yellowish Pink Vàng hồng chói - + Light Yellowish Pink Vàng hồng nhẹ - + Moderate Yellowish Pink Vàng hồng chuẩn - + Dark Yellowish Pink Vàng hồng tối - + Pale Yellowish Pink Vàng hồng nhạt - + Grayish Yellowish Pink Xám vàng hồng pha - + Brownish Pink Hồng nâu - + Vivid Reddish Orange Cam Đỏ chói - + Strong Reddish Orange Cam Đỏ Đậm - + Deep Reddish Orange Cam Đỏ Chói pha - + Moderate Reddish Orange Cam Đỏ pha chuẩn - + Dark Reddish Orange Cam Đỏ pha tối - + Grayish Reddish Orange Cam Đỏ xám pha - + Strong Reddish Brown Nâu Đỏ Đậm - + Deep Reddish Brown Nâu Đỏ chói - + Light Reddish Brown Nâu Đỏ nhạt - + Moderate Reddish Brown Nâu Đỏ chuẩn - + Dark Reddish Brown Nâu Đỏ tối - + Light Grayish Reddish Brown Nâu Đỏ Xám nhạt pha - + Grayish Reddish Brown Nâu Đỏ xám pha - + Dark Grayish Reddish Brown Nâu Đỏ Xám tối pha - + Vivid Orange Cam chói - + Brilliant Orange Cam sặc sỡ - + Strong Orange Cam Đậm - + Deep Orange Cam chói - + Light Orange Cam nhạt - + Moderate Orange Cam chuẩn - + Brownish Orange Cam nâu Đỏ - + Strong Brown Nâu Đậm - + Deep Brown Nâu Đậm - + Light Brown Nâu nhạt - + Moderate Brown Nâu chuẩn - + Dark Brown Nâu tối - + Light Grayish Brown Nâu xám nhẹ - + Grayish Brown Nâu xám - + Dark Grayish Brown Nâu xám tối - + Light Brownish Gray Xám nâu nhẹ - + Brownish Gray Xám nâu pha - + Brownish Black Đen nâu pha - + Vivid Orange Yellow Vàng cam Chói - + Brilliant Orange Yellow Vàng cam sặc sỡ - + Strong Orange Yellow Vàng cam Đậm - + Deep Orange Yellow Vàng cam chói - + Light Orange Yellow Vàng cam nhạt - + Moderate Orange Yellow Vàng cam chuẩn - + Dark Orange Yellow Vàng cam tối - + Pale Orange Yellow Vàng cam pha nhạt - + Strong Yellowish Brown Nâu vàng pha Đậm - + Deep Yellowish Brown Nâu vàng chói - + Light Yellowish Brown Nâu vàng nhạt - + Moderate Yellowish Brown Nâu vàng chuẩn - + Dark Yellowish Brown Nâu vàng pha tối - + Light Grayish Yellowish Brown Nâu vàng Xám pha nhạt - + Grayish Yellowish Brown Nâu vàng Xám pha - + Dark Grayish Yellowish Brown Nâu vàng xám tối - + Vivid Yellow Vàng chói - + Brilliant Yellow Vàng sặc sỡ - + Strong Yellow Vàng Đậm - + Deep Yellow Vàng mạnh - + Light Yellow Vàng nhạt - + Moderate Yellow Vàng chuẩn - + Dark Yellow Vàng tối - + Pale Yellow Vàng nhẹ - + Grayish Yellow Vàng pha xám - + Dark Grayish Yellow Vàng pha xám tối - + Yellowish White Trắng pha vàng - + Yellowish Gray Xám pha vàng - + Light Olive Brown Nâu Ô liu nhạt - + Moderate Olive Brown Nâu ô liêu chuẩn - + Dark Olive Brown Nâu ô liêu tối - + Vivid Greenish Yellow Vàng xanh lá Đậm - + Brilliant Greenish Yellow Vàng Xanh lá sặc sỡ - + Strong Greenish Yellow Vàng xanh lá sắc nét - + Deep Greenish Yellow Vàng xanh lá pha Đậm - + Light Greenish Yellow Vàng xanh lá pha nhạt - + Moderate Greenish Yellow Vàng pha xanh lá chuẩn - + Dark Greenish Yellow Vàng pha xanh lá tối - + Pale Greenish Yellow Vàng pha xanh lá nhạt - + Grayish Greenish Yellow Vàng xanh lá pha xám - + Light Olive Màu ô liu nhạt - + Moderate Olive Màu ô liu chuẩn - + Dark Olive Màu ô liu tối - + Light Grayish Olive Màu ô liu pha xám nhẹ - + Grayish Olive Màu ô liu pha xám - + Dark Grayish Olive Màu ô liu pha xám tối - + Light Olive Gray Xám ô liu nhạt - + Olive Gray Xám ô liu - + Olive Black Đen ô liu - + Vivid Yellow Green Xanh lá cây vàng rực rỡ - + Brilliant Yellow Green Xanh lá cây vàng sống Động - + Strong Yellow Green Xanh lá cây vàng Đậm - + Deep Yellow Green Xanh lá cây vàng Đậm pha - + Light Yellow Green Xanh lá cây vàng nhạt - + Moderate Yellow Green Xanh lá cây vàng chuẩn - + Pale Yellow Green Xanh lá cây vàng hơi nhạt - + Grayish Yellow Green Xanh lá cây vàng pha xám - + Strong Olive Green Xanh lá cây ô liu Đậm - + Deep Olive Green Xanh lá cây ô liu pha Đậm - + Moderate Olive Green Xanh lá ô liu chuẩn - + Dark Olive Green Xanh lá ô liu tối - + Grayish Olive Green Xanh lá ô liu pha xám - + Dark Grayish Olive Green Xanh lá ô liu pha tối - + Vivid Yellowish Green Xanh lá vàng rực rỡ - + Brilliant Yellowish Green Xanh lá vàng sặc sỡ - + Strong Yellowish Green Xanh lá vàng Đậm - + Deep Yellowish Green Xanh lá Vàng pha Đậm - + Very Deep Yellowish Green Rất Đậm xanh lá pha vàng - + Very Light Yellowish Green Rất nhạt xanh lá pha vàng - + Light Yellowish Green Xanh lá pha vàng nhạt - + Moderate Yellowish Green Xanh lá pha vàng chuẩn - + Dark Yellowish Green Xanh lá pha vàng tối - + Very Dark Yellowish Green Xanh lá pha vàng rất tối - + Vivid Green Xanh lá rực rỡ - + Brilliant Green Xanh lá sặc sỡ - + Strong Green Xanh lá Đậm - + Deep Green Xanh lá Đậm - + Very Light Green Xanh lá rất nhạt - + Light Green Xanh lá nhạt - + Moderate Green Xanh lá chuẩn - + Dark Green Xanh lá tối - + Very Dark Green Xanh lá rất tối - + Very Pale Green Xanh lá nhợt nhạt - + Pale Green Xanh lá hơi nhạt - + Grayish Green Xanh lá pha xám - + Dark Grayish Green Xanh lá pha xám tối - + Blackish Green Xanh lá pha Đen - + Greenish White Trắng pha xanh lá - + Light Greenish Gray Xám pha xanh lá nhẹ - + Greenish Gray Xám pha xanh lá - + Dark Greenish Gray Xám pha xanh lá tối - + Greenish Black Đen pha xanh lá - + Vivid Bluish Green Xanh lá cây pha sống Động - + Brilliant Bluish Green Xanh lá cây pha sặc sỡ - + Strong Bluish Green Xanh lá cây Đậm - + Deep Bluish Green Xanh lá cây Đậm Đà - + Very Light Bluish Green Xanh lá cây pha rất nhạt - + Light Bluish Green Xanh lá pha nhạt - + Moderate Bluish Green Xanh lá Đậm chuẩn - + Dark Bluish Green Xanh lá Đậm tối - + Very Dark Bluish Green Xanh lá Đậm rất tối - + Vivid Greenish Blue Xanh dương pha xanh lá rực rỡ - + Brilliant Greenish Blue Xanh dương pha xanh lá Sặc sỡ - + Strong Greenish Blue Xanh dương pha xanh lá Đậm Đà - + Deep Greenish Blue Xanh dương pha xanh lá sống Động - + Very Light Greenish Blue Xanh dương pha xanh lá rất nhạt - + Light Greenish Blue Xanh dương pha xanh lá nhạt - + Moderate Greenish Blue Xanh dương pha xanh lá chuẩn - + Dark Greenish Blue Xanh dương pha xanh lá tối - + Very Dark Greenish Blue Xanh dương pha xanh lá rất tối - + Vivid Blue Xanh dương rực rỡ - + Brilliant Blue Xanh dương sặc sỡ - + Strong Blue Xạnh dương sống Động - + Deep Blue Xanh dương Đậm Đà - + Very Light Blue Xanh dương rất nhạt - + Light Blue Xanh dương nhạt - + Moderate Blue Xanh dương chuẩn - + Dark Blue Xanh dương tối - + Very Pale Blue Xanh dương pha rất nhạt - + Pale Blue Xanh dương pha nhạt - + Grayish Blue Xanh dương pha xám - + Dark Grayish Blue Xanh dương pha xám tối - + Blackish Blue Xanh dương pha Đen - + Bluish White Trắng tự nhiên - + Light Bluish Gray Xám nhẹ - + Bluish Gray Xám Đặc trưng - + Dark Bluish Gray Xám Đâm tối - + Bluish Black Đen Đặc trưng - + Vivid Purplish Blue Xanh dương pha tím sặc sỡ - + Brilliant Purplish Blue Xanh dương pha tím rực rỡ - + Strong Purplish Blue Xanh dương pha tím Đậm - + Deep Purplish Blue Xanh dương pha tím Đậm Đà - + Very Light Purplish Blue Xanh dương pha tím rất nhạt - + Light Purplish Blue Xanh dương pha tím nhạt - + Moderate Purplish Blue Xanh dương pha tím chuẩn - + Dark Purplish Blue Xanh dương pha tím tối - + Very Pale Purplish Blue Xanh dương pha tím hơi nhạt - + Pale Purplish Blue Xanh dương tím pha hơi nhạt - + Grayish Purplish Blue Xanh dương tím pha xám - + Vivid Violet Tím rực rỡ - + Brilliant Violet Tím sặc sỡ - + Strong Violet Tím sinh Động - + Deep Violet Tím Đậm - + Very Light Violet Tím rất nhạt - + Light Violet Tím nhạt - + Moderate Violet Tím chuẩn - + Dark Violet Tím màu tối - + Very Pale Violet Tím hơi nhạt - + Pale Violet Tím nhạt - + Grayish Violet Tím pha xám - + Vivid Purple Tím hoàng hôn rực rỡ - + Brilliant Purple Tím hoàng hôn sặc sỡ - + Strong Purple Tím hoàng hôn Đậm - + Deep Purple Tím hoàng hôn sinh Động - + Very Deep Purple Tím hoàng hôn sắc nét - + Very Light Purple Tím hoàng hôn nhạt - + Light Purple Tím hoàng hôn nhạt - + Moderate Purple Tím hoàng hôn chuẩn - + Dark Purple Tím hoàng hôn tối - + Very Dark Purple Tím hoàng hôn rất tối - + Very Pale Purple Tím hoàng hôn rất nhạt - + Pale Purple Tím hoàng hôn nhạt - + Grayish Purple Tím hoàng hôn pha xám - + Dark Grayish Purple Tím hoàng hôn pha xám tối - + Blackish Purple Tím hoàng hôn Đen - + Purplish White Trắng pha tím - + Light Purplish Gray Xám pha tím nhạt - + Purplish Gray Xám pha tím - + Dark Purplish Gray Xám pha tím tối - + Purplish Black Đen pha tím hoàng hôn - + Vivid Reddish Purple Tím hoàn hôn pha Đỏ rực rỡ - + Strong Reddish Purple Tím hoàng hôn pha Đỏ Đậm - + Deep Reddish Purple Tím hoàng hôn pha Đỏ sặc sỡ - + Very Deep Reddish Purple Tím hoàng hôn pha Đỏ sống Động - + Light Reddish Purple Tím hoàng hộn pha Đỏ nhạt - + Moderate Reddish Purple Tím hoàng hôn pha Đỏ chuẩn - + Dark Reddish Purple Tím hoàng hôn pha Đỏ tối - + Very Dark Reddish Purple Tím hoàng hôn pha Đỏ rất tối - + Pale Reddish Purple Tím hoàng hôn pha Đỏ nhợt nhạt - + Grayish Reddish Purple Tím hoàng hôn pha Đỏ xám - + Brilliant Purplish Pink Hồng pha tím rực rỡ - + Strong Purplish Pink Hồng pha tím Đậm - + Deep Purplish Pink Hồng pha tím sặc sỡ - + Light Purplish Pink Hồng pha tím nhẹ - + Moderate Purplish Pink Hồng pha tím chuẩn - + Dark Purplish Pink Hồng pha tím tối - + Pale Purplish Pink Hồng pha tím nhợt nhạt - + Grayish Purplish Pink Hồng pha tím xám - + Vivid Purplish Red Đỏ pha tím rực rỡ - + Strong Purplish Red Đỏ pha tím Đậm Đà - + Deep Purplish Red Đỏ pha tím sống Động - + Very Deep Purplish Red Đỏ pha tím sặc sỡ - + Moderate Purplish Red Đỏ pha tím chuẩn - + Dark Purplish Red Đỏ pha tím tối - + Very Dark Purplish Red Đỏ pha tím rất tối - + Light Grayish Purplish Red Đỏ pha tím xám nhẹ - + Grayish Purplish Red Đỏ pha tím xám - + White Trắng - + Light Gray Xám nhẹ - + Medium Gray Xám chuẩn - + Dark Gray Xám tối - + Black Đen @@ -3332,60 +3338,60 @@ Bạn có muốn lưu ngay không? ScribbleArea - + Warning Cảnh báo - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Bạn Đang vẽ trên một Layer có thuộc tính ẩn! Hãy chọn một Layer khác (Hoặc Điều chỉnh thuộc tính Layer hiện tại thành hiển thị). - + Delete Selection Undo Step: clear the selection area. - - + + Clear Image Undo step text Làm sạch hình ảnh - + There is a gap in your drawing (or maybe you have zoomed too much). Xuất hiện hiện tượng rổ trên ảnh của bạn (hoặc bạn Đã phóng to quá nhiều). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). Thật xin lỗi! Chức năng này vẫn chưa Được hoàn thiện. Hãy thử lại một lần nữa (Phóng to một chút thôi, và chọn chỗ khác...) <br>Nếu chức năng vẫn không hoạt Động, Phóng to vào một chút và kiểm tra Đường dẫn chính xác bằng cách nhấn F1.). - + Out of bound. Ngoài giới hạn xử lý - + Could not find a closed path. Không thể tìm Được Đường dẫn Đúng - + Could not find the root index. Không thể tìm Được chỉ mục gốc - + %1<br><br>Error: %2 %1<br><br>Lỗi: %2 - + Flood fill error Lỗi tô màu @@ -3590,12 +3596,12 @@ Bạn có muốn lưu ngay không? TimeLineCells - + Layer Properties - + Layer name: @@ -3632,6 +3638,46 @@ Bạn có muốn lưu ngay không? Preferences + + + Drawing + + + + + When drawing on an empty frame: + + + + + Create a new (blank) key-frame and start drawing on it. + + + + + Create a new (blank) key-frame + + + + + Duplicate the previous key-frame and start drawing on the duplicate. + + + + + Duplicate the previous key-frame + + + + + Keep drawing on the previous key-frame + + + + + <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + Frame size diff --git a/translations/pencil_zh_TW.ts b/translations/pencil_zh_TW.ts index 13a367984..2edfbc725 100644 --- a/translations/pencil_zh_TW.ts +++ b/translations/pencil_zh_TW.ts @@ -148,57 +148,57 @@ BaseTool - + Pencil 鉛筆 - + Eraser 橡皮擦 - + Select 全選 - + Move 移動 - + Hand - + Smudge 塗抹 - + Pen 鋼筆 - + Polyline 多邊形工具 - + Bucket 油漆桶 - + Eyedropper 吸管 - + Brush 刷子 @@ -360,8 +360,8 @@ ColorPaletteWidget - - + + Colour name 顏色名稱 @@ -1278,7 +1278,7 @@ - + Play 播放 @@ -1496,106 +1496,112 @@ 影格後移 - + color palette:<br>use <b>(C)</b><br>toggle at cursor - + Lock Windows 鎖定視窗 - + Open Recent 最近開啟的 - + You have successfully cleared the list 成功清除清單 - - - - + + + + + Warning 警告 - - + + Pencil cannot read this file. If you want to import images, use the command import. Pencil 無法讀取這個檔案。如果您想要匯入影像,請使用指令匯入。 - + Opening document... 開啟文件... - - - + + + Abort 中止 - + Saving document... 儲存文件... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>發現錯誤,你的檔案可能並未成功保存。如果你看見這個訊息,請到<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a>協助回報錯誤<br>並附上以下錯誤細節訊息: - + This animation has been modified. Do you want to save your changes? 動畫已經修改。你想要儲存檔案嗎? - + The animation is not saved yet. Do you want to save now? 您的動畫還沒儲存。要現在儲存嗎? - + Never ask again AutoSave reminder button 不要再問我 - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. 無法匯入圖片。<br><b>提示</b> 使用點陣圖層來匯入點陣圖 - + Importing image sequence... - - + + was unable to import + + + + + Undo Menu item text - + Redo Menu item text - + Stop 停止 @@ -1603,122 +1609,122 @@ Object - + Black 黑色 - + Red 紅色 - + Dark Red 深紅色 - + Orange 橙色 - + Dark Orange 深橙色 - + Yellow 黃色 - + Dark Yellow 深黃色 - + Green 綠色 - + Dark Green 深綠色 - + Cyan 青色 - + Dark Cyan 深青色 - + Blue 藍色 - + Dark Blue 深藍色 - + White 白色 - + Very Light Grey 很淺灰色 - + Light Grey 淺灰色 - + Grey 灰色 - + Dark Grey 深灰色 - + Light Skin 淺膚色 - + Light Skin - shade - + Skin 膚色 - + Skin - shade - + Dark Skin 深膚色 - + Dark Skin - shade @@ -1853,26 +1859,26 @@ - + Warning: Transparency is not currently supported in movie files Command line warning - + Exporting movie... Command line task progress - - + + Done. Command line task done - + Exporting image sequence... Command line task progress @@ -1933,7 +1939,7 @@ - Images (*.png *.jpg *.jpeg *.tiff *.tif *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;TIFF(*.tif *.tiff);;BMP(*.bmp);;GIF(*.gif) + Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) @@ -1977,1337 +1983,1337 @@ - + Vivid Pink 亮粉紅 - + Strong Pink - + Deep Pink - + Light Pink - + Moderate Pink - + Dark Pink - + Pale Pink - + Grayish Pink - + Pinkish White - + Pinkish Gray - + Vivid Red - + Strong Red - + Deep Red - + Very Deep Red - + Moderate Red - + Dark Red - + Very Dark Red - + Light Grayish Red - + Grayish Red - + Dark Grayish Red - + Blackish Red - + Reddish Gray - + Dark Reddish Gray - + Reddish Black - + Vivid Yellowish Pink - + Strong Yellowish Pink - + Deep Yellowish Pink - + Light Yellowish Pink - + Moderate Yellowish Pink - + Dark Yellowish Pink - + Pale Yellowish Pink - + Grayish Yellowish Pink - + Brownish Pink - + Vivid Reddish Orange - + Strong Reddish Orange - + Deep Reddish Orange - + Moderate Reddish Orange - + Dark Reddish Orange - + Grayish Reddish Orange - + Strong Reddish Brown - + Deep Reddish Brown - + Light Reddish Brown - + Moderate Reddish Brown - + Dark Reddish Brown - + Light Grayish Reddish Brown - + Grayish Reddish Brown - + Dark Grayish Reddish Brown - + Vivid Orange - + Brilliant Orange - + Strong Orange - + Deep Orange - + Light Orange - + Moderate Orange - + Brownish Orange - + Strong Brown - + Deep Brown - + Light Brown - + Moderate Brown - + Dark Brown - + Light Grayish Brown - + Grayish Brown - + Dark Grayish Brown - + Light Brownish Gray - + Brownish Gray - + Brownish Black - + Vivid Orange Yellow - + Brilliant Orange Yellow - + Strong Orange Yellow - + Deep Orange Yellow - + Light Orange Yellow - + Moderate Orange Yellow - + Dark Orange Yellow - + Pale Orange Yellow - + Strong Yellowish Brown - + Deep Yellowish Brown - + Light Yellowish Brown - + Moderate Yellowish Brown - + Dark Yellowish Brown - + Light Grayish Yellowish Brown - + Grayish Yellowish Brown - + Dark Grayish Yellowish Brown - + Vivid Yellow - + Brilliant Yellow - + Strong Yellow - + Deep Yellow - + Light Yellow - + Moderate Yellow - + Dark Yellow - + Pale Yellow - + Grayish Yellow - + Dark Grayish Yellow - + Yellowish White - + Yellowish Gray - + Light Olive Brown - + Moderate Olive Brown - + Dark Olive Brown - + Vivid Greenish Yellow - + Brilliant Greenish Yellow - + Strong Greenish Yellow - + Deep Greenish Yellow - + Light Greenish Yellow - + Moderate Greenish Yellow - + Dark Greenish Yellow - + Pale Greenish Yellow - + Grayish Greenish Yellow - + Light Olive - + Moderate Olive - + Dark Olive - + Light Grayish Olive - + Grayish Olive - + Dark Grayish Olive - + Light Olive Gray - + Olive Gray - + Olive Black - + Vivid Yellow Green - + Brilliant Yellow Green - + Strong Yellow Green - + Deep Yellow Green - + Light Yellow Green - + Moderate Yellow Green - + Pale Yellow Green - + Grayish Yellow Green - + Strong Olive Green - + Deep Olive Green - + Moderate Olive Green - + Dark Olive Green - + Grayish Olive Green - + Dark Grayish Olive Green - + Vivid Yellowish Green - + Brilliant Yellowish Green - + Strong Yellowish Green - + Deep Yellowish Green - + Very Deep Yellowish Green - + Very Light Yellowish Green - + Light Yellowish Green - + Moderate Yellowish Green - + Dark Yellowish Green - + Very Dark Yellowish Green - + Vivid Green - + Brilliant Green - + Strong Green - + Deep Green - + Very Light Green - + Light Green - + Moderate Green - + Dark Green - + Very Dark Green - + Very Pale Green - + Pale Green - + Grayish Green - + Dark Grayish Green - + Blackish Green - + Greenish White - + Light Greenish Gray - + Greenish Gray - + Dark Greenish Gray - + Greenish Black - + Vivid Bluish Green - + Brilliant Bluish Green - + Strong Bluish Green - + Deep Bluish Green - + Very Light Bluish Green - + Light Bluish Green - + Moderate Bluish Green - + Dark Bluish Green - + Very Dark Bluish Green - + Vivid Greenish Blue - + Brilliant Greenish Blue - + Strong Greenish Blue - + Deep Greenish Blue - + Very Light Greenish Blue - + Light Greenish Blue - + Moderate Greenish Blue - + Dark Greenish Blue - + Very Dark Greenish Blue - + Vivid Blue - + Brilliant Blue - + Strong Blue - + Deep Blue - + Very Light Blue - + Light Blue - + Moderate Blue - + Dark Blue - + Very Pale Blue - + Pale Blue - + Grayish Blue - + Dark Grayish Blue - + Blackish Blue - + Bluish White - + Light Bluish Gray - + Bluish Gray - + Dark Bluish Gray - + Bluish Black - + Vivid Purplish Blue - + Brilliant Purplish Blue - + Strong Purplish Blue - + Deep Purplish Blue - + Very Light Purplish Blue - + Light Purplish Blue - + Moderate Purplish Blue - + Dark Purplish Blue - + Very Pale Purplish Blue - + Pale Purplish Blue - + Grayish Purplish Blue - + Vivid Violet - + Brilliant Violet - + Strong Violet - + Deep Violet - + Very Light Violet - + Light Violet - + Moderate Violet - + Dark Violet - + Very Pale Violet - + Pale Violet - + Grayish Violet - + Vivid Purple - + Brilliant Purple - + Strong Purple - + Deep Purple - + Very Deep Purple - + Very Light Purple - + Light Purple - + Moderate Purple - + Dark Purple - + Very Dark Purple - + Very Pale Purple - + Pale Purple - + Grayish Purple - + Dark Grayish Purple - + Blackish Purple - + Purplish White - + Light Purplish Gray - + Purplish Gray - + Dark Purplish Gray - + Purplish Black - + Vivid Reddish Purple - + Strong Reddish Purple - + Deep Reddish Purple - + Very Deep Reddish Purple - + Light Reddish Purple - + Moderate Reddish Purple - + Dark Reddish Purple - + Very Dark Reddish Purple - + Pale Reddish Purple - + Grayish Reddish Purple - + Brilliant Purplish Pink - + Strong Purplish Pink - + Deep Purplish Pink - + Light Purplish Pink - + Moderate Purplish Pink - + Dark Purplish Pink - + Pale Purplish Pink - + Grayish Purplish Pink - + Vivid Purplish Red - + Strong Purplish Red - + Deep Purplish Red - + Very Deep Purplish Red - + Moderate Purplish Red - + Dark Purplish Red - + Very Dark Purplish Red - + Light Grayish Purplish Red - + Grayish Purplish Red - + White - + Light Gray - + Medium Gray - + Dark Gray - + Black @@ -3328,60 +3334,60 @@ ScribbleArea - + Warning 警告 - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). 您在隱藏的圖層上繪製!請選擇其他圖層(或使目前圖層可看見)。 - + Delete Selection Undo Step: clear the selection area. 刪除選擇 - - + + Clear Image Undo step text 清除 - + There is a gap in your drawing (or maybe you have zoomed too much). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). - + Out of bound. 超出界線 - + Could not find a closed path. - + Could not find the root index. - + %1<br><br>Error: %2 - + Flood fill error 填滿功能錯誤 @@ -3586,12 +3592,12 @@ TimeLineCells - + Layer Properties 圖層屬性 - + Layer name: 圖層名稱: @@ -3628,6 +3634,46 @@ Preferences 時間軸長度: + + + Drawing + + + + + When drawing on an empty frame: + + + + + Create a new (blank) key-frame and start drawing on it. + + + + + Create a new (blank) key-frame + + + + + Duplicate the previous key-frame and start drawing on the duplicate. + + + + + Duplicate the previous key-frame + + + + + Keep drawing on the previous key-frame + + + + + <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + Frame size From 15286c28382ab03aaeaee965fc60cd3e2a2d2052 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 17 Jul 2018 10:20:34 +1000 Subject: [PATCH 138/184] lupdate --- translations/pencil.ts | 919 +++++++++++++++++++++++++---------------- 1 file changed, 567 insertions(+), 352 deletions(-) diff --git a/translations/pencil.ts b/translations/pencil.ts index e4fb7d5dc..376e6519f 100644 --- a/translations/pencil.ts +++ b/translations/pencil.ts @@ -15,13 +15,13 @@ - + Version: %1 Version Number in About Dialog - + Copy to clipboard Copy system info from About Dialog @@ -57,30 +57,30 @@ - + Exporting movie - + Finished. Open movie now? When movie export done. - - - - + + + + Layer Properties - - - - + + + + Layer name: @@ -90,58 +90,63 @@ - + + Finished. Open file location? + + + + Exporting image sequence... - + Abort - + Warning - + Unable to export image. - + Bitmap Layer - + Vector Layer - + Camera Layer - + Sound Layer - + Delete Layer Windows title of Delete current layer pop-up. - + Are you sure you want to delete layer: - + Please keep at least one camera layer in project text when failed to delete camera layer @@ -150,57 +155,57 @@ BaseTool - + Pencil - + Eraser - + Select - + Move - + Hand - + Smudge - + Pen - + Polyline - + Bucket - + Eyedropper - + Brush @@ -226,69 +231,55 @@ ColorBox - - Color Wheel - Color Wheel's window title + + Color Box + Color Box window title ColorInspector - + HSV - + RGB - - - Red + + R - - - Green + + A - - - Blue + + G - - - - Alpha + + B - - Hue - - - - - Saturation - - - - - Value + + Color Inspector + Window title of color inspector ColorPalette - + Color Palette Window title of color palette. @@ -304,57 +295,57 @@ - - ... + + Native color dialog window - + List Mode - + Show palette as a list - + Grid Mode - + Show palette as icons - + Small swatch - + Sets swatch size to: 16x16px - + Medium Swatch - + Sets swatch size to: 26x26px - + Large Swatch - + Sets swatch size to: 36x36px @@ -362,11 +353,60 @@ ColorPaletteWidget - - + + Add + + + + + Replace + + + + + Remove + + + + + Colour name + + + The color(s) you are about to delete are currently being used by one or multiple strokes. + + + + + Cancel + + + + + Delete + + + + + Palette Restriction + + + + + The palette requires at least one swatch to remain functional + + + + + ColorWheel + + + Color Wheel + Color Wheel's window title + + DisplayOption @@ -448,19 +488,19 @@ Editor - - + + Paste - + Remove frame - - + + Import Image @@ -486,12 +526,12 @@ ExportImageDialog - + Export image sequence - + Export image @@ -533,11 +573,51 @@ Transparency + + + Range + + + + + The last frame you want to include in the exported movie + + + + + End Frame + + + + + The first frame you want to include in the exported movie + + + + + Start Frame + + + + + <html><head/><body><p>End frame is set to last paintable keyframe (Useful when you only want to export to the last animated frame)</p></body></html> + + + + + To the end of sound clips + + ExportMovieDialog - + + Export Animated GIF + + + + Export Movie @@ -629,67 +709,83 @@ - Import movie + Import Animated GIF - Import sound + Import movie + Import sound + + + + Import palette - + Save animation - + Export image - + Export image sequence - + + Export Animated GIF + + + + Export movie - + Export sound - + Export palette - + + + Animated GIF (*.gif) + + + + Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) - - - Palette (*.xml) + + + Pencil2D Palette (*.xml);; Gimp Palette (*.gpl) - - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) + + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng) - + MyAnimation.pclx @@ -697,52 +793,72 @@ FileManager - - - + + + Could not open file + + + + + The file does not exist, so we are unable to open it. Please check to make sure the path is correct and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + Invalid Save Path - + The path ("%1") points to a directory. - + The directory ("%1") does not exist. - + The path ("%1") is not writable. - - + + Cannot Create Data Directory - + Failed to create directory "%1". Please make sure you have sufficient permissions. - + "%1" is a file. Please delete the file and try again. - - + + Miniz Error + + + + Internal Error - - + + An internal error occurred. Your file may not be saved successfully. @@ -820,87 +936,97 @@ - + Czech - + Danish - + English - + German - + + Estonian + + + + Spanish - + French - + Hebrew - + Hungarian - + Indonesian - + Italian - + Japanese - + + Polish + + + + Portuguese - Portugal - + Portuguese - Brazil - + Russian - + Slovenian - + Vietnamese - + Chinese - Taiwan @@ -945,12 +1071,12 @@ - + Restart Required - + The language change will take effect after a restart of Pencil2D @@ -976,7 +1102,12 @@ ImportImageSeqDialog - + + Import Animated GIF + + + + Import image sequence @@ -1000,7 +1131,7 @@ LayerBitmap - + Bitmap Layer @@ -1016,7 +1147,7 @@ LayerSound - + Sound Layer @@ -1047,686 +1178,745 @@ - + Export - + Edit - + Selection - + View - + Onion Skin - + Animation - - + + Tools - + Layer - - + + Help - + Windows - + New - + Open - + Save - + Save As .. - + Exit - - + + Image Sequence... - - + + Image... - - + + Movie... - - + + Palette... - + Sound... - + Undo - + Redo - + Cut - + Copy - + Paste - + Crop - + Crop To Selection - + Select All - + Deselect All - - + + Clear Frame - + Preferences - + Reset Windows - + Zoom In - + Zoom Out - + Rotate Clockwise - + Rotate AntiClosewise - + Reset Zoom/Rotate - + Horizontal Flip - + Vertical Flip - + Preview - + Grid - + Previous - + Show previous onion skin - + Next - + Show next onion skin - - + + Play - + Loop - + Next Frame - + Previous Frame - + Extend Frame - + Add Frame - + Duplicate Frame - + Remove Frame - + Move - + Select - + Brush - + Polyline - + Smudge - + Pen - + Hand - + Pencil - + Bucket - + Eyedropper - + Eraser - + New Bitmap Layer - + New Vector Layer - + New Sound Layer - + New Camera Layer - + Delete Current Layer - + About - - + + Reset to default - + MultiLayer Onion Skin - + Range - + Pencil2D Website - + Report a Bug - + Quick Reference Guide - + F1 - - + + + Animated GIF... + + + + + Next KeyFrame - - + + Previous KeyFrame - + Timeline - + Options - + Color Wheel - + Color Palette - + Display Options - + Flip X - + Flip Y - + Move Frame Forward - + Move Frame Backward - + color palette:<br>use <b>(C)</b><br>toggle at cursor - + + Color inspector + + + + Lock Windows - + Open Recent - + You have successfully cleared the list - - - - - + + + + + Could not open file + + + + + The file you have selected is a directory, so we are unable to open it. If you are are trying to open a project that uses the old structure, please open the file ending with .pcl, not the data folder. + + + + + The file you have selected does not exist, so we are unable to open it. Please check to make sure that you've entered the correct path and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + + + Warning - - - Pencil cannot read this file. If you want to import images, use the command import. + + This program does not currently have permission to write to the file you have selected. Please make sure you have write permission for this file before attempting to save it. Alternatively, you can use the Save As... menu option to save to a writable location. - + Opening document... - - - + + + + Abort - + + An unknown error occurred while trying to load the file and we are not able to load your file. + + + + Saving document... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: - + This animation has been modified. Do you want to save your changes? - + The animation is not saved yet. Do you want to save now? - + Never ask again AutoSave reminder button - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. - + Importing image sequence... - + + was unable to import - - + + Importing Animated GIF... + + + + + Undo Menu item text - + Redo Menu item text - + Stop + + MoveTool + + + Layer switch + Windows title of layer switch pop-up. + + + + + You are about to switch layer, do you want to apply the transformation? + + + Object - + Black - + Red - + Dark Red - + Orange - + Dark Orange - + Yellow - + Dark Yellow - + Green - + Dark Green - + Cyan - + Dark Cyan - + Blue - + Dark Blue - + White - + Very Light Grey - + Light Grey - + Grey - + Dark Grey - + Light Skin - + Light Skin - shade - + Skin - + Skin - shade - + Dark Skin - + Dark Skin - shade @@ -1734,153 +1924,153 @@ PencilApplication - + Pencil2D is an animation/drawing software for Mac OS X, Windows, and Linux. It lets you create traditional hand-drawn animation (cartoon) using both bitmap and vector graphics. - + Path to the input pencil file. - - + + Render the file to <output_path> - - + + output_path - + Name of the camera layer to use - + layer_name - + Width of the output frames - - + + integer - + Height of the output frames - + The first frame you want to include in the exported movie - - + + frame - + The last frame you want to include in the exported movie. Can also be last or last-sound to automatically use the last frame containing animation or sound, respectively - + Render transparency when possible - + Warning: width value %1 is not an integer, ignoring. - + Warning: height value %1 is not an integer, ignoring. - + Warning: start value %1 is not an integer, ignoring. - + Warning: start value must be at least 1, ignoring. - + Warning: end value %1 is not an integer, last or last-sound, ignoring. - + Warning: end value %1 is smaller than start value %2, ignoring. - + Error: No input file specified. - + Error: the input file at '%1' does not exist Command line error - + Error: the input path '%1' is not a file Command line error - + Warning: the specified camera layer %1 was not found, ignoring. - + Warning: Output format is not specified or unsupported. Using PNG. Command line warning - + Warning: Transparency is not currently supported in movie files Command line warning - + Exporting movie... Command line task progress - - + + Done. Command line task done - + Exporting image sequence... Command line task progress @@ -1922,12 +2112,12 @@ QApplication - + Checking environment... - + Done @@ -1935,42 +2125,47 @@ QObject - + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) - - Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp) - + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp); + + + + Everything ok. - + Ooops, Something went wrong. - + File doesn't exist. - + Cannot open file. - + The file is not a valid xml document. - + The file is not valid pencil document. @@ -3319,6 +3514,16 @@ Black + + + Could not open file + + + + + There was an error processing your file. This usually means that your project has been at least partially corrupted. You can try again with a newer version of Pencil2D, or you can try to use a backup file if you have one. If you contact us through one of our offical channels we may be able to help you. For reporting issues, the best places to reach us are: + + RecentFileMenu @@ -3336,60 +3541,60 @@ ScribbleArea - + Warning - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). - + Delete Selection Undo Step: clear the selection area. - - + + Clear Image Undo step text - + There is a gap in your drawing (or maybe you have zoomed too much). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). - + Out of bound. - + Could not find a closed path. - + Could not find the root index. - + %1<br><br>Error: %2 - + Flood fill error @@ -3486,12 +3691,12 @@ - + Start - + Stop @@ -3575,18 +3780,18 @@ - + Delete Layer Windows title of Delete current layer pop-up. - + Please keep at least one camera layer in project - + Are you sure you want to delete layer: @@ -3594,12 +3799,12 @@ TimeLineCells - + Layer Properties - + Layer name: @@ -3676,6 +3881,16 @@ <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + + Playback + + + + + Show onion skin while playing + + Frame size From 4f73eb168e0539e02789f0fdf009f18588278a02 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 17 Jul 2018 10:20:55 +1000 Subject: [PATCH 139/184] lrelease --- translations/pencil_cs.qm | Bin 39287 -> 53631 bytes translations/pencil_de.qm | Bin 63461 -> 63041 bytes translations/pencil_es.qm | Bin 76240 -> 75816 bytes translations/pencil_et.qm | Bin 30527 -> 36678 bytes translations/pencil_fr.qm | Bin 75314 -> 77562 bytes translations/pencil_he.qm | Bin 44090 -> 43670 bytes translations/pencil_hu_HU.qm | Bin 29613 -> 29195 bytes translations/pencil_it.qm | Bin 25950 -> 25526 bytes translations/pencil_ja.qm | Bin 25867 -> 25455 bytes translations/pencil_pt.qm | Bin 76302 -> 75880 bytes translations/pencil_pt_BR.qm | Bin 75868 -> 77388 bytes translations/pencil_ru.qm | Bin 42135 -> 41705 bytes translations/pencil_sl.qm | Bin 74018 -> 73600 bytes translations/pencil_vi.qm | Bin 61300 -> 60858 bytes 14 files changed, 0 insertions(+), 0 deletions(-) diff --git a/translations/pencil_cs.qm b/translations/pencil_cs.qm index 65389453ae4107b47baee6f6a9f8e93d028c488e..f9bb71703a41c6d859ea315bcf575a48c04731b5 100644 GIT binary patch delta 15646 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 delta 4228 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 diff --git a/translations/pencil_de.qm b/translations/pencil_de.qm index e202612458843392445ad34b280b633be70385d3..569a895cde3b013b364d21e70eaf675692d8f1fe 100644 GIT binary patch delta 3325 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 diff --git a/translations/pencil_es.qm b/translations/pencil_es.qm index ec585e3a1d6314d9c22048223843e9701b27e7d2..d24cc06334eb0803b13999b13e2d2acd6541d3bd 100644 GIT binary patch delta 3663 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 QjIzA9Y_@;p$&4BQ0wJ)>zW@LL diff --git a/translations/pencil_et.qm b/translations/pencil_et.qm index d4fada340ad4350c96ca626d253135c644be9c72..09d9a7479af53b5cde5729f7ab9835095634688b 100644 GIT binary patch delta 8021 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 K8(J}oWd8#dE5t?s delta 5974 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 diff --git a/translations/pencil_he.qm b/translations/pencil_he.qm index 8c68ebbe8b9fda0031f3b8f07714ef81613acc59..e1bb5bd75e4e9baeeccb41cd61ae11f3e47e7595 100644 GIT binary patch delta 1849 zcmX9;e^6A{89nbl-Y)z0?OTeDOhC4{$f^MsLIn*1=>~yF1T|qbf+S=c2nqs1ft8;D zTz;sFKdvZXv=|d5nh9}~8IwS&L>g=~rZrg7R@xY;okV;yC*l73lDcg0RP0pvs1bRh7WDdwfW+`tDeY*w87!eb|F-FL8+_$(I zYPqb~)Di_`Ttroe7qGt=E^|DP_!fG?tw8WnoJ^+k4GK>bEp>(e6U3Dy%*!D7bj}9a zhlLrvXMov$LZbLAz%L3ZM@V43D!g7b32Ztc(jkjLN|7RNzG$GUezAal!2ffxbR89RkBCnH93UWFta?Oa+cJaOB`d2w%UzO1Zn@#5nQaGZ zX7fHN-gk@JD_KbaB%24_MsCm)vhq=0qe+Tv`cX2El9t?aQm`Tc%cmsEo*BTt4r%@) zPOVC%)Z*`f=bEKVM?P7xf=_8Itm+&O)W);YlRQgniYeAfXEV(JyC_|IkPgK7d9Zq; zG`=zv$ZwR!Z>$1@(;jTemhS&RMfY&tr?r?%pVs(2St`F=jo;}s;CY88V7ryBjc9^i zqq1!?`Ls5g71(){x7A!>(4?Mg2dr;+uz6CGda(?c<;PKkbC-9Le^-#E<{8?p zpkPg1ULWx0w5Dm{yFfuVANNi(w+?7-r5pn0WoW&f^cJQ`t^PJG^_H)+Gb<*@A-B0* zXZ3Bnsy#NC2voFcPiQiL#zVYa7wx;vM|*vR49Ewx<7W%0=mfu}i}v4q*xO`YPIf=+ zy<}ZKFjw@BjcoxsBKShNoNc%A_vAIKyp2!GrpOALE`KLYzUpV4v;P*UY}M7b5ka1< z+dFWD0%g7Kz;iyduz9-Pbn3PBHc!=C>Po(r1FS^+HRTMpYv6lyZ$*!yJ8 zy>sQfRl`7tm)!dJWm-j-2X_p~dy4FoU>$PTo^IOgX8GU{nXM#Te!q%_U9?F4W7kSx z*;@H;H(iu)r{#N>^i``4{hh}t z7W39F{YM{BWX<`DzW>kU`QI+p53Zj{S7Lj@DlouDZk;*|OEn<`wJ3-0$avhKps=Qfp zodV>B;#?F3>?~8ND_;fDzf&5Ehk(p@#l2(_Q1X?7uV0|{eoD{6Dg>jXPC4^o10~08 z<@XCne$1FMSoImo)8Gg5ifSk9SIZ_TtU`{f&L`nlnXJ~{AS#<*R=eG0!2BHb%BCK&XuEpl6y4kR0zasl zSi8apRMYd@GL6>B5n%QA#)!3~aQ}7VuLkM8oO)xFA(^V&GbXG(Mh^bQxaN@x*j&bJ z8?h>^FlL|KPTh9#Kx4FAyxMreLBEUYd6v=i%ks6x9}nFm?rp{gnkb;@E#rf?A5)N~ XY#?V&^UHC;rv{9D`KQ#Hu<-u_k(DT< delta 2382 zcmZuyc~lhl9sleMv&Zc0j1i2lp!;x)Qud9D=Vfgi2FRaABvPq6*%^t@F6+4{*^D?OVZ5{+{ zoUih3J_HOJsETDL0u8yUgq;*%*&fwAcQ=r4Rb~CSozlBPmG@mO;Qv6iV$XP@pHXcd z`VpXof$h4igqlA?@2b`9eUzW_LWn36Xs4BI`XEW`cIEQ?|LI|2Y{7i)SP z1Z5y?N>nkes)-4BQW;?8}f4@P=0|O6|DojPqX7cxB;-c*(n>0K%D(f!K{tBZ0Vzm!>X zUf#yfc*hm2{rM7=by82^RX&RpB8YlOoK)rO$spLdOr5vj_dx{qEein-8{ce85=s!}|MDihZC{-^x~^t{)UFQT*2CT{QCSfD(WVF%laL_ssMi5X(Ld0f#2=6(6+k5 zpWiYam^zdH>)mqNjR*OEUD8uZ9`R2ul~5QqJwNOj^vJ!e7b~b-r9sOSG zC4DY=oM1Lpgz5L~qh&Yby8h^&Xy96V%?hV;sFxu81 z5Sm81fg(TQ(C1~8vP$9WAc`gYhS2J!6o=0e{_+)RTY5pb=1p`o3!SYj5S6artTDn( zf6C>uuZ8dDP$?$G3qS1a05Z#jpSXjxvFFM)hA?KCMm}vY2d`Xe__+5eg>cJosx6YZ zUK-9$BrDS=8?Lx01GWzhH-987XpskqW{>9^F|>*HM8R?~I{z@u;Bhf=2ZfL~TFgF7 z=XEE={BaEw`n#gDo3>ow9?{jeHQl$wlG~)V;Gwvq#t97160h2usC65}s|QGK<8AR# zCiTnUPO<0d31Do9*xQGOd*X{-B)6eSQVrE16VeNb|C>O61(P)Vaty8AISN+yN|x?+ z;O$$|sF~-eZA+vvttC|HUD7xMjelXSG-c*4Iy)y>w+rGO3><{mFj-CHJxPX!~7?Cs=x-9!I~f zLDG}0FKL**UqJuc&GOl(fCDX3OP)ss?ml;eYv;bB`#$_J9Ko=_fyKz7Q{VeSI=%j$ z_1{ww79g80g-5*;N_o%ug)0aVbfq8}*4M0f`phVw66mA#mHGc?QsGKPJmTn5 z+L;tUZIm?9`Zg&OHB$j-KFvNc{y2y{=S3t!Ip&% z<(bt7MGLaC6`-fh?x1JRg6yD(h?HdOD-k**q*zJ(e}Y6xjgN~X8p*%XLbRBq6e8Iq TyMqqa_`dIb$_`|>BSZfU)}N^n diff --git a/translations/pencil_hu_HU.qm b/translations/pencil_hu_HU.qm index 915c6a5b1b59774b9df99b5e7fcefe48451bcc44..212d8516cb4edcb52f817fb2d1316ffa474edfcc 100644 GIT binary patch delta 765 zcmXAmTS${(7{~v6U%$_N-?W3x6s;j1MyX9xv9xBMMKhUGv`sg4p2!oTcpy@#IZ$1EU9Q>o{X_1j8lYsA>4{FZs9+ws4On_v z3rUD7v7;uehwG@(7ns1aw=fc+1N{5(G=p~*&f&#y6W1uG>fCC*g<&Fl(KTorh_+31E zX=Obx%^an5d-I`X+HC3r%7KPy zS_C6*!A$2i20D ztIvtbWqy()GotJq1XOLJ&m?z^^AZC}0(s0P8x*Xv)hZh2Y&_->+ZI|$=|$EeYKbYB z4T&03>R{92Lb7E_8qb#j^K0qDeI0PrS6Y8Q!I>%TZ1O74U0KNGG}OrIuMVJMMGlKv z;PVeTyuX1Py<+q38dB8BesScDGEb$(&t_NE-s4)84^?%C_ZXzQ(i6jfw!+esT4FY{ zdSwpDi)PbGja)V9G4;5ICl9kVWjd(}VJ9RVDePqysf(0uuqCO$z4+NBZvAB@ delta 1246 zcmZuvZA@Eb6n=VdZ$EC!rW?4p#fE^?wqT23=CWD>8*9@JYAx+HIw+%X+Z9%9U_-JY zoy0A&h2i!ZlP$U!iG)PiLKeS%2qsS5Ou&yxGBulGM$kX}P!^YrF;DlR&cyrXzR!8i zd(Lytd+t4cLp3(9dL`GI4?M97kT-H{9S1z*Tip)$E&^sVP*V*w%${_O2$4Te&Q)w~ z{27w_GeA1cu|xx@W)ZM2K-#el*!>u!_yka@h159!lt0BWn#USd=3vt#q>JYP*9J&m zeL*-1N98<_d=RC9gFwr}*z_y4RJeqvi*EwX6C7)Q;@I*BM@3%2D{Mx!QHUE^j$oF< z49|Yu1~m6EmtdEpZzD4LD$rzN2ZV~UW((Si`{_F8aHODuv~Oe7VFxx0VcbJC>tpy} zq?4|_Q{@}>1G{`|POuBHX_hCNh2{z765W}WI^px8w*dXHaQ(7C4UdRx(uIK0E0)~t zqWkX@ORMz21Bb+|ubF`GoLEyubIEy0R8myb`>wbz%h%3|UG+x*rBdu!uK>Bn#6wFb zfV$P<3rDFL+a0mb^c|3A6UTajKu9Hy-JSsx)Q@T-cc?(1jTNcSu8Cfg3XKv_xgc4V z7|?o^&8WKz>fVv&ZUlfm$E2n51W?_hQK^>!$CO6Q;@qM@KTJT ztJzJdTWJ2Br8MS($b|O&Z_0sfCE6L=%aBYrWdKoxcDTpBe`@ zEdaWYjN_W?G#J0}!*l(VUCFNL+(KfK73u9ly@`eOeM0PIHlyF6jn+{8WY>i%j?0#GMhwVoaaauf%Gj7L_qAYGF?nPPQq!oZ4p8r8MWx7pj$d{?rtKN*j6pgopK)1FAitxjja?^#J9;tO~v{oh1#g}iPz`6z!y bg?w9T1LPtVtI_H7c(dnOu?s_y-gSQg+1xmI diff --git a/translations/pencil_it.qm b/translations/pencil_it.qm index 996d08b755062e79fce896f784839c9f356b7580..5de283bc2b4efdf2432967920599abe0c9306fb3 100644 GIT binary patch delta 795 zcmXYvTS!zv9LB#hXV2N)<0aa>poploo4C4~=4x7&nzwaz-Bs7?CUh~7f=HCGEEI}- z(3HvEx{#TQtfHnFQK4vF9tt8MDlI`#u+5;Nn`jfKrytA=-+cey%)%@;GR3ue1!n?# zJOSy8%z~YOX#xnD2h4|o+{m`r7Gj=jn@mc`eFPzW5)iXxhK@lne*?lz5bS9{4iBO7 zDG*Tx;cOESl`k`Ql^)=9Hp@7KiGCnag79*Ru^o|zR)CTfh?nndRr@=r5>tdRvPGXFrG-eL$FldtC5= znF-=tt|h=nN8=$`K9E!_AZlKK^A5Ro3M-5oMD1J zcJSJ1KcKLk58tY0x5x2O$!cKR7H>{wB0Zz{^BXNdW)EL~g|*myhrby38rWXUJI~pG ztR~+1XAW?yz543ZWYm zC@|4_MQut}s<6D22jn#f8!;>U9?RfWig5Lrcg_)W7JzT_?vGj2L>X6xKZWe)+<0CBh%(X9pa7X zoDucxZ3D~hQm>2*F}_i6uCqHmJ0-!&m~mh7dfNdMl}q~Q7feL})hdm|6hj?Kou=5! z?UWB2sHn%Sp>Z$!rDe2TX(xp)>QWk|5+C=`zDBkiNF!89q`01*Rv9Hzi^shmznJuc g)TuHMdlsEnr4w5X)v8lTY0glUx+i03$kwa*3(ytZsQ>@~ delta 1157 zcmZuve{54#6#m|QeXm`|Fq92~Vaqns+I3r3nN(!bz;JzO*Oj-f?YcHfR&ARtjx>%D zgVD(X1VR{+3&!vlabh55knv-Ip!{+O_=hCwVj>C}A%fV11dY)R=jm=y{_x%0``vTy zIp6v2J#YN7bmMdBozf~DczP~izArHHDd3*~s=o&UF92(=?O8U=f&+Ulc~Jw02+X1*b1nS%QO34;#PePeE3N)FaT)RxT4-Kn+ z1`<2r(l-I&2`s-uQYts&`P$!s=Ux`rQYA1lEHJvbfba2>lAFc0@SJ30p@+PT*&O<5 z#1HKS+Fgi$atv7WD-!8OB0DUwWu3rSD^D?7b?77X)(+7%_hW0dhr)iqp#~?g$bvDA zv;=zjD043jXQYvPM*zo*(wXp0pzXYr%iRJN*x2%;uK)|rv7x#Fz-nW=udV<(>Uo*$ z91Q=(KC`}0kGqcDxXOTtCR?&gfRg#L^~xfkbD3N>(@zigjqF-o1UxY#2UgQV&UMLe zOb=5deDa&yNX1hJBSkoXC=uAuGS{CF}8h>R)RE zWu$3{IAMu>l323^f1W#y8Z^<+5rkH#GWe*BIP%k>Rw(~}B}G)2BztKHnU9xzBu2zF zqmB4Pln^8Q+HC%;e{lBJq|5~RRGM%5`nofz{z|*UnO&c$bU1snVol{?Lr*#_fYxMR zmex#9x~8c~4{C)JGW@zm>Hj5?E9~=n$w&DG7V>GR1)G-PPL{CS@2_>_Le@(<6W BAAtY> diff --git a/translations/pencil_ja.qm b/translations/pencil_ja.qm index 29816b04418719bf74a0a1fb7a540008602be273..ffe6755b5a96518f7e3a4e32be5e7537eab913c6 100644 GIT binary patch delta 889 zcmXYvSx8iI7{$-MckZ3JcW#r6re$S0GE=EdlbP9+wvJ2Ao-9x5`0ijtrxAGDy2P^&Mdr{BZJ_nrSa=YQle_qmfh5i@NM zFw+3&gb00if!xV}ssomVfuwbSb16{Jbuz2h?%WSCrvuQGMmRMFqVpS&d>CTTK^yxZ zmfZ(ZRzci(2$Rv@kfw{l4{--bKac9P+GE;>XZMD=nGVJ=X3k-ed7-X&an zVIMh+Wn%;j@A0rKAt%in<~z*|fc7l^_7P78h6LmGBtUKvOkbzb@_=CO8b@3ur2eU( z?VGGsuo(SW!mjvI(l84(!^eP}ZZ;q!#OEFoZVdHM7aN4v6&rvluQbwx0QJ$w%$h{z z)?6^U>|&BC0&}j5Q->Mg>tiFDs>Qka;)nNMzflKfrk=*)69QL5rSwd{=K<~?EdL3*;x z-!GqA5Jh>0U!(xXcFG@bHxq~C-=9fKd7+3tq9av_d36~GwkRoSPsrp} zCH44LATN%MXcKrR*hF0dpSOc$=`8WS68+}$yTAw*c^~mal zwU21tq27|-lFAqL?#((<+0D#y4qtSHmCIHoUo+~;&tFtlG`lKiBnKWC%G%m!$!4e= zTn~&ZH(aW(1jct7y2~4Z=ww58GtC24OjI(AUU9T_um{KY}enjzp delta 1238 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 Xyu9t(w;>@or2TvQW_epmE6o1^T`A4O diff --git a/translations/pencil_pt_BR.qm b/translations/pencil_pt_BR.qm index e7b81338a984f00af6863a9c884a6e5840f7d517..bde27bc13445ca104e511f046bfe0df178e3154f 100644 GIT binary patch delta 6098 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 Ptals#g~J8L&hEbe(8DzN delta 5010 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 M=5v-?Q^wl*f6EOk;{X5v diff --git a/translations/pencil_ru.qm b/translations/pencil_ru.qm index 2d26dba29f37d366eb0c0a61cd8a265cb937bc7b..8eb7454d84b1cb7b24455eb34922d42b43aabbaf 100644 GIT binary patch delta 1664 zcmXApc~DbV6vn^2|b#jjQzz zi~+_-fcIWE%liS-hXMl^0I{cli6Rg;6)5_uE@F?iumh@V)c{*t*A+R@X#zj34bWNK zjEV#w_X?OY3;bLQu$BX#ejJ#Z27c8B^83h5r8jYwsYr^Z;N;#KPxa0`qik z<|kp{+a|!c(ari4q|TWGOp0`~cmOj0f3?VltjaLJDx>ft6;Rt3%BWp;T_p^e zL&t?IfR8k-zO9-r#sb0&H_NW8vX3mgK0fCj3HTS@n!19N z^O}_lYZl}m;_tsV63B4y_d90;oQIq1X7b&C(e)~c?+IN-T@Mo!Dhg(5u%P^(TcQPz zJEWT6Y@uKAc&aFb{-a49L-K{8i~Q*M=WLF8uHULrLi`Vu%eVt>x_%Pk&)b2)c|zjZ zRA8NsT~JRORM#OCjUl<4nBZD|07%~&^b4wGyjPe{HYtl9zCto=l$I(YXMW?2? zh9axFs@ZbvGBu@-rX`7-7Wp%~R`$%^sT~<|5y)%OhIf;&Hnp&3t&uCMViyQ`7WPyt za|J5qqcd|wH<(2yn^s2XcHKxJEuGNq-AhT0D%KtCAdT5}>sph&sli>kv(Zz44d+>d z&TOjbFAi&=5*fPP9Dh^vn{*SXyebCBZ|VA8F?b3smfR%vRA+RpKPOg?e@55!;?|UQ z^5PVmf(n7`N#fx>B{W9c#1nyLz~U5J3n|a355+6r(eF7G;x#X_qg}k+ssv(E+_bid zofGIk_C)-1Q5P`7CcfssB{^yI(zp;HEJYs`MRJVG(noF22HPkO<8n^3W>NMlXw>iQ zenYG4y#CbLa9Rj8`b&fCzi z!23%8akX?gi}u#=cBCbdSRu`2INUyZ%%@JqVLO9?_$k*V{FM%!{`sFXtm5R z`6(5_>tn;*9tns~Ff5LykXD2k7N4vl{k0nwU!-EqjWwhkrI0iJFr=IrNM|qNd{UZ` m`A9Oi;x>zrjE3CL41Wt@fOA_0&5?b7rgSf3|I31%rvCt$BIH1-_qZ zf&H(cMgIwKUoCnPY%sz$7q8eU-M&Va$y>tq88kEcUI$DenoRx?phIAO-WIuYo#x=p zBfv7Z=H9R~uxvgnU!O6~Q!0p*tMHTuA_m3k6H(3}D|CVg5Y^v|eXr zx+u>3Ec5HOCT}kj##Y1~*?dy6Wm$VoblmV9O;==dq@ z{+Pw`XP0m$3+gg>!pYs-czJ zNs$<;le-HH;cFs*hu$~jRnm24S`3c%)5P_F!F%!su)E#R*g=s6eTJ@67XkLFp|6-o z>qnSNv=n)A#Ms1lsjm6r(g|vpjuO$a^$@l2X>mirFtETXwtc-45ZY91T_|?COMsG@ z;%|Sx0$A~m_`%05!0Mgi-`_Ek+na1mv~W9q$wG}bE>O=>jTWoxy78saa`Ndg9z9BF zh-);Syg$&_-127^yBTfQRm zqf)|h8Zb3qN*V9Dsk_>w`~{;xyis!eZVm9bUh*zZ0@^%MaLH}r36-8JA0hgAQct`O za9@>PKhi|0$dKNQu>qO&(twXrmhp*n>DO)GQ4_~frKqs(PU)k^#(`|N^bg@UO{zZT zlD^N?Y+{Ebi^-Q7`r^bF)K@j3gTqT{2y}#=_b#T-v^ezIXN1+SvRjfRuw%76dpFfq z`=)Fwb&z_VoY3X^VW(MYHOAdGf_$#Ir9b-zlZKn``CqFU}xJ?MtM17_ zUZJvn83n#+R9Sy!4`suxtbdoXw<<>|KS>vRqE#tBJB#EQglkA1R2+NE?0(sl;A&R- zH*^5=4k)jUj*$sd&MqRCaf!+wq9cIXbmenh63~!Q1w1wTScQDON~;mIGueJ~cmUCu z4=Zf&pc<7VO|3VQ^zF6dKhhRd!AXy5r%LL&0xmkGt}DN>ia`oJ1;~f}f4rzWIkXqB zPrLtrE>*K)WFw0nHOz0j{C6;_T{`lJP_jw#qu<#eh*?+TZP-j!9(n3R-)eEakf5^@Ucbo{>uNmZPkl|?!_ cKg~kA^t=L65eu#D*;CuZrHMI~k diff --git a/translations/pencil_sl.qm b/translations/pencil_sl.qm index 591256608ec4c50295540fcbc745c7518c7e85c3..627c9001137a06e05e46efce135049ea21a40068 100644 GIT binary patch delta 3671 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 Xkf}bEa>It?PwG7*Eq_$$orV7ev(~1? delta 3929 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 From b75e283dcde605a281c938e4def8f7cf7ff86984 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Tue, 24 Jul 2018 07:43:44 +0800 Subject: [PATCH 140/184] Typo --- app/ui/mainwindow2.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/ui/mainwindow2.ui b/app/ui/mainwindow2.ui index 94dc48b72..af3efc5b3 100644 --- a/app/ui/mainwindow2.ui +++ b/app/ui/mainwindow2.ui @@ -256,7 +256,7 @@ :/icons/saveas.png:/icons/saveas.png - Save As .. + Save As... From 5279f7d3d938747583f0f51fe92b89032b7e8b88 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Thu, 26 Jul 2018 20:33:00 +1000 Subject: [PATCH 141/184] Translation update - Add a new translation Chinese China --- app/src/preferencesdialog.cpp | 1 + pencil2d.pro | 1 + translations/pencil.ts | 10 +- translations/pencil_cs.qm | Bin 53631 -> 54498 bytes translations/pencil_cs.ts | 1037 ++++---- translations/pencil_da.qm | Bin 13881 -> 13127 bytes translations/pencil_da.ts | 933 +++++--- translations/pencil_de.qm | Bin 63041 -> 62091 bytes translations/pencil_de.ts | 937 +++++--- translations/pencil_es.qm | Bin 75816 -> 87260 bytes translations/pencil_es.ts | 960 +++++--- translations/pencil_et.qm | Bin 36678 -> 35851 bytes translations/pencil_et.ts | 935 +++++--- translations/pencil_fr.qm | Bin 77562 -> 76003 bytes translations/pencil_fr.ts | 941 +++++--- translations/pencil_he.qm | Bin 43670 -> 42770 bytes translations/pencil_he.ts | 937 +++++--- translations/pencil_hu_HU.qm | Bin 29195 -> 28321 bytes translations/pencil_hu_HU.ts | 935 +++++--- translations/pencil_id.qm | Bin 10944 -> 10498 bytes translations/pencil_id.ts | 929 +++++--- translations/pencil_it.qm | Bin 25526 -> 24764 bytes translations/pencil_it.ts | 933 +++++--- translations/pencil_ja.qm | Bin 25455 -> 24814 bytes translations/pencil_ja.ts | 933 +++++--- translations/pencil_pl.qm | Bin 77698 -> 76167 bytes translations/pencil_pl.ts | 941 +++++--- translations/pencil_pt.qm | Bin 75880 -> 80767 bytes translations/pencil_pt.ts | 975 +++++--- translations/pencil_pt_BR.qm | Bin 77388 -> 81177 bytes translations/pencil_pt_BR.ts | 941 +++++--- translations/pencil_ru.qm | Bin 41705 -> 40715 bytes translations/pencil_ru.ts | 938 +++++--- translations/pencil_sl.qm | Bin 73600 -> 72416 bytes translations/pencil_sl.ts | 939 +++++--- translations/pencil_vi.qm | Bin 60858 -> 59822 bytes translations/pencil_vi.ts | 937 +++++--- translations/pencil_zh_CN.qm | Bin 0 -> 60141 bytes translations/pencil_zh_CN.ts | 4222 +++++++++++++++++++++++++++++++++ translations/pencil_zh_TW.qm | Bin 27452 -> 26462 bytes translations/pencil_zh_TW.ts | 939 +++++--- translations/translations.qrc | 1 + 42 files changed, 14675 insertions(+), 6580 deletions(-) create mode 100644 translations/pencil_zh_CN.qm create mode 100644 translations/pencil_zh_CN.ts diff --git a/app/src/preferencesdialog.cpp b/app/src/preferencesdialog.cpp index 9c4e068bc..c5cd972f3 100644 --- a/app/src/preferencesdialog.cpp +++ b/app/src/preferencesdialog.cpp @@ -112,6 +112,7 @@ GeneralPage::GeneralPage(QWidget* parent) : ui->languageCombo->addItem(tr("Russian") + " (Russian)", "ru"); ui->languageCombo->addItem(tr("Slovenian") + " (Slovenian)", "sl"); ui->languageCombo->addItem(tr("Vietnamese") + " (Vietnamese)", "vi"); + ui->languageCombo->addItem(tr("Chinese - China") + " (Chinese - China)", "zh_CN"); ui->languageCombo->addItem(tr("Chinese - Taiwan") + " (Chinese - Taiwan)", "zh_TW"); int value = settings.value("windowOpacity").toInt(); diff --git a/pencil2d.pro b/pencil2d.pro index 40ef49ca6..d1c98ab11 100644 --- a/pencil2d.pro +++ b/pencil2d.pro @@ -39,4 +39,5 @@ TRANSLATIONS += translations/pencil.ts \ translations/pencil_ru.ts \ translations/pencil_sl.ts \ translations/pencil_vi.ts \ + translations/pencil_zh_CN.ts \ translations/pencil_zh_TW.ts diff --git a/translations/pencil.ts b/translations/pencil.ts index 376e6519f..df010f3d0 100644 --- a/translations/pencil.ts +++ b/translations/pencil.ts @@ -1244,11 +1244,6 @@ Save - - - Save As .. - - Exit @@ -1583,6 +1578,11 @@ Next KeyFrame + + + Save As... + + diff --git a/translations/pencil_cs.qm b/translations/pencil_cs.qm index f9bb71703a41c6d859ea315bcf575a48c04731b5..c62964a05e88df29daa259c65421e97d85be1390 100644 GIT binary patch delta 5409 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 Hx6A(lW0M5= diff --git a/translations/pencil_cs.ts b/translations/pencil_cs.ts index bb92d64ca..2d88b604f 100644 --- a/translations/pencil_cs.ts +++ b/translations/pencil_cs.ts @@ -13,13 +13,13 @@ Stránky: <a href="https://www.pencil2d.org">pencil2d.org</a><br>Developed by: <b>Pascal Naidon, Patrick Corrieri, Matt Chang</b><br>Poděkování Qt Framework <a href="https://www.qt.io/download">https://www.qt.io/</a><br>miniz: <a href="https://github.com/richgel999/miniz">https://github.com/richgel999/miniz</a><br>Šířeno pod <a href="http://www.gnu.org/licenses/gpl-2.0.html">GNU General Public License, verze 2</a> - + Version: %1 Version Number in About Dialog Verze: %1 - + Copy to clipboard Copy system info from About Dialog Kopírovat do schránky @@ -55,30 +55,30 @@ Zvuková vrstva - + Exporting movie Vyvádí se obrazový záznam... - + Finished. Open movie now? When movie export done. Dokončeno. Otevřít záznam nyní? - - - - + + + + Layer Properties Vlastnosti vrstvy - - - - + + + + Layer name: Název vrstvy: @@ -88,58 +88,63 @@ Zvukový klip již v tomto snímku existuje! Vyberte, prosím, jiný klip nebo vrstvu. - + + Finished. Open file location? + + + + Exporting image sequence... Vyvádí se řada obrázků... - + Abort Zrušit - + Warning Varování - + Unable to export image. Obrázek nelze vyvést. - + Bitmap Layer Bitmapová vrstva - + Vector Layer Vektorová vrstva - + Camera Layer Kamerová vrstva - + Sound Layer Zvuková vrstva - + Delete Layer Windows title of Delete current layer pop-up. Smazat vrstvu - + Are you sure you want to delete layer: Opravdu chcete smazat vrstvu: - + Please keep at least one camera layer in project text when failed to delete camera layer Ponechejte, prosím, v projektu alespoň jednu vrstvu s kamerou @@ -148,57 +153,57 @@ BaseTool - + Pencil Tužka - + Eraser Guma - + Select Výběr - + Move Posun - + Hand Ruka - + Smudge Šmouha - + Pen Pero - + Polyline Lomená čára - + Bucket Kbelík - + Eyedropper Kapátko - + Brush Štětec @@ -224,69 +229,55 @@ ColorBox - - Color Wheel - Color Wheel's window title - Kolo barev + + Color Box + Color Box window title + ColorInspector - + HSV HSV - + RGB RGB - - - Red - Červená - - - - - Green - Zelená - - - - - Blue - Modrá + + R + - - - - Alpha - Alfa kanál + + A + - - Hue - Odstín + + G + - - Saturation - Nasycení + + B + - - Value - Hodnota + + Color Inspector + Window title of color inspector + ColorPalette - + Color Palette Window title of color palette. Paleta barev @@ -302,57 +293,57 @@ Odebrat barvu - - ... - ... + + Native color dialog window + - + List Mode Režim seznamu - + Show palette as a list Ukázat paletu jako seznam - + Grid Mode Režim mřížky - + Show palette as icons Ukázat paletu jako ikony - + Small swatch Malý vzorek barvy - + Sets swatch size to: 16x16px Nastaví velikost vzorku barvy na: 16 x 16 obrazových bodů (px) - + Medium Swatch Střední vzorek barvy - + Sets swatch size to: 26x26px Nastaví velikost vzorku barvy na: 26 x 26 obrazových bodů (px) - + Large Swatch Velký vzorek barvy - + Sets swatch size to: 36x36px Nastaví velikost vzorku barvy na: 36 x 36 obrazových bodů (px) @@ -360,11 +351,60 @@ ColorPaletteWidget - - + + Add + + + + + Replace + + + + + Remove + + + + + Colour name Název barvy + + + The color(s) you are about to delete are currently being used by one or multiple strokes. + + + + + Cancel + + + + + Delete + + + + + Palette Restriction + + + + + The palette requires at least one swatch to remain functional + + + + + ColorWheel + + + Color Wheel + Color Wheel's window title + + DisplayOption @@ -446,19 +486,19 @@ Editor - - + + Paste Vložit - + Remove frame Odstranit snímek - - + + Import Image Zavést obrázek @@ -484,12 +524,12 @@ ExportImageDialog - + Export image sequence Vyvést řadu obrázků - + Export image Vyvést obrázek @@ -531,11 +571,51 @@ Transparency Průhlednost + + + Range + + + + + The last frame you want to include in the exported movie + + + + + End Frame + + + + + The first frame you want to include in the exported movie + + + + + Start Frame + + + + + <html><head/><body><p>End frame is set to last paintable keyframe (Useful when you only want to export to the last animated frame)</p></body></html> + + + + + To the end of sound clips + + ExportMovieDialog - + + Export Animated GIF + + + + Export Movie Vyvést film @@ -627,67 +707,83 @@ + Import Animated GIF + + + + Import movie Zavést film - + Import sound Zavést zvuk - + Import palette Zavést paletu - + Save animation Uložit animaci - + Export image Vyvést obrázek - + Export image sequence Vyvést řadu obrázků - + + Export Animated GIF + + + + Export movie Vyvést film - + Export sound Vyvést zvuk - + Export palette Vyvést paletu - + + + Animated GIF (*.gif) + + + + Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) Zvuky (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) - - - Palette (*.xml) - Paleta (*.xml) + + + Pencil2D Palette (*.xml);; Gimp Palette (*.gpl) + - - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) + + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng) + - + MyAnimation.pclx Moje animace.pclx @@ -695,52 +791,72 @@ FileManager - - - + + + Could not open file + + + + + The file does not exist, so we are unable to open it. Please check to make sure the path is correct and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + Invalid Save Path Neplatná ukládací cesta - + The path ("%1") points to a directory. Cesta ("%1") ukazuje na adresář. - + The directory ("%1") does not exist. Adresář ("%1") neexistuje. - + The path ("%1") is not writable. Cesta ("%1") není zapisovatelná. - - + + Cannot Create Data Directory Nelze vytvořit adresář s daty - + Failed to create directory "%1". Please make sure you have sufficient permissions. Nepodařilo se vytvořit adresář "%1". Ujistěte se, prosím, že máte dostatečná oprávnění. - + "%1" is a file. Please delete the file and try again. "%1" je soubor. Smažte, prosím, soubor a zkuste to znovu. - - + + Miniz Error + + + + Internal Error Vnitřní chyba - - + + An internal error occurred. Your file may not be saved successfully. Vyskytla se vnitřní chyba. Soubor se nemuselo podařit uložit úspěšně. @@ -818,87 +934,97 @@ Mřížka - + Czech Čeština - + Danish Dánština - + English Angličtina - + German Němčina - + + Estonian + + + + Spanish Španělština - + French Francoužština - + Hebrew Hebrejština - + Hungarian Maďarština - + Indonesian Indonésština - + Italian Italština - + Japanese Japonština - + + Polish + + + + Portuguese - Portugal Portugalština (Portugalsko) - + Portuguese - Brazil Portugalština (Brazílie) - + Russian Ruština - + Slovenian Slovinština - + Vietnamese Větnamština - + Chinese - Taiwan Čínština (Tchaj-wan) @@ -943,12 +1069,12 @@ Místo vysokého rozlišení tabletu - + Restart Required Požadováno opětovné spuštění - + The language change will take effect after a restart of Pencil2D Změna jazyka se projeví po znovuspuštění Pencil2D @@ -974,7 +1100,12 @@ ImportImageSeqDialog - + + Import Animated GIF + + + + Import image sequence Zavést řadu obrázků @@ -998,7 +1129,7 @@ LayerBitmap - + Bitmap Layer Bitmapová vrstva @@ -1014,7 +1145,7 @@ LayerSound - + Sound Layer Zvuková vrstva @@ -1045,473 +1176,484 @@ Zavést - + Export Vyvést - + Edit Úpravy - + Selection Výběr - + View Pohled - + Onion Skin Cibulová slupka - + Animation Animace - - + + Tools Nástroje - + Layer Vrstva - - + + Help Nápověda - + Windows Okno - + New Nový - + Open Otevřít - + Save Uložit - + Save As .. Uložit jako... - + Exit Ukončit - - + + Image Sequence... Řada obrázků... - - + + Image... Obrázek... - - + + Movie... Film... - - + + Palette... Paleta... - + Sound... Zvuk... - + Undo Zpět - + Redo Znovu - + Cut Vyjmout - + Copy Kopírovat - + Paste Vložit - + Crop Oříznout - + Crop To Selection Oříznout k výběru - + Select All Vybrat vše - + Deselect All Zrušit výběr všeho - - + + Clear Frame Vyčistit snímek - + Preferences Nastavení - + Reset Windows Vrátit okna na výchozí - + Zoom In Přiblížit - + Zoom Out Oddálit - + Rotate Clockwise Otočit po směru hodinových ručiček - + Rotate AntiClosewise Otočit proti směru hodinových ručiček - + Reset Zoom/Rotate Vrátit na výchozí zvětšení/otočení - + Horizontal Flip Vodorovné převrácení - + Vertical Flip Svislé převrácení - + Preview Náhled - + Grid Mřížka - + Previous Předchozí - + Show previous onion skin Zobrazit předchozí cibulovou slupku - + Next Další - + Show next onion skin Zobrazit následující cibulovou slupku - - + + Play Přehrát - + Loop Smyčka - + Next Frame Další snímek - + Previous Frame Předchozí snímek - + Extend Frame Rozšířit snímek - + Add Frame Přidat snímek - + Duplicate Frame Zdvojit snímek - + Remove Frame Odstranit snímek - + Move Posun - + Select Výběr - + Brush Štětec - + Polyline Lomená čára - + Smudge Šmouha - + Pen Pero - + Hand Ruka - + Pencil Tužka - + Bucket Kbelík - + Eyedropper Kapátko - + Eraser Guma - + New Bitmap Layer Nová bitmapová vrstva - + New Vector Layer Nová vektorová vrstva - + New Sound Layer Nová zvuková vrstva - + New Camera Layer Nová kamerová vrstva - + Delete Current Layer Smazat nynější vrstvu - + About O programu - - + + Reset to default Vrátit na výchozí - + MultiLayer Onion Skin Vícevrstvý cibulový vzhled - + Range Rozsah - + Pencil2D Website Stránka Pencil2D - + Report a Bug Nahlásit chybu - + Quick Reference Guide Rychlý odborný průvodce - + F1 F1 - - + + + Animated GIF... + + + + + Next KeyFrame Další klíčový snímek - - + + Previous KeyFrame Předchozí klíčový snímek - + Timeline Časová osa - + Options Možnosti - + Color Wheel Kolo barev - + Color Palette Paleta barev - + Display Options Nastavení zobrazení - + Flip X Převrátit X - + Flip Y Převrátit Y - + Move Frame Forward Posunout snímek vpřed - + Move Frame Backward Posunout snímek vzad - + color palette:<br>use <b>(C)</b><br>toggle at cursor Paleta barev:<br>použijte přepínač <b>(C)</b><br>na pozici kurzoru - + + Color inspector + + + + Lock Windows Zamknout okna - + Open Recent Otevřít nedávné - + You have successfully cleared the list @@ -1520,369 +1662,417 @@ Úspěšně jste vyprázdnil seznam - - - - - + + + + + Could not open file + + + + + The file you have selected is a directory, so we are unable to open it. If you are are trying to open a project that uses the old structure, please open the file ending with .pcl, not the data folder. + + + + + The file you have selected does not exist, so we are unable to open it. Please check to make sure that you've entered the correct path and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + + + Warning Varování - - - Pencil cannot read this file. If you want to import images, use the command import. - Pencil není schopen přečíst tento soubor. Pokud chcete zavést obrázky, použijte příkaz Zavést. + + This program does not currently have permission to write to the file you have selected. Please make sure you have write permission for this file before attempting to save it. Alternatively, you can use the Save As... menu option to save to a writable location. + - + Opening document... Otevírám dokument... - - - + + + + Abort Zrušit - + + An unknown error occurred while trying to load the file and we are not able to load your file. + + + + Saving document... Ukládám dokument... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>Vyskytla se chyba, a tak soubor nemusí být úspěšně uložen. Pokud si myslíte, že potíže souvisí s Pencil2D, vytvořte, prosím, nové téma na:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Ujistěte se, prosím, že do záznamu o problému zahrnete následující podrobnosti: - + This animation has been modified. Do you want to save your changes? Tato animace byla změněna. Přejete si uložit změny? - + The animation is not saved yet. Do you want to save now? Animace ještě není uložena. Chcete ji uložit nyní? - + Never ask again AutoSave reminder button Už se znovu neptat - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Obrázek nelze zavést.<br><b>Rada:</b> K zavedení bitmap použijte bitmapovou vrstvu. - + Importing image sequence... Zavádí se řada obrázků... - + + was unable to import nebylo možno zavést - - + + Importing Animated GIF... + + + + + Undo Menu item text Zpět - + Redo Menu item text Znovu - + Stop Zastavit + + MoveTool + + + Layer switch + Windows title of layer switch pop-up. + + + + + You are about to switch layer, do you want to apply the transformation? + + + Object - + Black Černá - + Red Červená - + Dark Red - Tmavě červená + Tmavá červená - + Orange Oranžová - + Dark Orange - Tmavě oranžová + Tmavá oranžová - + Yellow Žlutá - + Dark Yellow - Tmavě žlutá + Tmavá žlutá - + Green Zelená - + Dark Green - Tmavě zelená + Tmavá zelená - + Cyan Tyrkysová - + Dark Cyan - Tmavě tyrkysová + Tmavá tyrkysová - + Blue Modrá - + Dark Blue - Tmavě modrá + Tmavá modrá - + White Bílá - + Very Light Grey - Velmi světle šedá + Velmi světlá šedá - + Light Grey - Světle šedá + Světlá šedá - + Grey Šedá - + Dark Grey - Tmavě šedá + Tmavá šedá - + Light Skin - Světle tělová + Světlá tělová - + Light Skin - shade - Světle tělová - odstín + Světlá tělová - odstín - + Skin Tělová - + Skin - shade Tělová - odstín - + Dark Skin Tmavá tělová - + Dark Skin - shade - Tmavě tělová - odstín + Tmavá tělová - odstín PencilApplication - + Pencil2D is an animation/drawing software for Mac OS X, Windows, and Linux. It lets you create traditional hand-drawn animation (cartoon) using both bitmap and vector graphics. Pencil2D je animační/kreslicí program pro operační systémy Mac OS X, Windows a Linux. Dovolí vám tvořit tradiční ručně kreslenou animaci pomocí bitmapové i vektorové grafiky - + Path to the input pencil file. Cesta k výstupnímu souboru Pencilu. - - + + Render the file to <output_path> Zpracovat soubor do <output_path> - - + + output_path výstupní_cesta - + Name of the camera layer to use Název vrstvy s kamerou, která se má použít - + layer_name název_vrstvy - + Width of the output frames Šířka výstupních snímků - - + + integer Celé číslo - + Height of the output frames Výška výstupních snímků - + The first frame you want to include in the exported movie První snímek, který chcete zahrnout do vyvedeného filmu - - + + frame snímek - + The last frame you want to include in the exported movie. Can also be last or last-sound to automatically use the last frame containing animation or sound, respectively Poslední snímek, který chcete zahrnout do vyvedeného obrazového záznamu. Také může být poslední nebo poslední-zvuk pro automatické použití posledního snímku obsahujícího animaci nebo zvuk, v tomto pořadí - + Render transparency when possible Vykreslovat průhlednost, když je to možné - + Warning: width value %1 is not an integer, ignoring. Varování: Hodnota pro šířku %1 není celé číslo. Přehlíží se. - + Warning: height value %1 is not an integer, ignoring. Varování: Hodnota pro výšku %1 není celé číslo. Přehlíží se. - + Warning: start value %1 is not an integer, ignoring. Varování: Začáteční hodnota %1 není celé číslo. Přehlíží se. - + Warning: start value must be at least 1, ignoring. Varování: Začáteční hodnota musí být alespoň %1. Přehlíží se. - + Warning: end value %1 is not an integer, last or last-sound, ignoring. Varování: Koncová hodnota %1 není celé číslo, poslední nebo poslední-zvuk. Přehlíží se. - + Warning: end value %1 is smaller than start value %2, ignoring. Varování: Koncová hodnota %1 je menší než začáteční %2. Přehlíží se. - + Error: No input file specified. Chyba: Nestanoven vstupní soubor. - + Error: the input file at '%1' does not exist Command line error Chyba: Vstupní soubor v '%1' neexistuje - + Error: the input path '%1' is not a file Command line error Chyba: Vstupní cesta '%1' není soubor - + Warning: the specified camera layer %1 was not found, ignoring. Varování: Daná kamerová vrstva %1 nebyla nalezena. Přehlíží se. - + Warning: Output format is not specified or unsupported. Using PNG. Command line warning Varování: Výstupní formát není stanoven nebo není podporován. Používá se PNG. - + Warning: Transparency is not currently supported in movie files Command line warning Varování: Průhlednost není v současnosti v souborech s obrazovým záznamem podporována. - + Exporting movie... Command line task progress Vyvádí se obrazový záznam... - - + + Done. Command line task done Hotovo. - + Exporting image sequence... Command line task progress Vyvádí se řada obrázků... @@ -1924,12 +2114,12 @@ Chcete ji uložit nyní? QApplication - + Checking environment... Prověřuje se prostředí... - + Done Hotovo @@ -1937,42 +2127,47 @@ Chcete ji uložit nyní? QObject - + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) AVI(*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) - - Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) - Obrázky (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp) + + + + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp); + - + Everything ok. Vše v pořádku. - + Ooops, Something went wrong. Ouč, něco se pokazilo. - + File doesn't exist. Soubor neexistuje. - + Cannot open file. Soubor nelze otevřít. - + The file is not a valid xml document. Tento soubor není validní xml dokument - + The file is not valid pencil document. Tento soubor není validní dokument pencil. @@ -1999,12 +2194,12 @@ Chcete ji uložit nyní? Deep Pink - Tmavě růžová + Tmavá růžová Light Pink - Světle růžová + Světlá růžová @@ -2049,12 +2244,12 @@ Chcete ji uložit nyní? Deep Red - Tmavě červená + Tmavá červená Very Deep Red - Velice sytá červená + Velmi tmavá červená @@ -2064,17 +2259,17 @@ Chcete ji uložit nyní? Dark Red - Tmavě červená + Tmavá červená Very Dark Red - Velice tmavá červená + Velmi tmavá červená Light Grayish Red - Světle šedavá červená + Světlá šedavá červená @@ -2119,7 +2314,7 @@ Chcete ji uložit nyní? Deep Yellowish Pink - Sytá žlutavá růžová + Tmavá žlutavá růžová @@ -2159,12 +2354,12 @@ Chcete ji uložit nyní? Strong Reddish Orange - + Výrazná červenavá oranžová Deep Reddish Orange - + Tmavá červenavá oranžová @@ -2189,7 +2384,7 @@ Chcete ji uložit nyní? Deep Reddish Brown - + Tmavá červenavá hnědá @@ -2239,7 +2434,7 @@ Chcete ji uložit nyní? Deep Orange - + Tmavá oranžová @@ -2264,7 +2459,7 @@ Chcete ji uložit nyní? Deep Brown - + Tmavá hnědá @@ -2329,7 +2524,7 @@ Chcete ji uložit nyní? Deep Orange Yellow - + Tmavá oranžovožlutá @@ -2359,7 +2554,7 @@ Chcete ji uložit nyní? Deep Yellowish Brown - + Tmavá žlutavá hnědá @@ -2409,7 +2604,7 @@ Chcete ji uložit nyní? Deep Yellow - + Tmavá žlutá @@ -2484,7 +2679,7 @@ Chcete ji uložit nyní? Deep Greenish Yellow - + Tmavá šedavá žlutá @@ -2574,7 +2769,7 @@ Chcete ji uložit nyní? Deep Yellow Green - + Tmavá žlutozelená @@ -2604,7 +2799,7 @@ Chcete ji uložit nyní? Deep Olive Green - + Tmavá olivovězelená @@ -2644,12 +2839,12 @@ Chcete ji uložit nyní? Deep Yellowish Green - + Tmavá žlutavá zelená Very Deep Yellowish Green - + Velmi tmavá žlutavá zelená @@ -2694,7 +2889,7 @@ Chcete ji uložit nyní? Deep Green - + Tmavá zelená @@ -2789,7 +2984,7 @@ Chcete ji uložit nyní? Deep Bluish Green - + Tmavá modravá zelená @@ -2834,7 +3029,7 @@ Chcete ji uložit nyní? Deep Greenish Blue - + Tmavá zelenavá modrá @@ -2879,7 +3074,7 @@ Chcete ji uložit nyní? Deep Blue - + Tmavá modrá @@ -2969,7 +3164,7 @@ Chcete ji uložit nyní? Deep Purplish Blue - + Tmavá nafialovělá modrá @@ -3024,7 +3219,7 @@ Chcete ji uložit nyní? Deep Violet - + Tmavá fialová @@ -3079,12 +3274,12 @@ Chcete ji uložit nyní? Deep Purple - + Tmavá nachová Very Deep Purple - + Velmi tmavá nachová @@ -3174,12 +3369,12 @@ Chcete ji uložit nyní? Deep Reddish Purple - + Tmavá červenavá nachová Very Deep Reddish Purple - + Velmi tmavá červenavá nachová @@ -3224,7 +3419,7 @@ Chcete ji uložit nyní? Deep Purplish Pink - + Tmavá nafialovělá růžová @@ -3264,12 +3459,12 @@ Chcete ji uložit nyní? Deep Purplish Red - + Tmavá nafialovělá červená Very Deep Purplish Red - + Velmi tmavá nafialovělá červená @@ -3304,7 +3499,7 @@ Chcete ji uložit nyní? Light Gray - Světle šedá + Světlá šedá @@ -3314,13 +3509,23 @@ Chcete ji uložit nyní? Dark Gray - Tmavě šedá + Tmavá šedá Black Černá + + + Could not open file + + + + + There was an error processing your file. This usually means that your project has been at least partially corrupted. You can try again with a newer version of Pencil2D, or you can try to use a backup file if you have one. If you contact us through one of our offical channels we may be able to help you. For reporting issues, the best places to reach us are: + + RecentFileMenu @@ -3338,60 +3543,60 @@ Chcete ji uložit nyní? ScribbleArea - + Warning Varování - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Kreslíte na skrytou vrstvu! Vyberte, prosím, jinou vrstvu (nebo nynější vrstvu udělejte viditelnou). - + Delete Selection Undo Step: clear the selection area. Smazat výběr - - + + Clear Image Undo step text Smazat obrázek - + There is a gap in your drawing (or maybe you have zoomed too much). Ve vaší kresbě je mezera (nebo jste možná provedl moc velké přiblížení). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). - + Out of bound. Zakázáno. - + Could not find a closed path. Nepodařilo se najít zavřenou cestu. - + Could not find the root index. Nepodařilo se najít kořenový index. - + %1<br><br>Error: %2 %1<br><br>Chyba: %2 - + Flood fill error Chyba výplně @@ -3488,12 +3693,12 @@ Chcete ji uložit nyní? - + Start Začátek - + Stop Zastavit @@ -3577,18 +3782,18 @@ Chcete ji uložit nyní? Přepnout odpovídající klíčové snímky - + Delete Layer Windows title of Delete current layer pop-up. Smazat vrstvu - + Please keep at least one camera layer in project Ponechejte, prosím, v projektu alespoň jednu vrstvu s kamerou - + Are you sure you want to delete layer: Opravdu chete smazat vrstvu: @@ -3596,12 +3801,12 @@ Chcete ji uložit nyní? TimeLineCells - + Layer Properties Vlastnosti vrstvy - + Layer name: Název vrstvy: @@ -3678,6 +3883,16 @@ Chcete ji uložit nyní? <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + + Playback + + + + + Show onion skin while playing + + Frame size diff --git a/translations/pencil_da.qm b/translations/pencil_da.qm index fb420d1a5b101359e1e74bab263cc9d2a0b613a2..3c39240741d8fdf18bd4cbe6e5b4532793c38a6c 100644 GIT binary patch delta 1475 zcmXAodr(wW9LK-xo^$VI_wHQ;6agVv-tM9%`KTNR9a151w17!W(WVd`U!$Yhs9c9h zCREUYG)-&-m8l%XL_%>iC5#-+HN)4aJy6F7S(J~dWVG+j{p+)P?m55n{eFMHb7X#J z$)<2~6OhvZgj@u2vw*?HKwbr)rULn$z<{Yh;X(e-CyxX2V~dfkz*~oaq)#DgTL4ca zMB@jnGYH~~S!6CmQyJICLL3!9=tu~EfDI7mlYp=ah)Y#~nKl&SE-#ju7Q=3lr-8)H z7}IpGw~&9&J7Psm*EkEn+%d<{sO0a-%91G6EQR02_< z76-RMu5SXO%OJO&f{B<$$ogk=avZXQA70o4>8JC!IE=n)0LHf%<9*Eamn^0yVB!|0 zU<@NW$Z5z<*$%}2h3vYmfLLVFc!tUADIjqHrk^ENQ(RolsSI*i_L z`!0!v)ONe?`BFw$WnW#v3&XqZ*Otzq@_jC$i&t$|7i|(P~`${?&T^2)2g?~8>hhC7v4E*RHE7kf&I_!}Nx&#ukWZvSN z6x1tAKfK7+ERgfF``GIai;=&|4KLe(p#Nl@cQ>GTEXKYoceioBGSy=2S$Xg%2Q_h& zJTcwF{k!CifATpK%Pc0hNV6}4&XTK@Ai)_J=vM3jrq5L3ih00ySxLQF4%mAwx(+Mp zdK#c_Q!>3HDCnWZsPW3Av!@ujU&%>sXM$^#ypv4AC|8Q7bg@M}%AB3|*n&Tlm5QA$ zcPXo1TftUo@2lfxQ+UWKHSf$hw&1+F!T$-T{+PN~DFRX-slPoBoa?aYv#Z^?4kl&# z)%(qX3uak#tk*UpYgq4N>i5B6pj?$f#&vbi3jbzNl= zp1E4rZ3^)0&@T3ralIwDDW7%Ho&?|dn){s@j>>0maz>^(Y8Dmn`#s0CJ8Sv=lWsbV z3J)DWb*7h{U=o*|Sq+>4?ToX^{+JOxan>B+v`eSOu*uF{*L5Ja#(Cg?%1E1aZ2}|h zSEsv@SXh&Kd{YaDvrf;tw1^kp*XJzh=JSl#zeyXy=yUb(zw_dr; rX^(SvX7He6-ds-Nmgc{uPp#eS^3?_#zUHS!O=xXQl-AtlF~j}`o5Orp delta 2106 zcmZ`)Yj6|g8h+C3x4TU?N$nl5ur2gP+u)H=s)JgvQp!-QTq@ouq1m>PkaTk4h>S!* zP|%JJv7#0oF4|EXtx^yLMXXi4AO)>VIU)*LL5^@7l{4z#Qr9xzqRo(=TSz<%se1(w8+RJg9tp_U1F4^w zSq$k=A&_NfL;%=`FEhC6{3&d z3$BOgry>O(pz^d6NSltyW#@tX<0ek{2sMvV9oJ4`AMrS*UrrU364VxV0^>SSyYVqV z3MMed0IM+T0ZOW@HnBJdHypYhaI2X8P%n^u6bncjEcHy?~X;+$tMf2uS(Kg&(wvv?|!^<@!I(`;*b%ogK)fVHYr+~2wERTXxoKR^wd-iLi}D)R1?!?04dv~ zz#ARFm>p8*W=bYKX=2(A>AkhR+z*(TaaQVI%E~iu6jB1Sw+dx*7nSG`V>JO3o)dL# zUy;xgqV?WS*|Hqruf4z-=reJYAs)OU1+e@oHkLgN$OR&nT;w~&)4S;)-(X_?Qn7u{ zE}-ay*mp|-9kz@pJi(Zq|ti^SY`kaa`IFX&oj~a zhJ32+W7_>@qT8#ecd%8du?xx+51FT1l)4WOa@y}y9_-%$3 zO?1DYoSbQ+QvJ%Ao z4s5Aqt9GjcN2x@tFhd;}B7wph_0xZ^phIJ7_gn@l-;{dl6*_3I+SdL)hcj}MZGCVa z&*QewPOWC8?RMvy0=D28d&P=v<})+`j%bPP?$1nE8o)>oJXr zO}4-ElES!^nmWzO`=61oISLs#b)A;qy_3_KuT>ujGT|AmC3KQ4_)u%FJjd&`SbMY7 z%@!QidY7}pkymL)GPq}`&wJULydsBl5^s<54o6iLiRhA}YEytin(mk}_G%Wm%5nE< z63_e6v9>;kgnvjN@BjF0rNeM|!6EKHaP6N+Kl^`toXjdx#5P=q2z2LH*#oHs}wAY6Iam zqbU*$#k0rf$Iofm@j-3;NDZ?Pg$DsN!5DV6PLCRlSRIow8$ZMQzk}I^_isX45|o{& z!#5-yfRAs>u#atyClU>LBEDeY|GC=GK-Ul}^$oj;29JO0-xiR}rox?k^kE0d?RM*l z3|g|@dXL|TM2wzN$A~!DLOD+t5u<3~YB7RX!Y7f>%e4{zLd{yh{}}vB zv~Nzm5oq%H^(Ids5RB*{!{gN>t-i3{?DHFLy|!6j7L4lu^aLV$B&hqAv;{*Ef~Um@ fm+R56L1RO23NBgV33&fHcE>HbSv~v4+?VkusZ$88 diff --git a/translations/pencil_da.ts b/translations/pencil_da.ts index ce72e57ad..e5c9f0460 100644 --- a/translations/pencil_da.ts +++ b/translations/pencil_da.ts @@ -13,13 +13,13 @@ - + Version: %1 Version Number in About Dialog - + Copy to clipboard Copy system info from About Dialog @@ -55,30 +55,30 @@ - + Exporting movie - + Finished. Open movie now? When movie export done. - - - - + + + + Layer Properties Lag Præferencer - - - - + + + + Layer name: Lag navn: @@ -88,58 +88,63 @@ Et lydklip eksisterer allerede på dette frame! Vælg venligst et andet frame eller lag - + + Finished. Open file location? + + + + Exporting image sequence... - + Abort - + Warning - + Unable to export image. - + Bitmap Layer Bitmap Lag - + Vector Layer Vector Lag - + Camera Layer Kamera Lag - + Sound Layer Lyd Lag - + Delete Layer Windows title of Delete current layer pop-up. - + Are you sure you want to delete layer: - + Please keep at least one camera layer in project text when failed to delete camera layer @@ -148,57 +153,57 @@ BaseTool - + Pencil Blyant - + Eraser Viskelæder - + Select Marker - + Move Bevæg - + Hand Hånd - + Smudge Udtvær - + Pen Fyldepen - + Polyline Linje - + Bucket Malerspand - + Eyedropper Pipette - + Brush Pensel @@ -224,69 +229,55 @@ ColorBox - - Color Wheel - Color Wheel's window title + + Color Box + Color Box window title ColorInspector - + HSV HSV - + RGB RGB - - - Red - Rød - - - - - Green - Grøn - - - - - Blue - Blå + + R + - - - - Alpha - Alfa + + A + - - Hue - Nuance + + G + - - Saturation - Mætning + + B + - - Value - Værdi + + Color Inspector + Window title of color inspector + ColorPalette - + Color Palette Window title of color palette. @@ -302,57 +293,57 @@ Fjern Farve - - ... - ... + + Native color dialog window + - + List Mode - + Show palette as a list - + Grid Mode - + Show palette as icons - + Small swatch - + Sets swatch size to: 16x16px - + Medium Swatch - + Sets swatch size to: 26x26px - + Large Swatch - + Sets swatch size to: 36x36px @@ -360,11 +351,60 @@ ColorPaletteWidget - - + + Add + + + + + Replace + + + + + Remove + + + + + Colour name Farve navn + + + The color(s) you are about to delete are currently being used by one or multiple strokes. + + + + + Cancel + + + + + Delete + + + + + Palette Restriction + + + + + The palette requires at least one swatch to remain functional + + + + + ColorWheel + + + Color Wheel + Color Wheel's window title + + DisplayOption @@ -446,19 +486,19 @@ Editor - - + + Paste Indsæt - + Remove frame - - + + Import Image @@ -484,12 +524,12 @@ ExportImageDialog - + Export image sequence - + Export image @@ -531,11 +571,51 @@ Transparency + + + Range + + + + + The last frame you want to include in the exported movie + + + + + End Frame + + + + + The first frame you want to include in the exported movie + + + + + Start Frame + + + + + <html><head/><body><p>End frame is set to last paintable keyframe (Useful when you only want to export to the last animated frame)</p></body></html> + + + + + To the end of sound clips + + ExportMovieDialog - + + Export Animated GIF + + + + Export Movie @@ -627,67 +707,83 @@ - Import movie + Import Animated GIF - Import sound + Import movie + Import sound + + + + Import palette - + Save animation - + Export image - + Export image sequence - + + Export Animated GIF + + + + Export movie - + Export sound - + Export palette - + + + Animated GIF (*.gif) + + + + Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) - - - Palette (*.xml) + + + Pencil2D Palette (*.xml);; Gimp Palette (*.gpl) - - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) + + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng) - + MyAnimation.pclx @@ -695,52 +791,72 @@ FileManager - - - + + + Could not open file + + + + + The file does not exist, so we are unable to open it. Please check to make sure the path is correct and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + Invalid Save Path - + The path ("%1") points to a directory. - + The directory ("%1") does not exist. - + The path ("%1") is not writable. - - + + Cannot Create Data Directory - + Failed to create directory "%1". Please make sure you have sufficient permissions. - + "%1" is a file. Please delete the file and try again. - - + + Miniz Error + + + + Internal Error - - + + An internal error occurred. Your file may not be saved successfully. @@ -818,87 +934,97 @@ - + Czech - + Danish - + English - + German - + + Estonian + + + + Spanish - + French - + Hebrew - + Hungarian - + Indonesian - + Italian - + Japanese - + + Polish + + + + Portuguese - Portugal - + Portuguese - Brazil - + Russian - + Slovenian - + Vietnamese - + Chinese - Taiwan @@ -943,12 +1069,12 @@ Tegnebræts høj-opløsnings position - + Restart Required - + The language change will take effect after a restart of Pencil2D @@ -974,7 +1100,12 @@ ImportImageSeqDialog - + + Import Animated GIF + + + + Import image sequence @@ -998,7 +1129,7 @@ LayerBitmap - + Bitmap Layer Bitmap Lag @@ -1014,7 +1145,7 @@ LayerSound - + Sound Layer Lyd Lag @@ -1045,686 +1176,745 @@ Importer - + Export Exporter - + Edit Rediger - + Selection - + View Se - + Onion Skin løgskind - + Animation Animation - - + + Tools Værktøjer - + Layer Lag - - + + Help Hjælp - + Windows Vinduer - + New Ny - + Open Åben - + Save Gem - + Save As .. Gem Som .. - + Exit Afslut - - + + Image Sequence... Billede Sekvens... - - + + Image... Billede... - - + + Movie... Film... - - + + Palette... Palet... - + Sound... Lyd... - + Undo Fortryd - + Redo Gentag - + Cut Klip - + Copy Kopier - + Paste Indsæt - + Crop Beskær - + Crop To Selection Beskær til Markering - + Select All Vælg Alt - + Deselect All Fravælg Alt - - + + Clear Frame Ryd Ramme - + Preferences Præferencer - + Reset Windows Nulstil Vinduer - + Zoom In Zoom Ind - + Zoom Out Zoom Ud - + Rotate Clockwise Roter Med Uret - + Rotate AntiClosewise Roter Mod Uret - + Reset Zoom/Rotate Nulstil Zoom/Rotation - + Horizontal Flip Vend Horisontalt - + Vertical Flip Vend Vertikalt - + Preview Vis Eksempel - + Grid Gitter - + Previous Tidligere - + Show previous onion skin - + Next Næste - + Show next onion skin - - + + Play Afspil - + Loop Lykke - + Next Frame Næste Ramme - + Previous Frame Forrige Ramme - + Extend Frame Forlæng Ramme - + Add Frame Tilføj Ramme - + Duplicate Frame dupliker Ramme - + Remove Frame Fjern Ramme - + Move Flyt - + Select Vælg - + Brush Pencel - + Polyline Polylinje - + Smudge Udtværd - + Pen Pen - + Hand Hånd - + Pencil Blyant - + Bucket Spand - + Eyedropper Pipette - + Eraser Viskelæder - + New Bitmap Layer Nyt Bitmap Lag - + New Vector Layer Nyt Vector Lag - + New Sound Layer Nyt Lyd Lag - + New Camera Layer Nyt Kamera Lag - + Delete Current Layer Fjern Nuværende Lag - + About Om - - + + Reset to default Nulstil til standard indstillinger - + MultiLayer Onion Skin - + Range - + Pencil2D Website - + Report a Bug - + Quick Reference Guide - + F1 - - + + + Animated GIF... + + + + + Next KeyFrame - - + + Previous KeyFrame - + Timeline Tidslinje - + Options Instillinger - + Color Wheel Farvehjul - + Color Palette Farve Palet - + Display Options Vis instillinger - + Flip X - + Flip Y - + Move Frame Forward - + Move Frame Backward - + color palette:<br>use <b>(C)</b><br>toggle at cursor farve palet:<br>tryk på <b>(C)</b><br>Slå til/fra ved markøren - + + Color inspector + + + + Lock Windows - + Open Recent Åben Seneste - + You have successfully cleared the list - - - - - + + + + + Could not open file + + + + + The file you have selected is a directory, so we are unable to open it. If you are are trying to open a project that uses the old structure, please open the file ending with .pcl, not the data folder. + + + + + The file you have selected does not exist, so we are unable to open it. Please check to make sure that you've entered the correct path and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + + + Warning Advarsel - - - Pencil cannot read this file. If you want to import images, use the command import. - Pencil kan ikke læse denne fil. hvis du vil importere billeder, brug kommandoen importer. + + This program does not currently have permission to write to the file you have selected. Please make sure you have write permission for this file before attempting to save it. Alternatively, you can use the Save As... menu option to save to a writable location. + - + Opening document... Åbner dokument... - - - + + + + Abort Om - + + An unknown error occurred while trying to load the file and we are not able to load your file. + + + + Saving document... Gemmer dokument... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: - + This animation has been modified. Do you want to save your changes? - + The animation is not saved yet. Do you want to save now? - + Never ask again AutoSave reminder button - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. - + Importing image sequence... - + + was unable to import - - + + Importing Animated GIF... + + + + + Undo Menu item text - + Redo Menu item text - + Stop + + MoveTool + + + Layer switch + Windows title of layer switch pop-up. + + + + + You are about to switch layer, do you want to apply the transformation? + + + Object - + Black Sort - + Red Rød - + Dark Red Mørkerød - + Orange Orange - + Dark Orange Mørke Orange - + Yellow Gul - + Dark Yellow Mørkegul - + Green Grøn - + Dark Green Mørkegrøn - + Cyan Turkis - + Dark Cyan Mørke turkis - + Blue Blå - + Dark Blue Mørkeblå - + White Hvid - + Very Light Grey Meget Lysegrå - + Light Grey Lysegrå - + Grey Grå - + Dark Grey Mørkegrå - + Light Skin Lys hud - + Light Skin - shade Lys hyd - skygge - + Skin Hud - + Skin - shade Hud - skygge - + Dark Skin Mørk Hud - + Dark Skin - shade Mørk Hud - skygge @@ -1732,153 +1922,153 @@ PencilApplication - + Pencil2D is an animation/drawing software for Mac OS X, Windows, and Linux. It lets you create traditional hand-drawn animation (cartoon) using both bitmap and vector graphics. - + Path to the input pencil file. - - + + Render the file to <output_path> - - + + output_path - + Name of the camera layer to use - + layer_name - + Width of the output frames - - + + integer - + Height of the output frames - + The first frame you want to include in the exported movie - - + + frame - + The last frame you want to include in the exported movie. Can also be last or last-sound to automatically use the last frame containing animation or sound, respectively - + Render transparency when possible - + Warning: width value %1 is not an integer, ignoring. - + Warning: height value %1 is not an integer, ignoring. - + Warning: start value %1 is not an integer, ignoring. - + Warning: start value must be at least 1, ignoring. - + Warning: end value %1 is not an integer, last or last-sound, ignoring. - + Warning: end value %1 is smaller than start value %2, ignoring. - + Error: No input file specified. - + Error: the input file at '%1' does not exist Command line error - + Error: the input path '%1' is not a file Command line error - + Warning: the specified camera layer %1 was not found, ignoring. - + Warning: Output format is not specified or unsupported. Using PNG. Command line warning - + Warning: Transparency is not currently supported in movie files Command line warning - + Exporting movie... Command line task progress - - + + Done. Command line task done - + Exporting image sequence... Command line task progress @@ -1920,12 +2110,12 @@ QApplication - + Checking environment... - + Done @@ -1933,42 +2123,47 @@ QObject - + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) - - Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp) - + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp); + + + + Everything ok. - + Ooops, Something went wrong. - + File doesn't exist. - + Cannot open file. - + The file is not a valid xml document. - + The file is not valid pencil document. @@ -3317,6 +3512,16 @@ Black + + + Could not open file + + + + + There was an error processing your file. This usually means that your project has been at least partially corrupted. You can try again with a newer version of Pencil2D, or you can try to use a backup file if you have one. If you contact us through one of our offical channels we may be able to help you. For reporting issues, the best places to reach us are: + + RecentFileMenu @@ -3334,60 +3539,60 @@ ScribbleArea - + Warning Advarsel - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Du tegner på et usynligt lag!, Vær venlig at vælge et andet lag (eller lav det nuværende lag synligt). - + Delete Selection Undo Step: clear the selection area. - - + + Clear Image Undo step text - + There is a gap in your drawing (or maybe you have zoomed too much). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). - + Out of bound. - + Could not find a closed path. - + Could not find the root index. - + %1<br><br>Error: %2 - + Flood fill error Fejl ved Oversvømmelses fyldning @@ -3484,12 +3689,12 @@ - + Start Start - + Stop @@ -3573,18 +3778,18 @@ - + Delete Layer Windows title of Delete current layer pop-up. - + Please keep at least one camera layer in project - + Are you sure you want to delete layer: @@ -3592,12 +3797,12 @@ TimeLineCells - + Layer Properties - + Layer name: @@ -3674,6 +3879,16 @@ <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + + Playback + + + + + Show onion skin while playing + + Frame size diff --git a/translations/pencil_de.qm b/translations/pencil_de.qm index 569a895cde3b013b364d21e70eaf675692d8f1fe..23c9555de24b5715a30161098b46f31cf85052f9 100644 GIT binary patch delta 5410 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 - + Version: %1 Version Number in About Dialog Version: %1 - + Copy to clipboard Copy system info from About Dialog In die Zwischenablage kopieren @@ -55,30 +55,30 @@ Ton-Ebene - + Exporting movie Film wird exportiert - + Finished. Open movie now? When movie export done. Erledigt. Film jetzt öffnen? - - - - + + + + Layer Properties Ebenen-Eigenschaften - - - - + + + + Layer name: Name der Ebene: @@ -88,58 +88,63 @@ Auf diesem Frame existiert bereits eine Tonspur! Bitte wähle einen anderen Frame oder eine andere Ebene. - + + Finished. Open file location? + + + + Exporting image sequence... Bildsequenz wird exportiert... - + Abort Abbrechen - + Warning Warnung - + Unable to export image. Bild kann nicht exportiert werden. - + Bitmap Layer Rasterbild-Ebene - + Vector Layer Vektor-Ebene - + Camera Layer Kamera-Ebene - + Sound Layer Ton-Ebene - + Delete Layer Windows title of Delete current layer pop-up. Ebene löschen - + Are you sure you want to delete layer: Sind Sie sicher, dass Sie die Ebene löschen möchten: - + Please keep at least one camera layer in project text when failed to delete camera layer Bitte belassen Sie mindestens eine Kamera-Ebene im Projekt @@ -148,57 +153,57 @@ BaseTool - + Pencil Bleistift - + Eraser Radierer - + Select Auswahl - + Move Verschieben - + Hand Hand - + Smudge Verwischen - + Pen Stift - + Polyline Polygonzug - + Bucket Fülleimer - + Eyedropper Pipette - + Brush Pinsel @@ -224,69 +229,55 @@ ColorBox - - Color Wheel - Color Wheel's window title - Farbrad + + Color Box + Color Box window title + ColorInspector - + HSV HSV - + RGB RGB - - - Red - Rot - - - - - Green - Grün - - - - - Blue - Blau + + R + - - - - Alpha - Alpha + + A + - - Hue - Farbton + + G + - - Saturation - Sättigung + + B + - - Value - Helligkeit + + Color Inspector + Window title of color inspector + ColorPalette - + Color Palette Window title of color palette. Farbpalette @@ -302,57 +293,57 @@ Farbe entfernen - - ... - ... + + Native color dialog window + - + List Mode Listenmodus - + Show palette as a list Palette als Liste anzeigen - + Grid Mode Rastermodus - + Show palette as icons Palette als Symbole anzeigen - + Small swatch Kleine Vorschau - + Sets swatch size to: 16x16px Setzt Vorschaugröße auf: 16x16px - + Medium Swatch Mittlere Vorschau - + Sets swatch size to: 26x26px Setzt Vorschaugröße auf: 26x26px - + Large Swatch Große Vorschau - + Sets swatch size to: 36x36px Setzt Vorschaugröße auf: 36x36px @@ -360,11 +351,60 @@ ColorPaletteWidget - - + + Add + + + + + Replace + + + + + Remove + + + + + Colour name Name der Farbe + + + The color(s) you are about to delete are currently being used by one or multiple strokes. + + + + + Cancel + + + + + Delete + + + + + Palette Restriction + + + + + The palette requires at least one swatch to remain functional + + + + + ColorWheel + + + Color Wheel + Color Wheel's window title + + DisplayOption @@ -446,19 +486,19 @@ Editor - - + + Paste Einfügen - + Remove frame Einzelbild entfernen - - + + Import Image Bild importieren @@ -484,12 +524,12 @@ ExportImageDialog - + Export image sequence Bildsequenz exportieren - + Export image Bild exportieren @@ -531,11 +571,51 @@ Transparency Transparenz + + + Range + + + + + The last frame you want to include in the exported movie + + + + + End Frame + + + + + The first frame you want to include in the exported movie + + + + + Start Frame + + + + + <html><head/><body><p>End frame is set to last paintable keyframe (Useful when you only want to export to the last animated frame)</p></body></html> + + + + + To the end of sound clips + + ExportMovieDialog - + + Export Animated GIF + + + + Export Movie Film exportieren @@ -627,67 +707,83 @@ + Import Animated GIF + + + + Import movie Film importieren - + Import sound Ton importieren - + Import palette Palette importieren - + Save animation Animation speichern - + Export image Bild exportieren - + Export image sequence Bildsequenz exportieren - + + Export Animated GIF + + + + Export movie Film exportieren - + Export sound Ton exportieren - + Export palette Palette exportieren - + + + Animated GIF (*.gif) + + + + Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) Töne (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) - - - Palette (*.xml) - Palette (*.xml) + + + Pencil2D Palette (*.xml);; Gimp Palette (*.gpl) + - - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) + + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng) - + MyAnimation.pclx MeineAnimation.pclx @@ -695,52 +791,72 @@ FileManager - - - + + + Could not open file + + + + + The file does not exist, so we are unable to open it. Please check to make sure the path is correct and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + Invalid Save Path Ungültiger Speicherpfad - + The path ("%1") points to a directory. Der Pfad („%1“) zeigt auf ein Verzeichnis. - + The directory ("%1") does not exist. Das Verzeichnis („%1“) existiert nicht. - + The path ("%1") is not writable. Der Pfad („%1“) ist nicht beschreibbar. - - + + Cannot Create Data Directory Kann Datenverzeichnis nicht erstellen - + Failed to create directory "%1". Please make sure you have sufficient permissions. - + "%1" is a file. Please delete the file and try again. „%1“ ist eine Datei. Bitte löschen Sie die Datei und versuchen Sie es erneut. - - + + Miniz Error + + + + Internal Error Interner Fehler - - + + An internal error occurred. Your file may not be saved successfully. Ein interner Fehler ist aufgetreten. Ihre Datei wurde möglicherweise nicht erfolgreich gespeichert. @@ -818,87 +934,97 @@ Raster - + Czech Tschechisch - + Danish Dänisch - + English Englisch - + German Deutsch - + + Estonian + + + + Spanish Spanisch - + French Französisch - + Hebrew - + Hungarian Ungarisch - + Indonesian - + Italian Italienisch - + Japanese Japanisch - + + Polish + + + + Portuguese - Portugal - + Portuguese - Brazil Portugiesisch – Brasilien - + Russian Russisch - + Slovenian - + Vietnamese - + Chinese - Taiwan Chinesisch – Taiwan @@ -943,12 +1069,12 @@ Hochauflösende Tablet-Position - + Restart Required Neustart erforderlich - + The language change will take effect after a restart of Pencil2D Die Sprachänderung wird nach einem Neustart von Pencil2D wirksam werden. @@ -974,7 +1100,12 @@ ImportImageSeqDialog - + + Import Animated GIF + + + + Import image sequence Bildsequenz importieren @@ -998,7 +1129,7 @@ LayerBitmap - + Bitmap Layer Rasterbild-Ebene @@ -1014,7 +1145,7 @@ LayerSound - + Sound Layer Ton-Ebene @@ -1045,473 +1176,484 @@ Importieren - + Export Exportieren - + Edit Bearbeiten - + Selection Auswahl - + View Ansicht - + Onion Skin Zwiebelhaut - + Animation Animation - - + + Tools Werkzeuge - + Layer Ebene - - + + Help Hilfe - + Windows Fenster - + New Neu - + Open Öffnen - + Save Speichern - + Save As .. Speichern unter... - + Exit Beenden - - + + Image Sequence... Bildsequenz... - - + + Image... Bild... - - + + Movie... Film... - - + + Palette... Palette... - + Sound... Ton... - + Undo Rückgängig - + Redo Wiederholen - + Cut Ausschneiden - + Copy Kopieren - + Paste Einfügen - + Crop Zuschneiden - + Crop To Selection Auf Auswahl zuscheiden - + Select All Alles auswählen - + Deselect All Nichts auswählen - - + + Clear Frame Einzelbild leeren - + Preferences Einstellungen - + Reset Windows Fenster zurücksetzen - + Zoom In Hineinzoomen - + Zoom Out Herauszoomen - + Rotate Clockwise Im Uhrzeigersinn rotieren - + Rotate AntiClosewise Gegen den Uhrzeigersinn rotieren - + Reset Zoom/Rotate Zoom/Drehung zurücksetzen - + Horizontal Flip Horizontal spiegeln - + Vertical Flip Vertikal spiegeln - + Preview Vorschau - + Grid Raster - + Previous Vorige - + Show previous onion skin Zeige vorige Zwiebelhaut - + Next Nächste - + Show next onion skin Zeige nächste Zwiebelhaut - - + + Play Abspielen - + Loop Wiederholen - + Next Frame Nächstes Einzelbild - + Previous Frame Vorheriges Einzelbild - + Extend Frame Einzelbild erweitern - + Add Frame Einzelbild hinzufügen - + Duplicate Frame Einzelbild duplizieren - + Remove Frame Einzelbild entfernen - + Move Verschieben - + Select Auswählen - + Brush Pinsel - + Polyline Polygonzug - + Smudge Verwischen - + Pen Stift - + Hand Hand - + Pencil Bleistift - + Bucket Farbeimer - + Eyedropper Pipette - + Eraser Radierer - + New Bitmap Layer Neue Rasterbild-Ebene - + New Vector Layer Neue Vektor-Ebene - + New Sound Layer Neue Ton-Ebene - + New Camera Layer Neue Kamera-Ebene - + Delete Current Layer Aktuelle Ebene löschen - + About Über - - + + Reset to default Auf Standard zurücksetzen - + MultiLayer Onion Skin - + Range Bereich - + Pencil2D Website Pencil2D-Website - + Report a Bug Einen Fehler melden - + Quick Reference Guide - + F1 - - + + + Animated GIF... + + + + + Next KeyFrame Nächstes Schlüsselbild - - + + Previous KeyFrame Voriges Schlüsselbild - + Timeline Zeitleiste - + Options Optionen - + Color Wheel Farbrad - + Color Palette Farbpalette - + Display Options Anzeige-Optionen - + Flip X Horizontal spiegeln - + Flip Y Vertikal spiegeln - + Move Frame Forward - + Move Frame Backward - + color palette:<br>use <b>(C)</b><br>toggle at cursor Farbpalette: <br><b>(C)</b><br>An Zeigerposition umschalten - + + Color inspector + + + + Lock Windows Fenster sperren - + Open Recent Zuletzt geöffnet - + You have successfully cleared the list @@ -1520,218 +1662,266 @@ Sie haben die Liste erfolgreich geleert - - - - - + + + + + Could not open file + + + + + The file you have selected is a directory, so we are unable to open it. If you are are trying to open a project that uses the old structure, please open the file ending with .pcl, not the data folder. + + + + + The file you have selected does not exist, so we are unable to open it. Please check to make sure that you've entered the correct path and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + + + Warning Warnung - - - Pencil cannot read this file. If you want to import images, use the command import. - Pencil kann die Datei nicht lesen. Wenn Sie Bilder importieren möchten, benutzen sie die Importfunktion. + + This program does not currently have permission to write to the file you have selected. Please make sure you have write permission for this file before attempting to save it. Alternatively, you can use the Save As... menu option to save to a writable location. + - + Opening document... Dokument wird geöffnet... - - - + + + + Abort Abbrechen - + + An unknown error occurred while trying to load the file and we are not able to load your file. + + + + Saving document... Dokument wird gespeichert... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>Ein Fehler ist aufgetreten und Ihre Datei wurde womöglich nicht erfolgreich gespeichert. Falls Sie glauben, dass es sich hierbei um einen Programmfehler in Pencil2D handelt, erstellen Sie bitte auf Englisch eine neue Meldung unter:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Bitte fügen Sie Ihrer Meldung unbedingt die folgenden Details bei: - + This animation has been modified. Do you want to save your changes? Diese Animation wurde geändert. Möchten Sie Ihre Änderungen speichern? - + The animation is not saved yet. Do you want to save now? Die Animation wurde noch nicht gespeichert. Möchten Sie sie jetzt speichern? - + Never ask again AutoSave reminder button Nicht mehr fragen - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Bild kann nicht importiert werden.<br><b>TIPP:</b> Verwenden Sie eine Rasterebene um Rasterbilder zu importieren. - + Importing image sequence... - + + was unable to import - - + + Importing Animated GIF... + + + + + Undo Menu item text - + Redo Menu item text - + Stop + + MoveTool + + + Layer switch + Windows title of layer switch pop-up. + + + + + You are about to switch layer, do you want to apply the transformation? + + + Object - + Black Schwarz - + Red Rot - + Dark Red Dunkelrot - + Orange Orange - + Dark Orange Dunkelorange - + Yellow Gelb - + Dark Yellow Dunkelgelb - + Green Grün - + Dark Green Dunkelgrün - + Cyan Cyan - + Dark Cyan Dunkelcyan - + Blue Blau - + Dark Blue Dunkelblau - + White Weiß - + Very Light Grey Sehr helles Grau - + Light Grey Hellgrau - + Grey Grau - + Dark Grey Dunkelgrau - + Light Skin Helle Hautfarbe - + Light Skin - shade Helle Hautfarbe – Schatten - + Skin Hautfarbe - + Skin - shade Hautfarbe – Schatten - + Dark Skin Dunkle Hautfarbe - + Dark Skin - shade Dunkle Hautfarbe – Schatten @@ -1739,153 +1929,153 @@ Sie haben die Liste erfolgreich geleert PencilApplication - + Pencil2D is an animation/drawing software for Mac OS X, Windows, and Linux. It lets you create traditional hand-drawn animation (cartoon) using both bitmap and vector graphics. Pencil2D ist eine Animations-/Zeichensoftware für Mac OS X, Windows und Linux. Sie eignet sich zum Schaffen von traditioneller handgezeichneter Animation (Zeichentrick) sowohl mit Raster- als auch mit Vektorgrafik. - + Path to the input pencil file. Pfad zur Eingabe-Pencil-Datei. - - + + Render the file to <output_path> Datei nach <Ausgabepfad> rendern - - + + output_path Ausgabepfad - + Name of the camera layer to use Name der zu verwendenden Kamera-Ebene - + layer_name Ebenenname - + Width of the output frames Breite der Ausgabebilder - - + + integer Ganzzahl - + Height of the output frames Höhe der Ausgabebilder - + The first frame you want to include in the exported movie Das erste Bild, das Sie in den exportierten Film einbeziehen möchten - - + + frame - + The last frame you want to include in the exported movie. Can also be last or last-sound to automatically use the last frame containing animation or sound, respectively - + Render transparency when possible Falls möglich Transparenz rendern - + Warning: width value %1 is not an integer, ignoring. Warnung: Wert %1 für Breite ist keine Ganzzahl, wird ignoriert. - + Warning: height value %1 is not an integer, ignoring. Warnung: Wert %1 für Höhe ist keine Ganzzahl, wird ignoriert. - + Warning: start value %1 is not an integer, ignoring. Warnung: Startwert %1 ist keine Ganzzahl, wird ignoriert. - + Warning: start value must be at least 1, ignoring. Warnung: Startwert muss mindestens 1 sein, wird ignoriert. - + Warning: end value %1 is not an integer, last or last-sound, ignoring. Warnung: Endwert %1 ist keine Ganzzahl, last oder last-sound, wird ignoriert. - + Warning: end value %1 is smaller than start value %2, ignoring. Warnung: Endwert %1 ist kleiner als Startwert %2, wird ignoriert. - + Error: No input file specified. Fehler: Keine Eingabedatei angegeben. - + Error: the input file at '%1' does not exist Command line error - + Error: the input path '%1' is not a file Command line error - + Warning: the specified camera layer %1 was not found, ignoring. Warnung: Die angegebene Kamera-Ebene %1 wurde nicht gefunden, wird ignoriert. - + Warning: Output format is not specified or unsupported. Using PNG. Command line warning - + Warning: Transparency is not currently supported in movie files Command line warning - + Exporting movie... Command line task progress - - + + Done. Command line task done - + Exporting image sequence... Command line task progress @@ -1927,12 +2117,12 @@ Sie haben die Liste erfolgreich geleert QApplication - + Checking environment... - + Done Erledigt. @@ -1940,42 +2130,47 @@ Sie haben die Liste erfolgreich geleert QObject - + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) - - Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp) - + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp); + + + + Everything ok. Alles ok. - + Ooops, Something went wrong. Uups, etwas ist schiefgegangen. - + File doesn't exist. Datei existiert nicht. - + Cannot open file. Kann Datei nicht öffnen. - + The file is not a valid xml document. Die Datei ist kein gültiges XML-Dokument. - + The file is not valid pencil document. Die Datei ist kein gültiges Pencil-Dokument. @@ -3324,6 +3519,16 @@ Sie haben die Liste erfolgreich geleert Black Schwarz + + + Could not open file + + + + + There was an error processing your file. This usually means that your project has been at least partially corrupted. You can try again with a newer version of Pencil2D, or you can try to use a backup file if you have one. If you contact us through one of our offical channels we may be able to help you. For reporting issues, the best places to reach us are: + + RecentFileMenu @@ -3341,60 +3546,60 @@ Sie haben die Liste erfolgreich geleert ScribbleArea - + Warning Warnung - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Sie zeichnen auf einer ausgeblendeten Ebene! Bitte wählen Sie eine andere Ebene aus (oder blenden Sie die aktuelle Ebene ein) - + Delete Selection Undo Step: clear the selection area. Auswahl löschen - - + + Clear Image Undo step text Bild leeren - + There is a gap in your drawing (or maybe you have zoomed too much). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). - + Out of bound. - + Could not find a closed path. Konnte keinen geschlossenen Pfad finden. - + Could not find the root index. - + %1<br><br>Error: %2 %1<br><br>Fehler: %2 - + Flood fill error @@ -3491,12 +3696,12 @@ Sie haben die Liste erfolgreich geleert - + Start Anfang - + Stop @@ -3580,18 +3785,18 @@ Sie haben die Liste erfolgreich geleert - + Delete Layer Windows title of Delete current layer pop-up. Ebene löschen - + Please keep at least one camera layer in project Bitte belassen Sie mindestens eine Kamera-Ebene im Projekt - + Are you sure you want to delete layer: Sind Sie sicher, dass Sie die Ebene löschen möchten: @@ -3599,12 +3804,12 @@ Sie haben die Liste erfolgreich geleert TimeLineCells - + Layer Properties Ebeneneigenschaften - + Layer name: Ebenenname: @@ -3681,6 +3886,16 @@ Sie haben die Liste erfolgreich geleert <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + + Playback + + + + + Show onion skin while playing + + Frame size diff --git a/translations/pencil_es.qm b/translations/pencil_es.qm index d24cc06334eb0803b13999b13e2d2acd6541d3bd..3b06880bc9e483c42e59604eec9a496459211f65 100644 GIT binary patch delta 15757 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 a<9ocjEcYxmppzbDk&Jbd)hOJr@_zvJ27l84 delta 6975 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 diff --git a/translations/pencil_es.ts b/translations/pencil_es.ts index 2064a0888..b38b524af 100644 --- a/translations/pencil_es.ts +++ b/translations/pencil_es.ts @@ -13,13 +13,13 @@ Sitio Oficial: <a href="https://www.pencil2d.org">pencil2d.org</a><br>Desarrollado por: <b>Pascal Naidon, Patrick Corrieri, Matt Chang</b><br>Agradecimientos a: Qt Framework <a href="https://www.qt.io/download">https://www.qt.io/</a><br>miniz: <a href="https://github.com/richgel999/miniz">https://github.com/richgel999/miniz</a><br>Distribución bajo la:<a href="http://www.gnu.org/licenses/gpl-2.0.html">GNU General Public License, version 2</a> - + Version: %1 Version Number in About Dialog Versión: %1 - + Copy to clipboard Copy system info from About Dialog Copiar al portapapeles @@ -55,30 +55,30 @@ Capa de Sonido - + Exporting movie Exportando película - + Finished. Open movie now? When movie export done. Terminado. ¿Ver ahora? - - - - + + + + Layer Properties Propiedades de la capa - - - - + + + + Layer name: Nombre de la capa: @@ -88,58 +88,63 @@ Un clip de sonido ya existe en este fotograma! Por favor seleccionar otro fotograma o capa - + + Finished. Open file location? + Terminado. ¿Abrir localización de archivo? + + + Exporting image sequence... Exportando secuencia de imágenes... - + Abort Abortar - + Warning Advertencia - + Unable to export image. No se puede exportar imagen. - + Bitmap Layer Capa de bitmap - + Vector Layer Capa de vector - + Camera Layer Capa de cámara - + Sound Layer Capa de sonido - + Delete Layer Windows title of Delete current layer pop-up. Eliminar Capa - + Are you sure you want to delete layer: ¿Seguro que deseas eliminar la capa? - + Please keep at least one camera layer in project text when failed to delete camera layer Favor de mantener al menos una capa de cámara en el proyecto @@ -148,57 +153,57 @@ BaseTool - + Pencil Lápiz - + Eraser Borrador - + Select Seleccionar - + Move Mover - + Hand Mano - + Smudge Dedo - + Pen Pluma - + Polyline Polilínea - + Bucket Bote - + Eyedropper Pipeta - + Brush Pincel @@ -224,69 +229,55 @@ ColorBox - - Color Wheel - Color Wheel's window title - Círculo Cromático + + Color Box + Color Box window title + Caja de Color ColorInspector - + HSV HSV - + RGB RGB - - - Red - Rojo - - - - - Green - Verde - - - - - Blue - Azul + + R + R - - - - Alpha - Alfa + + A + - - Hue - Tono + + G + - - Saturation - Saturación + + B + - - Value - Valor + + Color Inspector + Window title of color inspector + Inspector de color ColorPalette - + Color Palette Window title of color palette. Paleta de color @@ -302,57 +293,57 @@ Elimina color - - ... - ... + + Native color dialog window + Ventana de diálogo de color nativo - + List Mode Estilo Lista - + Show palette as a list Mostrar paleta como Lista - + Grid Mode Estilo Cuadrícula - + Show palette as icons Mostrar paleta como Iconos - + Small swatch Muestra pequeña - + Sets swatch size to: 16x16px Ajustar tamaño de muestra a: 16x16px - + Medium Swatch Muestra media - + Sets swatch size to: 26x26px Ajustar tamaño de muestra a: 26x26px - + Large Swatch Muestra grande - + Sets swatch size to: 36x36px Ajustar tamaño de muestra a: 36x36px @@ -360,11 +351,61 @@ ColorPaletteWidget - - + + Add + Agregar + + + + Replace + Reemplazar + + + + Remove + +Eliminar + + + + Colour name Nombre del color + + + The color(s) you are about to delete are currently being used by one or multiple strokes. + El / los color (s) que está a punto de eliminar se usan actualmente en uno o varios trazos. + + + + Cancel + Cancelar + + + + Delete + Borrar + + + + Palette Restriction + Paleta de restricción + + + + The palette requires at least one swatch to remain functional + La paleta requiere al menos una muestra para permanecer funcional + + + + ColorWheel + + + Color Wheel + Color Wheel's window title + Rueda de color + DisplayOption @@ -446,19 +487,19 @@ Editor - - + + Paste Pegar - + Remove frame Eliminar fotograma - - + + Import Image Importar imagen @@ -484,12 +525,12 @@ ExportImageDialog - + Export image sequence Exportar secuencia de imágenes - + Export image Exportar imagen @@ -531,11 +572,51 @@ Transparency Transparencia + + + Range + Alcance + + + + The last frame you want to include in the exported movie + El último cuadro que desea incluir en la película exportada + + + + End Frame + Marco final + + + + The first frame you want to include in the exported movie + El primer fotograma que desea incluir en la película exportada + + + + Start Frame + Cuadro de inicio + + + + <html><head/><body><p>End frame is set to last paintable keyframe (Useful when you only want to export to the last animated frame)</p></body></html> + <html><head/><body><p>El fotograma final está configurado como el último fotograma clave que se puede pintar (útil cuando solo desea exportar al último fotograma animado)</p></body></html> + + + + To the end of sound clips + Hasta el final de los clips de sonido + ExportMovieDialog - + + Export Animated GIF + Exportar GIF animado + + + Export Movie Exportar película @@ -627,67 +708,83 @@ + Import Animated GIF + Importar un GIF animado + + + Import movie Importar película - + Import sound Importar sonido - + Import palette Importar paleta - + Save animation Gravar animación - + Export image Exportar imagen - + Export image sequence Exportar secuencia de imágenes - + + Export Animated GIF + Exportar GIF animado + + + Export movie Exportar película - + Export sound Exportar sonido - + Export palette Exportar paleta - + + + Animated GIF (*.gif) + GIF animado (* .gif) + + + Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) Sonido (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) - - - Palette (*.xml) - Paleta (*.xml) + + + Pencil2D Palette (*.xml);; Gimp Palette (*.gpl) + Paleta Pencil2D (* .xml) ;; Gimp Palette (* .gpl) - - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) + + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng) + MP4 (* .mp4) ;; AVI (* .avi) ;; WebM (* .webm) ;; APNG (* .apng) - + MyAnimation.pclx MiAnimación.pclx @@ -695,52 +792,72 @@ FileManager - - - + + + Could not open file + No se pudo abrir el archivo + + + + The file does not exist, so we are unable to open it. Please check to make sure the path is correct and that the file is accessible and try again. + El archivo no existe, por lo que no podemos abrirlo. Verifique que la ruta sea correcta y que el archivo esté accesible y vuelva a intentarlo. + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + Este programa no tiene permiso para leer el archivo que ha seleccionado. Verifique que haya leído los permisos para este archivo y vuelva a intentarlo. + + + + + Invalid Save Path Camino inválido - + The path ("%1") points to a directory. La dirección del archivo ("%1") apunta a una carpeta - + The directory ("%1") does not exist. El directorio seleccionado en ("%1") no existe - + The path ("%1") is not writable. El camino ("%1") no se puede escribir. - - + + Cannot Create Data Directory No se puede crear Directorio de datos - + Failed to create directory "%1". Please make sure you have sufficient permissions. Fallo al crear directorio "%1". Por favor asegúrese de que tiene los permisos necesarios. - + "%1" is a file. Please delete the file and try again. "%1" es un archivo. Por favor elimine el archivo e inténtelo de nuevo. - - + + Miniz Error + Miniz Error + + + Internal Error Falla interna - - + + An internal error occurred. Your file may not be saved successfully. Una falla interna ocurrió. Puede que el archivo no se haya grabado correctamente. @@ -818,87 +935,97 @@ Cuadrícula - + Czech Checo - + Danish Dinamarqués - + English Ingles - + German Alemán - + + Estonian + Estonio + + + Spanish Español - + French Frances - + Hebrew Hebreo - + Hungarian Húngaro - + Indonesian Indonesio - + Italian Italiano - + Japanese Japones - + + Polish + Polaco + + + Portuguese - Portugal Portugués - Portugal - + Portuguese - Brazil Portugués - Brasil - + Russian Ruso - + Slovenian Eslovaquia - + Vietnamese Vietnam - + Chinese - Taiwan Chino - Taiwan @@ -943,12 +1070,12 @@ Posición de Alta Resolución para Tabla Gráfica - + Restart Required Inicio requerido - + The language change will take effect after a restart of Pencil2D El cambio de Idioma tomará efecto después de reiniciar Pencil2D @@ -974,7 +1101,12 @@ ImportImageSeqDialog - + + Import Animated GIF + Importar un GIF animado + + + Import image sequence Importar secuencia de imágenes @@ -998,7 +1130,7 @@ LayerBitmap - + Bitmap Layer Capa Bitmap @@ -1014,7 +1146,7 @@ LayerSound - + Sound Layer Capa de Sonido @@ -1045,688 +1177,747 @@ Importar - + Export Exportar - + Edit Editar - + Selection Selección - + View Vista - + Onion Skin Papel Cebolla - + Animation Animación - - + + Tools Herramientas - + Layer Capa - - + + Help Ayuda - + Windows Ventanas - + New Nuevo - + Open Abrir - + Save Grabar - + Save As .. Grabar como ... - + Exit Salir - - + + Image Sequence... Secuencia de Imagenes... - - + + Image... Imagen... - - + + Movie... Película... - - + + Palette... Paleta... - + Sound... Sonido... - + Undo Deshacer - + Redo Rehacer - + Cut Cortar - + Copy Copiar - + Paste Pegar - + Crop Recortar - + Crop To Selection Recortar por la Selección - + Select All Seleccionar Todo - + Deselect All Deseleccionar Todo - - + + Clear Frame Limpiar Fotograma - + Preferences Preferencias - + Reset Windows Restaurar Ventanas - + Zoom In Acercar - + Zoom Out Alejar - + Rotate Clockwise Rotar Derecha - + Rotate AntiClosewise Rotar Izquierda - + Reset Zoom/Rotate Restaurar Zoom/Rotación - + Horizontal Flip Girar Horizontalmente - + Vertical Flip Girar Verticalmente - + Preview Vista Previa - + Grid Cuadricula - + Previous Anterior - + Show previous onion skin Mostrar papel cebolla anterior - + Next Siguiente - + Show next onion skin Mostrar papel cebolla posterior  - - + + Play Reproducir - + Loop Ciclo - + Next Frame Fotograma posterior - + Previous Frame Fotograma anterior - + Extend Frame Extender Fotograma - + Add Frame Añadir Fotograma - + Duplicate Frame Duplicar Fotograma - + Remove Frame Eliminar Fotograma - + Move Mover - + Select Seleccionar - + Brush Pincel - + Polyline Polilínea - + Smudge Dedo - + Pen Pluma - + Hand Mano - + Pencil Lápiz - + Bucket Bote de pintura - + Eyedropper Pipeta - + Eraser Borrador - + New Bitmap Layer Nueva Capa Bitmap - + New Vector Layer Nueva Capa Vector - + New Sound Layer Nueva Capa Sonido - + New Camera Layer Nueva Capa Cámara - + Delete Current Layer Eliminar Capa Actual - + About Acerca de - - + + Reset to default Restaurar Predeterminado - + MultiLayer Onion Skin MultiCapas Papel Cebolla - + Range Alcance - + Pencil2D Website Sitio web de Pencil2D - + Report a Bug Reportar una falla - + Quick Reference Guide Quia de Consulta Rápida - + F1 F1 - - + + + Animated GIF... + GIF animado + + + + Next KeyFrame Fotograma-Clave posterior - - + + Previous KeyFrame Fotograma-Clave anterior - + Timeline Línea de Tiempo - + Options Opciones - + Color Wheel Rueda de Color - + Color Palette Paleta de Color - + Display Options Opciones de Visualización - + Flip X Girar Horizontalmente - + Flip Y Girar Verticalmente - + Move Frame Forward Avanzar un fotograma - + Move Frame Backward Retroceder un fotograma - + color palette:<br>use <b>(C)</b><br>toggle at cursor Paleta de Color:<br>Utilice <b>(C)</b><br>para alternar sobre punteros - + + Color inspector + Inspector de color + + + Lock Windows Bloquear Ventanas - + Open Recent Abrir Reciente - + You have successfully cleared the list Lista eliminada con éxito - - - - - + + + + + Could not open file + No se pudo abrir el archivo + + + + The file you have selected is a directory, so we are unable to open it. If you are are trying to open a project that uses the old structure, please open the file ending with .pcl, not the data folder. + El archivo que ha seleccionado es un directorio, por lo que no podemos abrirlo. Si está intentando abrir un proyecto que usa la estructura anterior, abra el archivo que termina en .pcl, no la carpeta de datos. + + + + The file you have selected does not exist, so we are unable to open it. Please check to make sure that you've entered the correct path and that the file is accessible and try again. + El archivo que ha seleccionado no existe, por lo que no podemos abrirlo. Verifique que haya ingresado la ruta correcta y que el archivo esté accesible y vuelva a intentarlo. + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + Este programa no tiene permiso para leer el archivo que ha seleccionado. Verifique que haya leído los permisos para este archivo y vuelva a intentarlo. + + + + + + + Warning Advertencia - - - Pencil cannot read this file. If you want to import images, use the command import. - Pencil no puede leer este archivo. Si desea importar imágenes, utilice la opción Importar. + + This program does not currently have permission to write to the file you have selected. Please make sure you have write permission for this file before attempting to save it. Alternatively, you can use the Save As... menu option to save to a writable location. + Este programa actualmente no tiene permiso para escribir en el archivo que ha seleccionado. Asegúrese de tener permiso de escritura para este archivo antes de intentar guardarlo. Alternativamente, puede usar la opción de menú Guardar como ... para guardar en una ubicación de escritura. - + Opening document... Abriendo Documento... - - - + + + + Abort Abortar - + + An unknown error occurred while trying to load the file and we are not able to load your file. + Se produjo un error desconocido al intentar cargar el archivo y no podemos cargar su archivo. + + + Saving document... Grabando Documento... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>Una falla ha ocurrido y el archivo puede que no se haya grabado correctamente. Si piensa que este error es un problema de Pencil2D, por favor haga un informe en:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Asegúrese de incluir los siguientes detalles en su reporte: - + This animation has been modified. Do you want to save your changes? Esta animación ha sido modificada. ¿Desea guardar sus cambios? - + The animation is not saved yet. Do you want to save now? La animación aun no ha sido gravada. Quiere gravarla ahora? - + Never ask again AutoSave reminder button No volver a preguntar - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. No se puede importar imagen<br><b>TIP:</b> Use una capa Bitmap para importar bitmaps. - + Importing image sequence... Importando secuencia de imágenes... - + + was unable to import - + no pudo importar - - + + Importing Animated GIF... + Importación de GIF animado ... + + + + Undo Menu item text Deshacer - + Redo Menu item text Rehacer - + Stop Parar + + MoveTool + + + Layer switch + Windows title of layer switch pop-up. + Conmutador de capa + + + + You are about to switch layer, do you want to apply the transformation? + Estás a punto de cambiar de capa, ¿quieres aplicar la transformación? + + Object - + Black Negro - + Red Rojo - + Dark Red Rojo Oscuro - + Orange Naranja - + Dark Orange Naranja Oscuro - + Yellow Amarillo - + Dark Yellow Amarillo Oscuro - + Green Verde - + Dark Green Verde Oscuro - + Cyan Cian - + Dark Cyan Cian Oscuro - + Blue Azul - + Dark Blue Azul Oscuro - + White Blanco - + Very Light Grey Gris Muy Claro - + Light Grey Gris Claro - + Grey Gris - + Dark Grey Gris Oscuro - + Light Skin Piel Clara - + Light Skin - shade Piel Clara - Sombra - + Skin Piel - + Skin - shade Piel - Sombra - + Dark Skin Piel Oscura - + Dark Skin - shade Piel Oscura - Sombra @@ -1734,153 +1925,153 @@ Quiere gravarla ahora? PencilApplication - + Pencil2D is an animation/drawing software for Mac OS X, Windows, and Linux. It lets you create traditional hand-drawn animation (cartoon) using both bitmap and vector graphics. Pencil2D es un software de animación/dibujo para Mac OS X, Windows y Linux. Permite crear animaciones tradicionales hechas a mano (dibujos animados) usando gráficos rasterizados y/o vectoriales. - + Path to the input pencil file. Ruta del archivo de pencil importado - - + + Render the file to <output_path> Renderizar el archivo a <output_path> - - + + output_path Ruta_de_exportación - + Name of the camera layer to use Nombre de la Capa Cámara a usar - + layer_name nombre_de_capa - + Width of the output frames Ancho de los fotogramas de exportación - - + + integer entero - + Height of the output frames Altura de los marcos de exportación - + The first frame you want to include in the exported movie El primer fotograma que deseas incluir en la película exportada - - + + frame Fotograma - + The last frame you want to include in the exported movie. Can also be last or last-sound to automatically use the last frame containing animation or sound, respectively El ultimo fotograma que deseas incluir en la película exportada. Éste puede ser el último fotograma de audio o de animación. - + Render transparency when possible Renderizar tansparencia cuando sea posible - + Warning: width value %1 is not an integer, ignoring. Advertencia: valor largura %1 no es un número entero. Postergado. - + Warning: height value %1 is not an integer, ignoring. Advertencia: valor altura %1 no es un número entero. Postergado. - + Warning: start value %1 is not an integer, ignoring. Advertencia: el valor de inicio %1 no es un número entero. Postergado. - + Warning: start value must be at least 1, ignoring. Advertencia: el valor de inicio tiene que ser por lo menos 1. Postergado. - + Warning: end value %1 is not an integer, last or last-sound, ignoring. Advertencia: el último valor %1 no es un número entero, ultimo o ultimo-sonido. Postergado. - + Warning: end value %1 is smaller than start value %2, ignoring. Advertencia: el último valor %1 es menor que el valor de inicio %2. Postergado. - + Error: No input file specified. Fallo: archivo no especificado - + Error: the input file at '%1' does not exist Command line error Fallo: El archivo en '%1' no existe - + Error: the input path '%1' is not a file Command line error Fallo: El camino '%1' no es un archivo - + Warning: the specified camera layer %1 was not found, ignoring. Advertencia: la capa de cámara %1 no se ha encontrado. Postergado. - + Warning: Output format is not specified or unsupported. Using PNG. Command line warning Advertencia: el formato escogido no es soportado. Usar PNG. - + Warning: Transparency is not currently supported in movie files Command line warning Advertencia: La Transparencia no es actualmente soportada en archivos de películas - + Exporting movie... Command line task progress Exportando película - - + + Done. Command line task done Terminado. - + Exporting image sequence... Command line task progress Exportando secuencia de imágenes... @@ -1922,12 +2113,12 @@ Quiere gravarla ahora? QApplication - + Checking environment... Probando el sistema... - + Done Terminado @@ -1935,42 +2126,47 @@ Quiere gravarla ahora? QObject - + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) - - Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) - + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp) + Imágenes (* .png * .jpg * .jpeg * .bmp) ;; PNG (* .png) ;; JPG (*. Jpg * .jpeg) ;; BMP (*. Bmp) + + + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp); + Imágenes (* .png * .jpg * .jpeg * .bmp) ;; PNG (* .png) ;; JPG (*. Jpg * .jpeg) ;; BMP (*. Bmp); - + Everything ok. Todo correcto. - + Ooops, Something went wrong. ¡Ups! Algo ha salido mal. - + File doesn't exist. El archivo no existe. - + Cannot open file. No se puede abrir el archivo - + The file is not a valid xml document. El archivo no es un documento xml válido - + The file is not valid pencil document. El archivo no es un documento válido de Pencil @@ -3319,6 +3515,16 @@ Quiere gravarla ahora? Black Negro + + + Could not open file + No se pudo abrir el archivo + + + + There was an error processing your file. This usually means that your project has been at least partially corrupted. You can try again with a newer version of Pencil2D, or you can try to use a backup file if you have one. If you contact us through one of our offical channels we may be able to help you. For reporting issues, the best places to reach us are: + Hubo un error al procesar su archivo. Esto generalmente significa que su proyecto ha sido al menos parcialmente dañado. Puede volver a intentarlo con una versión más nueva de Pencil2D, o puede intentar usar un archivo de copia de seguridad si tiene uno. Si se comunica con nosotros a través de uno de nuestros canales oficiales, podemos ayudarlo. Para informar problemas, los mejores lugares para contactarnos son: + RecentFileMenu @@ -3336,60 +3542,60 @@ Quiere gravarla ahora? ScribbleArea - + Warning Advertencia - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Usted está dibujando en una capa oculta! Por favor seleccione otra capa (o haga visible la capa actual). - + Delete Selection Undo Step: clear the selection area. Quitar Selección - - + + Clear Image Undo step text Limpiar imagen - + There is a gap in your drawing (or maybe you have zoomed too much). Hay una interrupción en su dibujo (ó talvez usted haya usado mucho el zoom) - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). Disculpe! Esto ni siempre funciona. Por favor inténtelo de nuevo (aumente un poco el zoom, haga clic en otro sitio... )<br>Caso no funcione, aumente un poco más el zoom y asegúrese de que las interrupciones son conectadas presionando F1). - + Out of bound. Fuera del limite - + Could not find a closed path. No se encuentra el camino cerrado - + Could not find the root index. No se encuentra el índice principal. - + %1<br><br>Error: %2 %1<br><br>Fallo: %2 - + Flood fill error Fallo de Relleno @@ -3486,12 +3692,12 @@ Quiere gravarla ahora? - + Start Inicio - + Stop Parar @@ -3575,18 +3781,18 @@ Quiere gravarla ahora? Alternancia fotogramas claves - + Delete Layer Windows title of Delete current layer pop-up. Eliminar capa - + Please keep at least one camera layer in project Por favor, mantenga al menos una capa de cámara en el proyecto - + Are you sure you want to delete layer: Estás seguro de que quieres eliminar la capa: @@ -3594,12 +3800,12 @@ Quiere gravarla ahora? TimeLineCells - + Layer Properties Propiedades de la capa - + Layer name: Nombre de la capa: @@ -3639,42 +3845,52 @@ Quiere gravarla ahora? Drawing - + Dibujo When drawing on an empty frame: - + Al dibujar en un marco vacío: Create a new (blank) key-frame and start drawing on it. - + Cree un nuevo fotograma clave (en blanco) y comience a dibujar en él. Create a new (blank) key-frame - + Crear un nuevo fotograma clave (en blanco) Duplicate the previous key-frame and start drawing on the duplicate. - + Duplique el fotograma clave anterior y comience a dibujar en el duplicado. Duplicate the previous key-frame - + Duplicar el marco clave anterior Keep drawing on the previous key-frame - + Sigue dibujando en el fotograma clave anterior <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> - + <html><head/><body><p>(Se aplica a las herramientas Lápiz, Borrador, Pluma, Polilínea, Cubeta y Cepillo)</p></body></html> + + + + Playback + Reproducción + + + + Show onion skin while playing + Mostrar piel de cebolla mientras se reproduce diff --git a/translations/pencil_et.qm b/translations/pencil_et.qm index 09d9a7479af53b5cde5729f7ab9835095634688b..6fd1a24846c79b20f2eea57bff17363ec7be09c1 100644 GIT binary patch delta 3390 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 M?e;@Gc1d&o2T{ejivR!s delta 3915 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 DPg5Ametlik veebisait: <a href="https://www.pencil2d.org">pencil2d.org</a><br>Arendaja: <b>Pascal Naidon, Patrick Corrieri, Matt Chang</b><br>Suur tänu Qt Frameworkile <a href="https://www.qt.io/download">https://www.qt.io/</a><br>miniz: <a href="https://github.com/richgel999/miniz">https://github.com/richgel999/miniz</a><br>Levitatakse <a href="http://www.gnu.org/licenses/gpl-2.0.html">GNU General Public License, version 2</a> alusel - + Version: %1 Version Number in About Dialog Versioon: %1 - + Copy to clipboard Copy system info from About Dialog Kopeeri lõikelauale @@ -55,30 +55,30 @@ Helikiht - + Exporting movie Video eksportimine - + Finished. Open movie now? When movie export done. Lõpetatud. Kas avada video? - - - - + + + + Layer Properties Kihi omadused - - - - + + + + Layer name: Kihi nimi: @@ -88,58 +88,63 @@ Heliklipp on selles kaadris juba olemas! Palun vali teine kaader või kiht. - + + Finished. Open file location? + + + + Exporting image sequence... Pildiseeria importimine... - + Abort Katkesta - + Warning Hoiatus - + Unable to export image. Pildi eksportimine ebaõnnestus. - + Bitmap Layer Pildifaili kiht - + Vector Layer Vektorkiht - + Camera Layer Kaamera kiht - + Sound Layer Helikiht - + Delete Layer Windows title of Delete current layer pop-up. Kustuta kiht - + Are you sure you want to delete layer: Oled sa kindel, et soovid kusutada kihti: - + Please keep at least one camera layer in project text when failed to delete camera layer Palun hoia projektis alles vähemalt üks kaamerakiht @@ -148,57 +153,57 @@ BaseTool - + Pencil Pliiats - + Eraser Kustukumm - + Select Valimine - + Move Liigutamine - + Hand Käsi - + Smudge Hägustamine - + Pen Pliiats - + Polyline - + Bucket - + Eyedropper - + Brush Pintsel @@ -224,69 +229,55 @@ ColorBox - - Color Wheel - Color Wheel's window title - Värvi ratas + + Color Box + Color Box window title + ColorInspector - + HSV HSV - + RGB RGB - - - Red - Punane - - - - - Green - Roheline - - - - - Blue - Sinine + + R + - - - - Alpha - Alfa + + A + - - Hue + + G - - Saturation - Küllastus + + B + - - Value - Väärtus + + Color Inspector + Window title of color inspector + ColorPalette - + Color Palette Window title of color palette. Värvipalett @@ -302,57 +293,57 @@ Eemalda värv - - ... - ... + + Native color dialog window + - + List Mode Nimekirjarežiim - + Show palette as a list Näita paletti nimekirjana - + Grid Mode Võrgustiku režiim - + Show palette as icons Näita palette ikoonidena - + Small swatch - + Sets swatch size to: 16x16px - + Medium Swatch - + Sets swatch size to: 26x26px - + Large Swatch - + Sets swatch size to: 36x36px @@ -360,11 +351,60 @@ ColorPaletteWidget - - + + Add + + + + + Replace + + + + + Remove + + + + + Colour name Värvi nimi + + + The color(s) you are about to delete are currently being used by one or multiple strokes. + + + + + Cancel + + + + + Delete + + + + + Palette Restriction + + + + + The palette requires at least one swatch to remain functional + + + + + ColorWheel + + + Color Wheel + Color Wheel's window title + + DisplayOption @@ -446,19 +486,19 @@ Editor - - + + Paste Aseta - + Remove frame Eemalda kaader - - + + Import Image Impordi pilt @@ -484,12 +524,12 @@ ExportImageDialog - + Export image sequence Ekspordi pildiseeria - + Export image Ekspordi pilt @@ -531,11 +571,51 @@ Transparency Läbipaistvus + + + Range + + + + + The last frame you want to include in the exported movie + + + + + End Frame + + + + + The first frame you want to include in the exported movie + + + + + Start Frame + + + + + <html><head/><body><p>End frame is set to last paintable keyframe (Useful when you only want to export to the last animated frame)</p></body></html> + + + + + To the end of sound clips + + ExportMovieDialog - + + Export Animated GIF + + + + Export Movie Ekspordi video @@ -627,67 +707,83 @@ + Import Animated GIF + + + + Import movie Impordi video - + Import sound Impordi heli - + Import palette Impordi palett - + Save animation Salvesta animatsioon - + Export image Ekspordi pilt - + Export image sequence Ekspordi pildiseeria - + + Export Animated GIF + + + + Export movie Ekspordi video - + Export sound Ekspordi heli - + Export palette Ekspordi palett - + + + Animated GIF (*.gif) + + + + Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) Helifailid (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) - - - Palette (*.xml) - Palett (*.xml) + + + Pencil2D Palette (*.xml);; Gimp Palette (*.gpl) + - - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) + + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng) + - + MyAnimation.pclx MinuAnimatsioon.pclx @@ -695,52 +791,72 @@ FileManager - - - + + + Could not open file + + + + + The file does not exist, so we are unable to open it. Please check to make sure the path is correct and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + Invalid Save Path Vigane salvestamise asukoht - + The path ("%1") points to a directory. Asukoht ("%1") viitab kaustale. - + The directory ("%1") does not exist. Kausta ("%1") pole olemas. - + The path ("%1") is not writable. Kaust ("%1") pole kirjutatav. - - + + Cannot Create Data Directory Andmete kausta loomine ebaõnnestus - + Failed to create directory "%1". Please make sure you have sufficient permissions. Kausta "%1" loomine ebaõnnestus. Palun veendu, et sul oleks piisavalt õiguseid. - + "%1" is a file. Please delete the file and try again. "%1" on fail. Palun kustuta see fail ja proovi siis uuesti. - - + + Miniz Error + + + + Internal Error Sisemine tõrge - - + + An internal error occurred. Your file may not be saved successfully. Tekkis sisemine tõrge. Võimalik, et sinu faili ei salvestatud korrektselt. @@ -818,87 +934,97 @@ Võrgustik - + Czech Tšehhi - + Danish Taani - + English Inglise - + German Saksa - + + Estonian + + + + Spanish Hispaania - + French Prantsuse - + Hebrew eebrea - + Hungarian Ungari - + Indonesian Indoneesia - + Italian Itaalia - + Japanese Jaapani - + + Polish + + + + Portuguese - Portugal Portugali - Portugal - + Portuguese - Brazil Portugali - Brasiilia - + Russian Vene - + Slovenian Sloveenia - + Vietnamese Vietnami - + Chinese - Taiwan Hiina - Taivani @@ -943,12 +1069,12 @@ - + Restart Required Nõutud on taaskäivitamine - + The language change will take effect after a restart of Pencil2D Keele muudatus rakendatakse pärast Pencil2D taaskäivitamist @@ -974,7 +1100,12 @@ ImportImageSeqDialog - + + Import Animated GIF + + + + Import image sequence Impordi pildiseeria @@ -998,7 +1129,7 @@ LayerBitmap - + Bitmap Layer Pildifaili kiht @@ -1014,7 +1145,7 @@ LayerSound - + Sound Layer Helikiht @@ -1045,473 +1176,484 @@ Impordi - + Export Ekspordi - + Edit Muuda - + Selection Valik - + View Vaade - + Onion Skin - + Animation Animatsioon - - + + Tools Tööriistad - + Layer Kiht - - + + Help Aviinfo - + Windows Aken - + New Uus - + Open Ava - + Save Salvesta - + Save As .. Salvesta kui ... - + Exit Välju - - + + Image Sequence... Pildiseeria... - - + + Image... Pilt... - - + + Movie... Video... - - + + Palette... Palett... - + Sound... Heli... - + Undo Samm tagasi - + Redo Korda - + Cut Lõika - + Copy Kopeeri - + Paste Aseta - + Crop Kärbi - + Crop To Selection Kärbi valiku järgi - + Select All Vali kõik - + Deselect All Tühista valik - - + + Clear Frame Tühjenda kaader - + Preferences Eelistused - + Reset Windows Nulli aknad - + Zoom In Suumi sisse - + Zoom Out Suumi välja - + Rotate Clockwise Pööra päripäeva - + Rotate AntiClosewise Pööra vastupäeva - + Reset Zoom/Rotate Nulli suurendus/pööramine - + Horizontal Flip Horisontaalne peegeldamine - + Vertical Flip Vertikaalne peegeldamine - + Preview Eelvaade - + Grid Võrgustik - + Previous Eelmine - + Show previous onion skin - + Next Järgmine - + Show next onion skin - - + + Play Esita - + Loop Kordamine - + Next Frame Järgmine kaader - + Previous Frame Eelmine kaader - + Extend Frame Laienda kaadrit - + Add Frame Lisa kaader - + Duplicate Frame Tee kaadrist koopia - + Remove Frame Eemalda kaader - + Move Liigutamine - + Select Valimine - + Brush Pintsel - + Polyline - + Smudge - + Pen Pliiats - + Hand Käsi - + Pencil Pliiats - + Bucket - + Eyedropper - + Eraser Kustukumm - + New Bitmap Layer Uus pildifaili kiht - + New Vector Layer Uus vektorkiht - + New Sound Layer Uus helikiht - + New Camera Layer Uus kaamera kiht - + Delete Current Layer Kustuta praegune kiht - + About Info - - + + Reset to default Taasta vaikeväärtused - + MultiLayer Onion Skin - + Range Vahemik - + Pencil2D Website Pencil2D veebisait - + Report a Bug Teavita veast - + Quick Reference Guide Kiirjuhend - + F1 F1 - - + + + Animated GIF... + + + + + Next KeyFrame - - + + Previous KeyFrame - + Timeline Ajatelg - + Options Valikud - + Color Wheel Värviratas - + Color Palette Värvipalett - + Display Options Vaate valikud - + Flip X - + Flip Y - + Move Frame Forward Liigut akaadrit edasi - + Move Frame Backward Liiguta kaadrit tagasi - + color palette:<br>use <b>(C)</b><br>toggle at cursor - + + Color inspector + + + + Lock Windows Lukusta aknad - + Open Recent Ava hiljutised - + You have successfully cleared the list @@ -1520,213 +1662,261 @@ Nimekiri on tühjendatud - - - - - + + + + + Could not open file + + + + + The file you have selected is a directory, so we are unable to open it. If you are are trying to open a project that uses the old structure, please open the file ending with .pcl, not the data folder. + + + + + The file you have selected does not exist, so we are unable to open it. Please check to make sure that you've entered the correct path and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + + + Warning Hoiatus - - - Pencil cannot read this file. If you want to import images, use the command import. + + This program does not currently have permission to write to the file you have selected. Please make sure you have write permission for this file before attempting to save it. Alternatively, you can use the Save As... menu option to save to a writable location. - + Opening document... Dokumendi avamine... - - - + + + + Abort Info - + + An unknown error occurred while trying to load the file and we are not able to load your file. + + + + Saving document... Dokumendi salvestamine... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: - + This animation has been modified. Do you want to save your changes? - + The animation is not saved yet. Do you want to save now? - + Never ask again AutoSave reminder button Ära küsi kunagi uuesti - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. - + Importing image sequence... Pildiseeria importimine... - + + was unable to import - - + + Importing Animated GIF... + + + + + Undo Menu item text Samm tagasi - + Redo Menu item text Korda - + Stop Peata + + MoveTool + + + Layer switch + Windows title of layer switch pop-up. + + + + + You are about to switch layer, do you want to apply the transformation? + + + Object - + Black Must - + Red Punane - + Dark Red Tumepunane - + Orange Oraanž - + Dark Orange Tumeoraanž - + Yellow Kollane - + Dark Yellow Tumekollane - + Green Roheline - + Dark Green Tumeroheline - + Cyan Tsüaan - + Dark Cyan Tume tsüaan - + Blue Sinine - + Dark Blue Tumesinine - + White Valge - + Very Light Grey Väga hele hall - + Light Grey Helehall - + Grey Hall - + Dark Grey Tumehall - + Light Skin Hele nahk - + Light Skin - shade Hele nahk - varjuga - + Skin Nahk - + Skin - shade Nahk - varjuga - + Dark Skin Tume nahk - + Dark Skin - shade Tume nahk - varjuga @@ -1734,153 +1924,153 @@ Nimekiri on tühjendatud PencilApplication - + Pencil2D is an animation/drawing software for Mac OS X, Windows, and Linux. It lets you create traditional hand-drawn animation (cartoon) using both bitmap and vector graphics. - + Path to the input pencil file. - - + + Render the file to <output_path> Renderda fail kausta <output_path> - - + + output_path väljundi_kaust - + Name of the camera layer to use Kasutatava kaamera kihi nimi - + layer_name kihi_nimi - + Width of the output frames Väljundikaadrite laius - - + + integer täisarv - + Height of the output frames Väljundkaadrite kõrgus - + The first frame you want to include in the exported movie - - + + frame kaader - + The last frame you want to include in the exported movie. Can also be last or last-sound to automatically use the last frame containing animation or sound, respectively - + Render transparency when possible Kui võimalik, siis säilita läbipaistvus - + Warning: width value %1 is not an integer, ignoring. Hoiatus: %1 laiuse väärtus pole täisarv. Seda ignoreeritakse. - + Warning: height value %1 is not an integer, ignoring. Hoiatus: %1 kõrguse väärtus pole täisarv. Seda ignoreeritakse. - + Warning: start value %1 is not an integer, ignoring. Hoiatus: %1 alguse väärtus pole täisarv. Seda ignoreeritakse. - + Warning: start value must be at least 1, ignoring. Hoiatus: alguse väärtus peab olema vähemalt 1. Seda ignoreeritakse. - + Warning: end value %1 is not an integer, last or last-sound, ignoring. - + Warning: end value %1 is smaller than start value %2, ignoring. - + Error: No input file specified. Tõrge: Sisendfaili pole määratud. - + Error: the input file at '%1' does not exist Command line error - + Error: the input path '%1' is not a file Command line error - + Warning: the specified camera layer %1 was not found, ignoring. - + Warning: Output format is not specified or unsupported. Using PNG. Command line warning - + Warning: Transparency is not currently supported in movie files Command line warning - + Exporting movie... Command line task progress Video eksportimine... - - + + Done. Command line task done Valmis. - + Exporting image sequence... Command line task progress Pildiseeria eksportimine... @@ -1922,12 +2112,12 @@ Nimekiri on tühjendatud QApplication - + Checking environment... Keskkonna kontrollimine... - + Done Valmis @@ -1935,42 +2125,47 @@ Nimekiri on tühjendatud QObject - + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) - - Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp) - + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp); + + + + Everything ok. Kõik on OK. - + Ooops, Something went wrong. Oih, midagi läks valesti. - + File doesn't exist. Faili pole olemas. - + Cannot open file. Faili ei saa avada. - + The file is not a valid xml document. Fail pole korrektne XML dokument. - + The file is not valid pencil document. Fail pole korrektne pencil dokument. @@ -3319,6 +3514,16 @@ Nimekiri on tühjendatud Black Must + + + Could not open file + + + + + There was an error processing your file. This usually means that your project has been at least partially corrupted. You can try again with a newer version of Pencil2D, or you can try to use a backup file if you have one. If you contact us through one of our offical channels we may be able to help you. For reporting issues, the best places to reach us are: + + RecentFileMenu @@ -3336,60 +3541,60 @@ Nimekiri on tühjendatud ScribbleArea - + Warning Hoiatus - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). - + Delete Selection Undo Step: clear the selection area. Kustuta valik - - + + Clear Image Undo step text Eemalda pilt - + There is a gap in your drawing (or maybe you have zoomed too much). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). - + Out of bound. Piiridest väljas. - + Could not find a closed path. Suletud asukohta ei leitud. - + Could not find the root index. - + %1<br><br>Error: %2 %1<br><br>Viga: %2 - + Flood fill error @@ -3486,12 +3691,12 @@ Nimekiri on tühjendatud - + Start Algus - + Stop Peata @@ -3575,18 +3780,18 @@ Nimekiri on tühjendatud - + Delete Layer Windows title of Delete current layer pop-up. Kustuta kiht - + Please keep at least one camera layer in project - + Are you sure you want to delete layer: @@ -3594,12 +3799,12 @@ Nimekiri on tühjendatud TimeLineCells - + Layer Properties Kihi omadused - + Layer name: Kihi nimi: @@ -3676,6 +3881,16 @@ Nimekiri on tühjendatud <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + + Playback + + + + + Show onion skin while playing + + Frame size diff --git a/translations/pencil_fr.qm b/translations/pencil_fr.qm index e086806de4da106c697c94ab19f37afad23ce96e..7d93030a385cc6211fc866e62e320b86866c8d5d 100644 GIT binary patch delta 6021 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 officiel : <a href="https://www.pencil2d.org">pencil2d.org</a><br> Développé par: <b>Pascal Naidon, Patrick Corrieri, Matt Chang</b><br> Remerciements à Qt Framework <a href="https://www.qt.io/download">https://www.qt.io/</a><br>miniz: <a href="https://github.com/richgel999/miniz">https://github.com/richgel999/miniz</a> <br>Distribué sous la <a href="http://www.gnu.org/licenses/gpl-2.0.html">GNU General Public License, version 2</a> - + Version: %1 Version Number in About Dialog Version: %1 - + Copy to clipboard Copy system info from About Dialog Copier dans le presse-papier @@ -55,30 +55,30 @@ Calque son - + Exporting movie Exporter un film - + Finished. Open movie now? When movie export done. Fini. Ouvrir un film maintenant? - - - - + + + + Layer Properties Propriétés du calque - - - - + + + + Layer name: Nom du calque: @@ -88,58 +88,63 @@ Un clip sonore existe déjà sur ce cadre! Veuillez sélectionner un autre cadre ou calque. - + + Finished. Open file location? + + + + Exporting image sequence... Exportation de la séquence d'images... - + Abort Abandonner - + Warning Attention - + Unable to export image. Incapable d'exporter l'image. - + Bitmap Layer couche bitmap - + Vector Layer couche vecteur - + Camera Layer couche caméra - + Sound Layer couche son - + Delete Layer Windows title of Delete current layer pop-up. Supprimer le calque - + Are you sure you want to delete layer: Êtes-vous sûr de vouloir supprimer le calque: - + Please keep at least one camera layer in project text when failed to delete camera layer Veuillez conserver au moins un calque de caméra dans le projet @@ -148,57 +153,57 @@ BaseTool - + Pencil Crayon - + Eraser Gomme - + Select Sélectionner - + Move Déplacer - + Hand Main - + Smudge Etaler - + Pen Stylo - + Polyline Polyligne - + Bucket Seau - + Eyedropper Pipette - + Brush Brosse @@ -224,69 +229,55 @@ ColorBox - - Color Wheel - Color Wheel's window title - Roue Couleurs + + Color Box + Color Box window title + ColorInspector - + HSV HSV - + RGB RGB - - - Red - Rouge + + R + - - - Green - Vert + + A + - - - Blue - Bleu + + G + - - - - Alpha - Alpha - - - - Hue - teinte - - - - Saturation - Saturation + + B + - - Value - Valeur + + Color Inspector + Window title of color inspector + ColorPalette - + Color Palette Window title of color palette. Palette Couleur @@ -302,57 +293,57 @@ Retirer couleur - - ... - ... + + Native color dialog window + - + List Mode Mode Liste - + Show palette as a list Afficher la palette sous forme de liste - + Grid Mode Mode Grille - + Show palette as icons Afficher la palette sous forme d'icônes - + Small swatch Échantillon Petit - + Sets swatch size to: 16x16px Définit la taille de l'échantillon à: 16x16px - + Medium Swatch Échantillon Moyen - + Sets swatch size to: 26x26px Définit la taille de l'échantillon à: 26x26px - + Large Swatch Échantillon Large - + Sets swatch size to: 36x36px Définit la taille de l'échantillon à: 36x36px @@ -360,11 +351,60 @@ ColorPaletteWidget - - + + Add + + + + + Replace + + + + + Remove + + + + + Colour name Nom de la couleur + + + The color(s) you are about to delete are currently being used by one or multiple strokes. + + + + + Cancel + + + + + Delete + + + + + Palette Restriction + + + + + The palette requires at least one swatch to remain functional + + + + + ColorWheel + + + Color Wheel + Color Wheel's window title + + DisplayOption @@ -447,19 +487,19 @@ Editor - - + + Paste Coller - + Remove frame Supprimer le cadre - - + + Import Image Importer une image @@ -485,12 +525,12 @@ ExportImageDialog - + Export image sequence Exporter une séquence d'images - + Export image Exporter l'image @@ -532,11 +572,51 @@ Transparency Transparence + + + Range + + + + + The last frame you want to include in the exported movie + + + + + End Frame + + + + + The first frame you want to include in the exported movie + + + + + Start Frame + + + + + <html><head/><body><p>End frame is set to last paintable keyframe (Useful when you only want to export to the last animated frame)</p></body></html> + + + + + To the end of sound clips + + ExportMovieDialog - + + Export Animated GIF + + + + Export Movie Exporter un film @@ -628,67 +708,83 @@ + Import Animated GIF + + + + Import movie Importer un film - + Import sound Importer le son - + Import palette Importer palette - + Save animation Enregistrer l'animation - + Export image Exporter l'image - + Export image sequence Exporter une séquence d'image - + + Export Animated GIF + + + + Export movie Exporter un film - + Export sound Exporter le son - + Export palette Exporter palette - + + + Animated GIF (*.gif) + + + + Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) Sons (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) - - - Palette (*.xml) - Palette (*.xml) + + + Pencil2D Palette (*.xml);; Gimp Palette (*.gpl) + - - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) - MP4 (*.mp4);;AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) + + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng) + - + MyAnimation.pclx MyAnimation.pclx @@ -696,52 +792,72 @@ FileManager - - - + + + Could not open file + + + + + The file does not exist, so we are unable to open it. Please check to make sure the path is correct and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + Invalid Save Path Chemin de sauvegarde invalide - + The path ("%1") points to a directory. Le chemin ("%1") pointe vers un répertoire. - + The directory ("%1") does not exist. Le répertoire ("%1") n'existe pas. - + The path ("%1") is not writable. Le chemin ("%1") n'est pas accessible en écriture. - - + + Cannot Create Data Directory Impossible de créer le répertoire de données - + Failed to create directory "%1". Please make sure you have sufficient permissions. Impossible de créer le répertoire "%1". S'il vous plaît assurez-vous que vous avez les autorisations suffisantes. - + "%1" is a file. Please delete the file and try again. "%1" est un fichier. Veuillez supprimer le fichier et réessayer. - - + + Miniz Error + + + + Internal Error Erreur interne - - + + An internal error occurred. Your file may not be saved successfully. Une erreur interne a eu lieu. Votre fichier peut ne pas être enregistré avec succès. @@ -819,87 +935,97 @@ Grille - + Czech Tchèque - + Danish Danois - + English Anglais - + German Allemand - + + Estonian + + + + Spanish Espanol - + French Français - + Hebrew Hébreu - + Hungarian Hongrois - + Indonesian Indonésien - + Italian Italien - + Japanese Japonais - + + Polish + + + + Portuguese - Portugal Portugais - Portugal - + Portuguese - Brazil Portugais - Brésil - + Russian Russe - + Slovenian Slovaque - + Vietnamese Vietnamien - + Chinese - Taiwan Chinois - Taïwan @@ -944,12 +1070,12 @@ Position haute résolution de la tablette - + Restart Required Redémarrage requis - + The language change will take effect after a restart of Pencil2D Le changement de langue prendra effet après un redémarrage de Pencil2D @@ -975,7 +1101,12 @@ ImportImageSeqDialog - + + Import Animated GIF + + + + Import image sequence Importer une séquence d'image @@ -999,7 +1130,7 @@ LayerBitmap - + Bitmap Layer Calque image @@ -1015,7 +1146,7 @@ LayerSound - + Sound Layer Calque son @@ -1046,473 +1177,484 @@ Importer - + Export Exporter - + Edit Édition - + Selection Sélection - + View Affichage - + Onion Skin Pelure d'oignon - + Animation Animation - - + + Tools Outils - + Layer Calque - - + + Help Aide - + Windows Fenêtres - + New Nouveau - + Open Ouvrir - + Save Enregistrer - + Save As .. Enregistrer sous... - + Exit Sortie - - + + Image Sequence... Séquence d'images... - - + + Image... Image... - - + + Movie... Film... - - + + Palette... Palette... - + Sound... Son... - + Undo Annuler - + Redo Rétablir - + Cut Couper - + Copy Copier - + Paste Coller - + Crop Découper - + Crop To Selection Découper vers sélection - + Select All Tout sélectionner - + Deselect All Tout désélectionner - - + + Clear Frame Effacer l'image - + Preferences Préférences - + Reset Windows Réinitialiser la fenêtre - + Zoom In Agrandir - + Zoom Out Diminuer - + Rotate Clockwise Rotation sens horaire - + Rotate AntiClosewise Rotation sens anti horaire - + Reset Zoom/Rotate Réinitialiser Zoom/Rotation - + Horizontal Flip Symétrie horizontale - + Vertical Flip Symétrie verticale - + Preview Aperçu - + Grid Grille - + Previous Précédent - + Show previous onion skin Afficher précédente image transparente - + Next Suivant - + Show next onion skin Afficher prochaine image transparente - - + + Play Play - + Loop Boucle - + Next Frame image suivante - + Previous Frame image précédente - + Extend Frame image étendue - + Add Frame Ajouter une image - + Duplicate Frame Dupliquer une image - + Remove Frame Enlever une image - + Move Déplacer - + Select Sélectionner - + Brush Brosse - + Polyline Polyligne - + Smudge Etaler - + Pen Stylo - + Hand Main - + Pencil Crayon - + Bucket Seau - + Eyedropper Pipette - + Eraser Gomme - + New Bitmap Layer Nouveau calque Image - + New Vector Layer Nouveau calque Vecteur - + New Sound Layer Nouveau calque Son - + New Camera Layer Nouveau calque Caméra - + Delete Current Layer Supprimer le calque courant - + About A propos - - + + Reset to default Réinitialiser par défaut - + MultiLayer Onion Skin Peau d'oignon Multicouche - + Range Gamme - + Pencil2D Website Site Web Pencil2D - + Report a Bug Signaler un bug - + Quick Reference Guide Aide-mémoire - + F1 F1 - - + + + Animated GIF... + + + + + Next KeyFrame Image suivante - - + + Previous KeyFrame Image précedente - + Timeline Chronologie - + Options Options - + Color Wheel Roue Couleurs - + Color Palette Palette Couleurs - + Display Options Option d'Affichage - + Flip X Retourner axe X - + Flip Y Retourner axe Y - + Move Frame Forward Avancer l'image - + Move Frame Backward Reculer l'image - + color palette:<br>use <b>(C)</b><br>toggle at cursor palette de couleurs :<br>utiliser <b>(C)</b><br>bascule à curseur - + + Color inspector + + + + Lock Windows Verrouiller les fenêtres - + Open Recent Ouvrir fichier récent - + You have successfully cleared the list @@ -1521,215 +1663,263 @@ Vous avez effacé la liste avec succès - - - - - + + + + + Could not open file + + + + + The file you have selected is a directory, so we are unable to open it. If you are are trying to open a project that uses the old structure, please open the file ending with .pcl, not the data folder. + + + + + The file you have selected does not exist, so we are unable to open it. Please check to make sure that you've entered the correct path and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + + + Warning Attention - - - Pencil cannot read this file. If you want to import images, use the command import. - Pencil ne peut pas lire ce fichier. Si vous voulez import des images, utilisez la commande import. + + This program does not currently have permission to write to the file you have selected. Please make sure you have write permission for this file before attempting to save it. Alternatively, you can use the Save As... menu option to save to a writable location. + - + Opening document... Document de démarrage... - - - + + + + Abort Abandonner - + + An unknown error occurred while trying to load the file and we are not able to load your file. + + + + Saving document... Enregistrement d'un document... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>Une erreur est survenue et votre fichier n'a peut-être pas été sauvegardé correctement. Si vous pensez que cette erreur est un problème avec Pencil2D, veuillez créer un nouveau problème sur:<br><a href='https://github.com/pencil2d/pencil/issues'> https: //github.com/pencil2d/pencil/issues</a><br>Veuillez vous assurer d'inclure les détails suivants dans votre problème: - + This animation has been modified. Do you want to save your changes? Cette animation a été modifiée. Voulez vous sauvegarder vos modifications ? - + The animation is not saved yet. Do you want to save now? L'animation n'est pas encore enregistrée. Voulez-vous enregistrer maintenant? - + Never ask again AutoSave reminder button Ne plus me demander - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Impossible d'importer l'image.<br><b>ASTUCE:</b> Utilisez un calque "Bitmap" pour importer des bitmaps. - + Importing image sequence... Importation de la séquence d'image... - + + was unable to import incapable d'importer - - + + Importing Animated GIF... + + + + + Undo Menu item text Annuler - + Redo Menu item text Rétablir - + Stop Arrêter + + MoveTool + + + Layer switch + Windows title of layer switch pop-up. + + + + + You are about to switch layer, do you want to apply the transformation? + + + Object - + Black Noir - + Red Rouge - + Dark Red Rouge foncé - + Orange Orange - + Dark Orange Orange foncé - + Yellow Jaune - + Dark Yellow Jaune foncé - + Green Vert - + Dark Green Vert foncé - + Cyan Cyan - + Dark Cyan Cyan foncé - + Blue Bleu - + Dark Blue Bleu foncé - + White Blanc - + Very Light Grey Gris trés léger - + Light Grey Gris léger - + Grey Gris - + Dark Grey Gris foncé - + Light Skin Peau clair - + Light Skin - shade Peau claire - ombré - + Skin Peau - + Skin - shade Peau ombrée - + Dark Skin Peau foncée - + Dark Skin - shade Peau foncée ombrée @@ -1737,153 +1927,153 @@ Voulez-vous enregistrer maintenant? PencilApplication - + Pencil2D is an animation/drawing software for Mac OS X, Windows, and Linux. It lets you create traditional hand-drawn animation (cartoon) using both bitmap and vector graphics. Pencil2D est un logiciel d'animation / dessin pour Mac OS X, Windows et Linux. Il vous permet de créer une animation traditionnelle (dessin animé) à la main en utilisant à la fois des images bitmap et des graphiques vectoriels. - + Path to the input pencil file. Chemin d'accès de l'entrée au fichier du crayon. - - + + Render the file to <output_path> Rendre le fichier à <output_path> - - + + output_path output_path - + Name of the camera layer to use Nom du calque de la caméra à utiliser - + layer_name layer_name - + Width of the output frames Largeur des trames de sortie - - + + integer entier - + Height of the output frames Hauteur des trames de sortie - + The first frame you want to include in the exported movie La première image que vous souhaitez inclure dans le film exporté - - + + frame cadre - + The last frame you want to include in the exported movie. Can also be last or last-sound to automatically use the last frame containing animation or sound, respectively La dernière image que vous voulez inclure dans le film exporté. Peut aussi être le dernier ou le dernier son à utiliser automatiquement la dernière image contenant de l'animation ou du son, respectivement - + Render transparency when possible Rendre la transparence quand c'est possible - + Warning: width value %1 is not an integer, ignoring. Attention: la valeur de la largeur %1 n'est pas un nombre entier, ignorer. - + Warning: height value %1 is not an integer, ignoring. Attention: la valeur de hauteur %1 n'est pas un entier, ignorer. - + Warning: start value %1 is not an integer, ignoring. Attention: la valeur de départ %1 n'est pas un nombre entier, ignorer. - + Warning: start value must be at least 1, ignoring. Attention: la valeur de départ doit être au moins 1, ignorer. - + Warning: end value %1 is not an integer, last or last-sound, ignoring. Attention: la valeur finale %1 n'est pas un entier, dernier ou dernier son, ignorer. - + Warning: end value %1 is smaller than start value %2, ignoring. Attention: la valeur finale %1 est inférieure à la valeur initiale %2, ignorer. - + Error: No input file specified. Erreur: Aucun fichier d'entrée spécifié. - + Error: the input file at '%1' does not exist Command line error Erreur: le fichier source à '%1' n'existe pas - + Error: the input path '%1' is not a file Command line error Erreur: le chemin d'entrée '%1' n'est pas un fichier - + Warning: the specified camera layer %1 was not found, ignoring. Attention: le calque de la caméra spécifié %1 n'a pas été trouvé, ignorer. - + Warning: Output format is not specified or unsupported. Using PNG. Command line warning Attention: le format de sortie n'est pas spécifié ou non supporté. Utilisation PNG. - + Warning: Transparency is not currently supported in movie files Command line warning Attention: la transparence n'est actuellement pas supportée dans les fichiers vidéo - + Exporting movie... Command line task progress Exportation du film... - - + + Done. Command line task done Terminé. - + Exporting image sequence... Command line task progress Exportation de la séquence d'images... @@ -1925,12 +2115,12 @@ Voulez-vous enregistrer maintenant? QApplication - + Checking environment... Vérification de l'environnement... - + Done Terminé @@ -1938,42 +2128,47 @@ Voulez-vous enregistrer maintenant? QObject - + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) - - Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) - Images (* .png * .jpg * .jpeg * .bmp * .gif) ;; PNG (* .png) ;; JPG (* .jpg * .jpeg) ;; BMP (* .bmp) ;; GIF (* .gif) + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp) + + + + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp); + - + Everything ok. Tout est OK. - + Ooops, Something went wrong. Oups, quelque chose ne s'est pas passé comme prévu. - + File doesn't exist. Le fichier n’existe pas. - + Cannot open file. Impossible d'ouvrir le fichier - + The file is not a valid xml document. Le fichier n'est pas un document xml valide. - + The file is not valid pencil document. Le fichier n'est pas un fichier Pencil valide. @@ -3322,6 +3517,16 @@ Voulez-vous enregistrer maintenant? Black Noir + + + Could not open file + + + + + There was an error processing your file. This usually means that your project has been at least partially corrupted. You can try again with a newer version of Pencil2D, or you can try to use a backup file if you have one. If you contact us through one of our offical channels we may be able to help you. For reporting issues, the best places to reach us are: + + RecentFileMenu @@ -3339,60 +3544,60 @@ Voulez-vous enregistrer maintenant? ScribbleArea - + Warning Attention - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Vous dessinez sur un calque masqué ! Veuillez sélectionner une autre couche (ou rendre le calque visible). - + Delete Selection Undo Step: clear the selection area. Supprimer la sélection - - + + Clear Image Undo step text Effacer l'image - + There is a gap in your drawing (or maybe you have zoomed too much). Il y a un écart dans votre dessin (ou peut-être que vous avez trop zoomé). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). Pardon! Cela ne fonctionne pas toujours. Veuillez réessayer (zoomer un peu, cliquer à un autre endroit ...)<br>si cela ne fonctionne pas, zoomez un peu et vérifiez que vos chemins sont connectés en appuyant sur F1.). - + Out of bound. En dehors de la limite. - + Could not find a closed path. Impossible de trouver un chemin fermé. - + Could not find the root index. Impossible de trouver l'index racine. - + %1<br><br>Error: %2 %1<br><br>Erreur:%2 - + Flood fill error Erreur de remplissage @@ -3489,12 +3694,12 @@ Voulez-vous enregistrer maintenant? - + Start Début - + Stop Arrêter @@ -3578,18 +3783,18 @@ Voulez-vous enregistrer maintenant? Basculer les images clés correspondantes - + Delete Layer Windows title of Delete current layer pop-up. Supprimer le calque - + Please keep at least one camera layer in project Veuillez conserver au moins un calque de la caméra dans le projet - + Are you sure you want to delete layer: Etes vous sûr de vouloir supprimer le calque: @@ -3597,12 +3802,12 @@ Voulez-vous enregistrer maintenant? TimeLineCells - + Layer Properties Propriétés du calque - + Layer name: Nom du calque: @@ -3679,6 +3884,16 @@ Voulez-vous enregistrer maintenant? <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> <html><head/><body><p>(S'applique aux outils Crayon, Gomme, Stylo, Polyligne, Seau et Pinceau)</p></body></html> + + + Playback + + + + + Show onion skin while playing + + Frame size diff --git a/translations/pencil_he.qm b/translations/pencil_he.qm index e1bb5bd75e4e9baeeccb41cd61ae11f3e47e7595..610091db3ccfa6636f9a308d09fa0374a3d872ef 100644 GIT binary patch delta 3949 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 diff --git a/translations/pencil_he.ts b/translations/pencil_he.ts index fa511a497..63a6fe249 100644 --- a/translations/pencil_he.ts +++ b/translations/pencil_he.ts @@ -13,13 +13,13 @@ - + Version: %1 Version Number in About Dialog גירסא: %1 - + Copy to clipboard Copy system info from About Dialog העתק ללוח @@ -55,30 +55,30 @@ שכבת צליל - + Exporting movie - + Finished. Open movie now? When movie export done. סיימתי. האם לפתוח את הסרט כעת? - - - - + + + + Layer Properties מאפייני שכבה - - - - + + + + Layer name: שם שכבה: @@ -88,58 +88,63 @@ קטע קול קיים למסגרת זו! אנא בחר מסגרת או שכבה אחרת - + + Finished. Open file location? + + + + Exporting image sequence... מייצא רצף תמונות... - + Abort בטל - + Warning אזהרה - + Unable to export image. לא אפשרי לייצא תמונה - + Bitmap Layer שכבת מפת ביטים - + Vector Layer שכבת וקטורים - + Camera Layer שכבת מצלמה - + Sound Layer שכבת צליל - + Delete Layer Windows title of Delete current layer pop-up. מחק שכבה - + Are you sure you want to delete layer: האם אתה בטוח שברצונך למחוק שכבה: - + Please keep at least one camera layer in project text when failed to delete camera layer אנא שמור לפחות שכבת מצלמה אחת בפרוייקט @@ -148,57 +153,57 @@ BaseTool - + Pencil עפרון - + Eraser מחק - + Select בחירה - + Move הזזה - + Hand יד - + Smudge טשטוש - + Pen עט - + Polyline רב-קו - + Bucket דלי - + Eyedropper טפטפת - + Brush מברשת @@ -224,69 +229,55 @@ ColorBox - - Color Wheel - Color Wheel's window title - גלגל צבעים + + Color Box + Color Box window title + ColorInspector - + HSV HSV - + RGB RGB - - - Red - אדום - - - - - Green - ירוק - - - - - Blue - כחול + + R + - - - - Alpha - שקיפות + + A + - - Hue - גוון + + G + - - Saturation - רוויה + + B + - - Value - ערך/בהירות + + Color Inspector + Window title of color inspector + ColorPalette - + Color Palette Window title of color palette. @@ -302,57 +293,57 @@ הסר צבע - - ... - ... + + Native color dialog window + - + List Mode - + Show palette as a list - + Grid Mode - + Show palette as icons - + Small swatch - + Sets swatch size to: 16x16px - + Medium Swatch - + Sets swatch size to: 26x26px - + Large Swatch - + Sets swatch size to: 36x36px @@ -360,11 +351,60 @@ ColorPaletteWidget - - + + Add + + + + + Replace + + + + + Remove + + + + + Colour name שם צבע + + + The color(s) you are about to delete are currently being used by one or multiple strokes. + + + + + Cancel + + + + + Delete + + + + + Palette Restriction + + + + + The palette requires at least one swatch to remain functional + + + + + ColorWheel + + + Color Wheel + Color Wheel's window title + + DisplayOption @@ -446,19 +486,19 @@ Editor - - + + Paste הדבק - + Remove frame הסר מסגרת - - + + Import Image ייבא תמונה @@ -484,12 +524,12 @@ ExportImageDialog - + Export image sequence ייצא רצף תמונות - + Export image ייצא תמונה @@ -531,11 +571,51 @@ Transparency שקיפות + + + Range + + + + + The last frame you want to include in the exported movie + + + + + End Frame + + + + + The first frame you want to include in the exported movie + + + + + Start Frame + + + + + <html><head/><body><p>End frame is set to last paintable keyframe (Useful when you only want to export to the last animated frame)</p></body></html> + + + + + To the end of sound clips + + ExportMovieDialog - + + Export Animated GIF + + + + Export Movie ייצא סרט @@ -627,67 +707,83 @@ + Import Animated GIF + + + + Import movie ייבא סרט - + Import sound ייבא צליל - + Import palette ייבא טבלת צבעים - + Save animation שמור הנפשה - + Export image ייצא תמונה - + Export image sequence ייצא רצף תמונות - + + Export Animated GIF + + + + Export movie ייצא סרט - + Export sound ייצא צליל - + Export palette ייצא טבלת צבעים - + + + Animated GIF (*.gif) + + + + Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) צלילים (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) - - - Palette (*.xml) - טבלת צבעים (*.xml) + + + Pencil2D Palette (*.xml);; Gimp Palette (*.gpl) + - - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) + + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng) - + MyAnimation.pclx הנפשה_שלי.pclx @@ -695,52 +791,72 @@ FileManager - - - + + + Could not open file + + + + + The file does not exist, so we are unable to open it. Please check to make sure the path is correct and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + Invalid Save Path מיקום לא חוקי לשמירה - + The path ("%1") points to a directory. - + The directory ("%1") does not exist. - + The path ("%1") is not writable. - - + + Cannot Create Data Directory לא ניתן ליצור תיקיית נתונים - + Failed to create directory "%1". Please make sure you have sufficient permissions. - + "%1" is a file. Please delete the file and try again. - - + + Miniz Error + + + + Internal Error שגיאה פנימית - - + + An internal error occurred. Your file may not be saved successfully. @@ -818,87 +934,97 @@ רשת - + Czech צ׳כית - + Danish דנית - + English אנגלית - + German גרמנית - + + Estonian + + + + Spanish ספרדית - + French צרפתית - + Hebrew - + Hungarian הונגרית - + Indonesian - + Italian איטלקית - + Japanese יפנית - + + Polish + + + + Portuguese - Portugal - + Portuguese - Brazil פורטוגזית - ברזיל - + Russian רוסית - + Slovenian - + Vietnamese - + Chinese - Taiwan סינית - טיוואן @@ -943,12 +1069,12 @@ מיקום לוח מגע באבחנה גבוהה - + Restart Required יש לאתחל מחדש - + The language change will take effect after a restart of Pencil2D שינוי השפה יבוא לידי ביטוי לאחר הפעלה מחדש של Pencil2D. @@ -974,7 +1100,12 @@ ImportImageSeqDialog - + + Import Animated GIF + + + + Import image sequence ייבא רצף תמונות @@ -998,7 +1129,7 @@ LayerBitmap - + Bitmap Layer שכבת מפת ביטים @@ -1014,7 +1145,7 @@ LayerSound - + Sound Layer שכבת צליל @@ -1045,473 +1176,484 @@ ייבא - + Export ייצא - + Edit ערוך - + Selection בחירה - + View תצוגה - + Onion Skin שכבות בצל - + Animation הנפשה - - + + Tools כלים - + Layer שכבה - - + + Help עזרה - + Windows חלונות - + New חדש - + Open פתח - + Save שמור - + Save As .. שמור בשם... - + Exit יציאה - - + + Image Sequence... רצף תמונות... - - + + Image... תמונה... - - + + Movie... סרט... - - + + Palette... טבלת צבעים... - + Sound... צליל... - + Undo בטל פעולה - + Redo חזור על פעולה - + Cut חתוך - + Copy העתק - + Paste הדבק - + Crop לחתוך לגודל - + Crop To Selection חתוך לאזור הבחירה - + Select All בחר הכל - + Deselect All בטל כל בחירה - - + + Clear Frame אפס מסגרת - + Preferences העדפות - + Reset Windows אפס חלונות - + Zoom In הגדלה - + Zoom Out הקטנה - + Rotate Clockwise סובב בכיוון השעון - + Rotate AntiClosewise סובב נגד כיוון השעון - + Reset Zoom/Rotate אפס הגדלה וסיבוב - + Horizontal Flip הפוך אופקית - + Vertical Flip הפוך אנכית - + Preview תצוגה מקדימה - + Grid רשת - + Previous הקודם - + Show previous onion skin הצג שכבת בצל קודמת - + Next הבא - + Show next onion skin הצג שכבת בצל הבאה - - + + Play נגן - + Loop לולאה - + Next Frame המסגרת הבאה - + Previous Frame המסגרת הקודמת - + Extend Frame הארכת מסגרת - + Add Frame הוסף מסגרת - + Duplicate Frame שכפל מסגרת - + Remove Frame הסר מסגרת - + Move הזז - + Select בחר - + Brush מברשת - + Polyline רב-קו - + Smudge טשטוש - + Pen עט - + Hand יד - + Pencil עפרון - + Bucket דלי - + Eyedropper טפטפת - + Eraser מחק - + New Bitmap Layer שכבת מפת ביטים חדשה - + New Vector Layer שכבת וקטורים חדשה - + New Sound Layer שכבת צליל חדשה - + New Camera Layer שכבת מצלמה חדשה - + Delete Current Layer מחק שכבה נוכחית - + About אודות - - + + Reset to default החזר לברירת המחדל - + MultiLayer Onion Skin עור בצל רב שכבתי - + Range תחום - + Pencil2D Website אתר Pencil2D - + Report a Bug דווח על באג - + Quick Reference Guide - + F1 - - + + + Animated GIF... + + + + + Next KeyFrame מסגרת מפתח הבאה - - + + Previous KeyFrame מסגרת מפתח הקודמת - + Timeline ציר זמן - + Options אפשרויות - + Color Wheel גלגל צבעים - + Color Palette טבלת צבעים - + Display Options אפשרויות תצוגה - + Flip X הפוך X - + Flip Y הפוך Y - + Move Frame Forward הזז מסגרת קדימה - + Move Frame Backward הזז מסגרת אחורה - + color palette:<br>use <b>(C)</b><br>toggle at cursor מסגרת צבעים: <br>השתמש ב<b>(C)</b><br>להחליף בסמן - + + Color inspector + + + + Lock Windows נעל חלונות - + Open Recent פתח מהאחרונים - + You have successfully cleared the list @@ -1520,215 +1662,263 @@ מחקת בהצלחה את הרשימה - - - - - + + + + + Could not open file + + + + + The file you have selected is a directory, so we are unable to open it. If you are are trying to open a project that uses the old structure, please open the file ending with .pcl, not the data folder. + + + + + The file you have selected does not exist, so we are unable to open it. Please check to make sure that you've entered the correct path and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + + + Warning אזהרה - - - Pencil cannot read this file. If you want to import images, use the command import. - Pencil2D לא הצליחה לקרוא את הקובץ. אם ברצונך לייבא תמונות, השתמש בפעולת הייבוא + + This program does not currently have permission to write to the file you have selected. Please make sure you have write permission for this file before attempting to save it. Alternatively, you can use the Save As... menu option to save to a writable location. + - + Opening document... פותח מסמך... - - - + + + + Abort בטל - + + An unknown error occurred while trying to load the file and we are not able to load your file. + + + + Saving document... שומר מסמך: - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>שגיאה ארעה ויתכן כי הקובץ שלך לא נשמר בהצלחה. אם אתה מאמין שזו תקלה ב-Pencil2D, אנא צור דו״ח תקלה בכתובת: <br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>אנא כלול את הפרטים הבאים בדיווח שלך: - + This animation has been modified. Do you want to save your changes? הנפשה זו נערכה ושונתה. האם ברצונך לשמור השינויים? - + The animation is not saved yet. Do you want to save now? ההנפשה לא נשמרה עדיין. האם ברצונך לשמור כעת? - + Never ask again AutoSave reminder button אל תשאל שוב - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. לא ניתן לייבא תמונה.<br><b>טיפ:</b> השתמש בשכבת מפת ביטים לייבוא תמונות - + Importing image sequence... - + + was unable to import - - + + Importing Animated GIF... + + + + + Undo Menu item text - + Redo Menu item text - + Stop עצור + + MoveTool + + + Layer switch + Windows title of layer switch pop-up. + + + + + You are about to switch layer, do you want to apply the transformation? + + + Object - + Black שחור - + Red אדום - + Dark Red אדום כהה - + Orange כתום - + Dark Orange כתום כהה - + Yellow צהוב - + Dark Yellow צהוב כהה - + Green ירוק - + Dark Green ירוק כהה - + Cyan תכלת ציאן - + Dark Cyan תכלת ציאן כהה - + Blue כחול - + Dark Blue כחול כהה - + White לבן - + Very Light Grey אפור בהיר מאד - + Light Grey אפור בהיר - + Grey אפור - + Dark Grey אפור כהה - + Light Skin צבע עור בהיר - + Light Skin - shade צבע עור בהיר - צללית - + Skin צבע עור - + Skin - shade צבע עור - צללית - + Dark Skin צבע עור כהה - + Dark Skin - shade צבע עור כהה - צללית @@ -1736,153 +1926,153 @@ PencilApplication - + Pencil2D is an animation/drawing software for Mac OS X, Windows, and Linux. It lets you create traditional hand-drawn animation (cartoon) using both bitmap and vector graphics. Pencil2D היא תוכנת ציור והנפשה עבור Mac OS X, Windows ו-Linux. היא מאפשרת לך ליצור הנפשות בסגנון מסורתי מצוייר ביד (cartoon) תוך שימוש בכלי מפת ביטים וכלים וקטוריים. - + Path to the input pencil file. נתיב לקובץ pencil קלט - - + + Render the file to <output_path> לכתוב את הקובץ אל <output_path> - - + + output_path output_path - + Name of the camera layer to use שם שכבת המצלמה לשימוש - + layer_name layer_name - + Width of the output frames רוחב מסגרות הפלט - - + + integer מספר שלם - + Height of the output frames גובה מסגרות הפלט - + The first frame you want to include in the exported movie המסגרת הראשונה שתיכלל בסרט המיוצא - - + + frame מסגרת - + The last frame you want to include in the exported movie. Can also be last or last-sound to automatically use the last frame containing animation or sound, respectively המסגרת האחרונה שאתה רוצה לכלול בסרט המיוצא. יכול להיות גם last או last-sound על מנת לבחור אוטומטית את המסגרת האחרונה המכילה אנימציה או צליל בהתאמה - + Render transparency when possible רשום שקיפות כשאפשר - + Warning: width value %1 is not an integer, ignoring. אזהרה: רוחב %1 הוא לא מספר שלם, מתעלם. - + Warning: height value %1 is not an integer, ignoring. אזהרה: גובה %1 הוא לא מספר שלם, מתעלם. - + Warning: start value %1 is not an integer, ignoring. אזהרה: ערך התחלתי %1 הוא לא מספר שלם, התוכנה תתעלם ממנו. - + Warning: start value must be at least 1, ignoring. אזהרה: ערך התחלתי חייב להיות לפחות 1, התוכנה תתעלם ממנו. - + Warning: end value %1 is not an integer, last or last-sound, ignoring. אזהרה: ערך סופי %1 הוא לא מספר שלם, last או last-sound, התוכנה תתעלם ממנו. - + Warning: end value %1 is smaller than start value %2, ignoring. אזהרה: ערך סופי %1 קטן מהערך ההתחלתי %2, התוכנה תתעלם ממנו. - + Error: No input file specified. שגיאה: לא נבחר קובץ קלט. - + Error: the input file at '%1' does not exist Command line error - + Error: the input path '%1' is not a file Command line error - + Warning: the specified camera layer %1 was not found, ignoring. אזהרה: שכבת המצלמה המצויינת %1 לא נמצאה. התוכנה תתעלם. - + Warning: Output format is not specified or unsupported. Using PNG. Command line warning - + Warning: Transparency is not currently supported in movie files Command line warning - + Exporting movie... Command line task progress - - + + Done. Command line task done - + Exporting image sequence... Command line task progress @@ -1924,12 +2114,12 @@ QApplication - + Checking environment... - + Done @@ -1937,42 +2127,47 @@ QObject - + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) - - Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp) - + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp); + + + + Everything ok. הכל בסדר. - + Ooops, Something went wrong. אופס, משהו השתבש. - + File doesn't exist. קובץ לא קיים. - + Cannot open file. לא יכול לפתוח קובץ. - + The file is not a valid xml document. הקובץ אינו מסמך xml תקין. - + The file is not valid pencil document. הקובץ אינו מסמך pencil תקין. @@ -3321,6 +3516,16 @@ Black + + + Could not open file + + + + + There was an error processing your file. This usually means that your project has been at least partially corrupted. You can try again with a newer version of Pencil2D, or you can try to use a backup file if you have one. If you contact us through one of our offical channels we may be able to help you. For reporting issues, the best places to reach us are: + + RecentFileMenu @@ -3338,60 +3543,60 @@ ScribbleArea - + Warning אזהרה - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). אתה מצייר על שכבה נסתרת! בחר בבקשה שכבה אחרת (או הפוך את השכבה הנוכחית לנראית) - + Delete Selection Undo Step: clear the selection area. מחק את הבחירה - - + + Clear Image Undo step text מחק תמונה - + There is a gap in your drawing (or maybe you have zoomed too much). יש רווח בציור שלך (או אולי אתה ברמת הגדלה גבוהה מדי) - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). מצטערים! זה לא תמיד עובד. אנא נסה שוב (הגדל מעט, לחץ במקום אחר...) <br> אם זה לא עובד, הגדל מעט ובדוק שהקווים מחוברים על ידי לחיצה על F1). - + Out of bound. מחוץ לגבולות. - + Could not find a closed path. לא ניתן למצא קו סגור. - + Could not find the root index. לא ניתן למצוא את אינדקס השורש. - + %1<br><br>Error: %2 %1<br><br> שגיאה: %2 - + Flood fill error שגיאה במילוי שטף @@ -3488,12 +3693,12 @@ - + Start התחל - + Stop עצור @@ -3577,18 +3782,18 @@ הפוך מסגרות תואמות - + Delete Layer Windows title of Delete current layer pop-up. מחק שכבה - + Please keep at least one camera layer in project אנא שמור לפחות שכבת מצלמה אחת בפרוייקט - + Are you sure you want to delete layer: האם אתה בטוח שברצונך למחוק שכבה: @@ -3596,12 +3801,12 @@ TimeLineCells - + Layer Properties מאפייני שכבה - + Layer name: שם שכבה: @@ -3678,6 +3883,16 @@ <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + + Playback + + + + + Show onion skin while playing + + Frame size diff --git a/translations/pencil_hu_HU.qm b/translations/pencil_hu_HU.qm index 212d8516cb4edcb52f817fb2d1316ffa474edfcc..b5ec67cd353ff03c44fb55b55c56e718cf9659ee 100644 GIT binary patch delta 2594 zcmXArdt6QV8pfZ!_gZVOeW#0D2Hh`Hx+u2_g``wMQYu|Uj@y`A4%3-7xttT?s53+k z(r}tj2qANEnID7}sNFjAr=o!Dw=xJ?pRU`t7yW`+MK#ecs>N8y~1DZ>g-| zr*eBY|GMj=%P#Mn&8j?oYYd=k0)otdyhCB;A3(G-U}^zk8v*x`K-@SWWe^a*9?;GK zCPf40Fd*py;9CPs^Wu6wkbI2yOUW~U*sL(%9N#?-MC3rQmYo2?_d__a5^(zf!Y5he zK?t>l{Jj~%=K|ny2SO|984KZx2QXl}La!+hu9qJAD^SJ{&|t=2XXv)2H2tS-Tn~c_~IZDVsaEWSORelEASt{J&J)q z-nTI|8{)=VV6X*ZIo}WAy0V*6Uh&h3TjVx%i)q=#Uyh!{3ldsGJ(wi}5O9Q1TLh^?FfYDE3 zz&fO?y#`pGDh%pSnEDhms+q`)d6;pUy^e81+MHk(a8Thy4KjXXoX8Mlyr~9yE?(P%1?bQtvq@@cw7s@SRoVCpv2?B~0I zun^V!JDXWih-!!XK31Ho(50_x*WAH?U%kSaeN|7MJOFw%svS~TfPJWXcx^7wdzQM$ zZyBucJgMGtF%-zqtN-11HY@Z}S4KwB?M@1N98uQ_5830N)%63~fu66`pS@%PLr$wt z+n(>4s{XQpEgKxBaONKM*B(qrmejW|s@d9S8oR}Afc~Jy@9h$LsY(+VspE9q){NaY zzzR$b(!|*|G(6JGUPuMTmueQ+)^_7GOH$VXS(`K~Y#Z4<(G+yC;)FEKhwG_~kAtSr zmXLjk=Fo~M9Km?ap*O5h*H82Pl04pjC}jCr+?h!RE-p(jj@3Gim>SPM?mmb z!kPkWH)pv{C=XxF$_s?@^fi>~ccG$^rV_qY=vp9DC)&(&NT^*iou2qXXew^tvgBb32o{Wz^jlyAs9vIaoo=bBDRENY{ zuaY?DNeUBQiVq(o0%_O9u3$NKha}%+;(f14`YuYU`%ZE?oigc-Xi44f)W zxOAQyhDouW4LnNENbz5CBbP>nY2&0RO*u^PpHjLDy%CozWhSp^20o-dP%M8nYnK->1xFdO57>kuBQirGo^ds zW2nqPh0aORqs8Cwxo;F^jFNte-OUXqYa_E+k=s3O{C`_`5^mLQYTeG0vPD}X&7kY` z+LKp#E{w6$wxv%6ChXVVeakpjKWF74qgZ<{PR|PMwLjO{Hk_l-xm-48@^`6Gw!6QK zN)*eEaf|pts*s1Le!&V?$>aN<0s38%6OO&$S|`tqp+bGWl}pkc*jfj9&ud4TFi&BR z*YaMGirSU@Nh=1Lt4(6U)2nsOd;FPLfbP*r#_gA->;BdD zT#jCxOvWeb9lopL{AV}meFsyr_^>}pJURO-L#OW&Kujo0XR zmhR=JbC$k&=Onglt^WH*>)5JV{j1AN%)Y~5Uhm4IywotL@EkufVFv%@e*q?rG6dMx zhEhY;bH>YDYM8%^)0MNqu%MUKcA+z@E~5ETnhYhH7c|FuL+Pja9IqgSUS>npO(R|X zzM-Zgo0UZvjvUc)jy(;RJ8WY#*>Fd12RQCAbbiW;eG`oGc$&_`+i3D&;_@`3OYI3B zM86v&_L+g93ykBgzXxa>j1#RPo0)MRV?tmD10FHv<=>-wKQSJaZUeJ+8c!WAqC%UD zXMGqrAlleaaE9agALDg;X%AjGU;zTD(_l3fwd8Wpua0dFtbYTQH z9_wU!>cvX*QD#kkH^=RbS+Mms^sRYWXD;wgs(Ek8GGO2ebK63G?Huo#pQdpP9bL>X zUb6+>OU*BBlp8H7cO6^eZnfxb(z>@;yj$sdzeNf&+AaQ_*MO)umgFuoGrncXYGK8r zt1Q_U`j9ymYeySR8)@0@&p-|N_6t{%y;JV8(O0VY%Xxz&Lr9SJDvv uVJW8}a?esT97GiIP#3Px(w6zy`IVK~`PFT;Uudk0b$-^bZsEw?A^!)zle~Zc delta 3238 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 YYhHP2sl6=!ulc%j2|ms05!+(^4V!Z diff --git a/translations/pencil_hu_HU.ts b/translations/pencil_hu_HU.ts index 192acaf2b..774ab3e15 100644 --- a/translations/pencil_hu_HU.ts +++ b/translations/pencil_hu_HU.ts @@ -13,13 +13,13 @@ - + Version: %1 Version Number in About Dialog - + Copy to clipboard Copy system info from About Dialog @@ -55,30 +55,30 @@ - + Exporting movie - + Finished. Open movie now? When movie export done. - - - - + + + + Layer Properties Réteg tulajdonságai - - - - + + + + Layer name: Réteg neve: @@ -88,58 +88,63 @@ Egy hang már el lett helyezve ezen a képkockán. Válasszon másik pozíciót vagy réteget! - + + Finished. Open file location? + + + + Exporting image sequence... - + Abort - + Warning - + Unable to export image. - + Bitmap Layer Bitkép réteg - + Vector Layer Vektor réteg - + Camera Layer Kamera réteg - + Sound Layer Hang réteg - + Delete Layer Windows title of Delete current layer pop-up. - + Are you sure you want to delete layer: - + Please keep at least one camera layer in project text when failed to delete camera layer @@ -148,57 +153,57 @@ BaseTool - + Pencil Ceruza - + Eraser Radír - + Select Kijelölés - + Move Mozgatás - + Hand Kéz - + Smudge Maszatolás - + Pen Toll - + Polyline Vonallánc - + Bucket Vödör - + Eyedropper Szemcseppentő - + Brush Ecset @@ -224,69 +229,55 @@ ColorBox - - Color Wheel - Color Wheel's window title + + Color Box + Color Box window title ColorInspector - + HSV HSV - + RGB RGB - - - Red - Vörös - - - - - Green - Zöld - - - - - Blue - Kék + + R + - - - - Alpha - Alfa + + A + - - Hue - Színárnyalat + + G + - - Saturation - Telítettség + + B + - - Value - Érték + + Color Inspector + Window title of color inspector + ColorPalette - + Color Palette Window title of color palette. @@ -302,57 +293,57 @@ Szín eltávolítása - - ... - ... + + Native color dialog window + - + List Mode - + Show palette as a list - + Grid Mode - + Show palette as icons - + Small swatch - + Sets swatch size to: 16x16px - + Medium Swatch - + Sets swatch size to: 26x26px - + Large Swatch - + Sets swatch size to: 36x36px @@ -360,11 +351,60 @@ ColorPaletteWidget - - + + Add + + + + + Replace + + + + + Remove + + + + + Colour name Szín neve + + + The color(s) you are about to delete are currently being used by one or multiple strokes. + + + + + Cancel + + + + + Delete + + + + + Palette Restriction + + + + + The palette requires at least one swatch to remain functional + + + + + ColorWheel + + + Color Wheel + Color Wheel's window title + + DisplayOption @@ -446,19 +486,19 @@ Editor - - + + Paste Beillesztés - + Remove frame - - + + Import Image Kép importálása @@ -484,12 +524,12 @@ ExportImageDialog - + Export image sequence Képsorozat exportálása - + Export image Kép exportálása @@ -531,11 +571,51 @@ Transparency Átlátszóság + + + Range + + + + + The last frame you want to include in the exported movie + + + + + End Frame + + + + + The first frame you want to include in the exported movie + + + + + Start Frame + + + + + <html><head/><body><p>End frame is set to last paintable keyframe (Useful when you only want to export to the last animated frame)</p></body></html> + + + + + To the end of sound clips + + ExportMovieDialog - + + Export Animated GIF + + + + Export Movie Videó exportálása @@ -627,67 +707,83 @@ + Import Animated GIF + + + + Import movie Videó importálása - + Import sound Hang importálása - + Import palette Paletta importálása - + Save animation Animáció mentése - + Export image Kép exportálása - + Export image sequence Képsorozat exportálása - + + Export Animated GIF + + + + Export movie Videó exportálása - + Export sound Hang exportálása - + Export palette Paletta exportálása - + + + Animated GIF (*.gif) + + + + Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) Hangok (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) - - - Palette (*.xml) - Paletta (*.xml) + + + Pencil2D Palette (*.xml);; Gimp Palette (*.gpl) + - - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) + + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng) - + MyAnimation.pclx @@ -695,52 +791,72 @@ FileManager - - - + + + Could not open file + + + + + The file does not exist, so we are unable to open it. Please check to make sure the path is correct and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + Invalid Save Path Érvénytelen mentési útvonal - + The path ("%1") points to a directory. - + The directory ("%1") does not exist. - + The path ("%1") is not writable. - - + + Cannot Create Data Directory Az adatkönyvtár nem hozható létre - + Failed to create directory "%1". Please make sure you have sufficient permissions. - + "%1" is a file. Please delete the file and try again. - - + + Miniz Error + + + + Internal Error Belső hiba - - + + An internal error occurred. Your file may not be saved successfully. @@ -818,87 +934,97 @@ Rács - + Czech Cseh - + Danish Dán - + English Angol - + German Német - + + Estonian + + + + Spanish Spanyol - + French Francia - + Hebrew - + Hungarian Magyar - + Indonesian - + Italian Olasz - + Japanese Japán - + + Polish + + + + Portuguese - Portugal - + Portuguese - Brazil Portugál - Brazil - + Russian Orosz - + Slovenian - + Vietnamese - + Chinese - Taiwan Kínai - Taiwan @@ -943,12 +1069,12 @@ Nagy pontosságú pozicionálás táblagépen - + Restart Required Újraindítás szükséges - + The language change will take effect after a restart of Pencil2D A nyelv megváltoztatása csak a Pencil2D újraindítása után érvényesül @@ -974,7 +1100,12 @@ ImportImageSeqDialog - + + Import Animated GIF + + + + Import image sequence Képsorozat importálása @@ -998,7 +1129,7 @@ LayerBitmap - + Bitmap Layer Bitkép réteg @@ -1014,7 +1145,7 @@ LayerSound - + Sound Layer Hang réteg @@ -1045,687 +1176,746 @@ Importálás - + Export Exportálás - + Edit Szerkesztés - + Selection Kijelölés - + View Nézet - + Onion Skin Képfólia - + Animation Animáció - - + + Tools Eszközök - + Layer Réteg - - + + Help Súgó - + Windows Ablakok - + New Új - + Open Megnyitás - + Save Mentés - + Save As .. Mentés másként .. - + Exit Kilépés - - + + Image Sequence... Képsorozat... - - + + Image... Kép... - - + + Movie... Videó... - - + + Palette... Paletta... - + Sound... Hang... - + Undo Visszavonás - + Redo Újra - + Cut Kivágás - + Copy Másolás - + Paste Beillesztés - + Crop Csonkítás - + Crop To Selection Csonkítás kijelölésre - + Select All Minden kijelölése - + Deselect All Kijelölés megszüntetése - - + + Clear Frame Képkocka kiürítése - + Preferences Beállítások - + Reset Windows Ablakok visszaállítása - + Zoom In Nagyítás - + Zoom Out Kicsinyítés - + Rotate Clockwise Forgatás jobbra - + Rotate AntiClosewise Forgatás balra - + Reset Zoom/Rotate Nagyítás/Elforgatás visszaállítása - + Horizontal Flip Vízszintes tükrözés - + Vertical Flip Függőleges tükrözés - + Preview Előnézet - + Grid Rács - + Previous Előző - + Show previous onion skin Előző képfólia megjelenítése - + Next Következő - + Show next onion skin Következő képfólia megjelenítése - - + + Play Lejátszás - + Loop Ismétlés - + Next Frame Következő képkocka - + Previous Frame Előző képkocka - + Extend Frame Képkocka kiterjesztése - + Add Frame Képkocka hozzáadása - + Duplicate Frame Képkocka kétszerezése - + Remove Frame Képkocka eltávolítása - + Move Mozgatás - + Select Kijelölés - + Brush Ecset - + Polyline Vonallánc - + Smudge Maszatolás - + Pen Toll - + Hand Kéz - + Pencil Ceruza - + Bucket Vödör - + Eyedropper Szemcseppentő - + Eraser Radír - + New Bitmap Layer Új bitkép réteg - + New Vector Layer Új vektor réteg - + New Sound Layer Új hang réteg - + New Camera Layer Új kamera réteg - + Delete Current Layer Aktuális réteg törlése - + About Névjegy - - + + Reset to default Alapértékek visszaállítása - + MultiLayer Onion Skin Többrétegű képfóliák - + Range Tartomány - + Pencil2D Website - + Report a Bug - + Quick Reference Guide - + F1 - - + + + Animated GIF... + + + + + Next KeyFrame Következő kulcsképkocka - - + + Previous KeyFrame Előző kulcsképkocka - + Timeline Idővonal - + Options Beállítások - + Color Wheel Színkerék - + Color Palette Színpaletta - + Display Options Megjelenítés beállításai - + Flip X X tükrözés - + Flip Y Y tükrözés - + Move Frame Forward Képkocka mozgatása előre - + Move Frame Backward Képkocka mozgatása hátra - + color palette:<br>use <b>(C)</b><br>toggle at cursor Színpaletta:<br><b>(C)</b>lenyomásával<br>átváltás a kurzornál - + + Color inspector + + + + Lock Windows - + Open Recent Legutóbbi megnyitása - + You have successfully cleared the list - - - - - + + + + + Could not open file + + + + + The file you have selected is a directory, so we are unable to open it. If you are are trying to open a project that uses the old structure, please open the file ending with .pcl, not the data folder. + + + + + The file you have selected does not exist, so we are unable to open it. Please check to make sure that you've entered the correct path and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + + + Warning Figyelmeztetés - - - Pencil cannot read this file. If you want to import images, use the command import. - A Pencil nem tudja olvasni ezt a fájlt. Képek beemeléséhez az "Importálás" művelet használható. + + This program does not currently have permission to write to the file you have selected. Please make sure you have write permission for this file before attempting to save it. Alternatively, you can use the Save As... menu option to save to a writable location. + - + Opening document... Dokumentum megnyitása... - - - + + + + Abort Névjegy - + + An unknown error occurred while trying to load the file and we are not able to load your file. + + + + Saving document... Dokumentum mentése... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: - + This animation has been modified. Do you want to save your changes? Ez az animáció meg lett változtatva. Szeretné menteni a változásokat? - + The animation is not saved yet. Do you want to save now? - + Never ask again AutoSave reminder button - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. A kép nem importálható.<br><b>TIPP:</b> Képek importálásához bitkép réteget kell használni. - + Importing image sequence... - + + was unable to import - - + + Importing Animated GIF... + + + + + Undo Menu item text - + Redo Menu item text - + Stop Megállítás + + MoveTool + + + Layer switch + Windows title of layer switch pop-up. + + + + + You are about to switch layer, do you want to apply the transformation? + + + Object - + Black Fekete - + Red Piros - + Dark Red Sötét vörös - + Orange Narancs - + Dark Orange Sötét narancs - + Yellow Sárga - + Dark Yellow Sötét sárga - + Green Zöld - + Dark Green Sötét zöld - + Cyan Cián - + Dark Cyan Sötét cián - + Blue Kék - + Dark Blue Sötét kék - + White Fehér - + Very Light Grey Halvány szürke - + Light Grey Világos szürke - + Grey Szürke - + Dark Grey Sötét szürke - + Light Skin Világos bőr - + Light Skin - shade Világos bőr - árnyék - + Skin Bőr - + Skin - shade Bőr - árnyék - + Dark Skin Sötét bőr - + Dark Skin - shade Sötét bőr - árnyék @@ -1733,153 +1923,153 @@ PencilApplication - + Pencil2D is an animation/drawing software for Mac OS X, Windows, and Linux. It lets you create traditional hand-drawn animation (cartoon) using both bitmap and vector graphics. A Pencil2D egy animáció készítő/rajzoló szoftver Mac OS X, Windows és Linux rendszerekre. Hagyományos, kézzel rajzolt animációk készítésére alkalmas bitképek és vektorgrafika használatával. - + Path to the input pencil file. A bemeneti "pencil" fájl útvonala. - - + + Render the file to <output_path> Fájl leképezése ide: <kimeneti_útvonal> - - + + output_path kimeneti_útvonal - + Name of the camera layer to use - + layer_name - + Width of the output frames A kimeneti képkockák szélessége - - + + integer egész szám - + Height of the output frames A kimeneti képkockák magassága - + The first frame you want to include in the exported movie - - + + frame - + The last frame you want to include in the exported movie. Can also be last or last-sound to automatically use the last frame containing animation or sound, respectively - + Render transparency when possible Átlátszóság leképezése amikor lehetséges - + Warning: width value %1 is not an integer, ignoring. Figyelmeztetés: a szélesség értéke %1 nem egész szám, ezért figyelmen kívül lesz hagyva. - + Warning: height value %1 is not an integer, ignoring. Figyelmeztetés: a magasság értéke %1 nem egész szám, ezért figyelmen kívül lesz hagyva. - + Warning: start value %1 is not an integer, ignoring. - + Warning: start value must be at least 1, ignoring. - + Warning: end value %1 is not an integer, last or last-sound, ignoring. - + Warning: end value %1 is smaller than start value %2, ignoring. - + Error: No input file specified. Hiba: Nincs bemeneti fájl megadva. - + Error: the input file at '%1' does not exist Command line error - + Error: the input path '%1' is not a file Command line error - + Warning: the specified camera layer %1 was not found, ignoring. - + Warning: Output format is not specified or unsupported. Using PNG. Command line warning - + Warning: Transparency is not currently supported in movie files Command line warning - + Exporting movie... Command line task progress - - + + Done. Command line task done - + Exporting image sequence... Command line task progress @@ -1921,12 +2111,12 @@ QApplication - + Checking environment... - + Done @@ -1934,42 +2124,47 @@ QObject - + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) - - Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp) - + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp); + + + + Everything ok. Minden rendben. - + Ooops, Something went wrong. Hoppá, valami rosszul sikerült. - + File doesn't exist. A fájl nem létezik. - + Cannot open file. A fájl nem nyitható meg. - + The file is not a valid xml document. Ez a fájl nem egy érvényes XML dokumentum. - + The file is not valid pencil document. Ez a fájl nem egy érvényes Pencil dokumentum. @@ -3318,6 +3513,16 @@ Black + + + Could not open file + + + + + There was an error processing your file. This usually means that your project has been at least partially corrupted. You can try again with a newer version of Pencil2D, or you can try to use a backup file if you have one. If you contact us through one of our offical channels we may be able to help you. For reporting issues, the best places to reach us are: + + RecentFileMenu @@ -3335,60 +3540,60 @@ ScribbleArea - + Warning Figyelmeztetés - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Most egy láthatatlan rétegre rajzol! Válasszon egy másik réteget (vagy tegye láthatóvá az aktuális réteget). - + Delete Selection Undo Step: clear the selection area. - - + + Clear Image Undo step text - + There is a gap in your drawing (or maybe you have zoomed too much). Egy rés van a rajzon (vagy túlságosan fel van nagyítva). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). Elnézést! Ez nem mindig működik. Próbáld újra (egy kis nagyítással vagy máshová kattintva...)<br>Ha nem működik nagyíts egy kicsit és az F1 lenyomásával ellenőrizd, hogy az útvonalak összeérnek-e.). - + Out of bound. Tartományon kívül. - + Could not find a closed path. Nem található zárt útvonal. - + Could not find the root index. Nem található a gyökér index. - + %1<br><br>Error: %2 %1<br><br>Hiba: %2 - + Flood fill error Kitöltési hiba @@ -3485,12 +3690,12 @@ - + Start Indítás - + Stop Megállítás @@ -3574,18 +3779,18 @@ Érintkező kulcsképkocka be- és kikapcsolása - + Delete Layer Windows title of Delete current layer pop-up. - + Please keep at least one camera layer in project - + Are you sure you want to delete layer: Biztosan törölni akarja a következő réteget: @@ -3593,12 +3798,12 @@ TimeLineCells - + Layer Properties - + Layer name: @@ -3675,6 +3880,16 @@ <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + + Playback + + + + + Show onion skin while playing + + Frame size diff --git a/translations/pencil_id.qm b/translations/pencil_id.qm index a5c49f9cfa692b37911f775e990746cd13962b3b..c0ad1170192143216055356b999128440cec07b7 100644 GIT binary patch delta 964 zcmX9+e@s<%6#u;Y>)reAeecoZ0rL2f{CGZNPGF!>=@w=p2Va!7mznKB7TQo6Y5{DOA?|BJ_AN2zE?ItG9qRj7SZO;;cLqzo)Uiab^-F3Fm+1+;^Rcu(Ih}UBBo_)fL<&<{oWLnu8R2~Uad~7 z458zpSXJ~P>ko<5AwFllSQ9@H0K!zUyZHqwo)j-V;)F_{_-j=Kt-daKn;SW~Ps%a! z0O4(^ZCfn|oieX44_ zPLv*~+h>B@fzYq+iu;}o|55jTwM_J>=T{>rwc14cpxPmi(6bHdL>E1dE>zcUpQ3fA zG^B4Cxo&gc?*@`$Y};12tAzEozi-#@U9O&5!^_vw z^_^WZckslxURy^+o<6-v_&Cw7U0R(j4zcbHkvnncxp41=NR|GiM-3Wu^{s$_J(~?gE;rLauI^j)m2j`B1v1(jm zRH(S>j3A3TSmsvfjMU*Kfy1O0Rts9A#+0$38CDyL%*sB;6}6Us+&%kzzt8jie4gj? zwiFMQye#`}0tK6aXaMCO0YV%&|0#eU1ox#4SZ(57ooaTxHa%&@OH0z~$~ z{$?k@R)sLB14Rc0X^?r8?td51-bVTJ6M()ugwYFl>=-=|Q-jB!T2K1M5GGY(`#v%t z975$Uq>GwB<*j3Y;h7LxYq6uG1c;qfeb6ugACg8@^Yb%++{(!1)F7N?vQAW!!wlxF zNCnW%FoEnXfV4Y=hLg;h*m1x(#hhL2rp9XKT##ohXNJ#TCx_L{C$=6yEizM|GF11n zraei3CctK7Yv{c$_P%GQ0M!y(kiEr6&W2c5ut8V?TVK&if@!uX_+Z!w+Z=2Zp3C<7 zH<1G~+jolwRL`;B)$ar%?40GL?1F5lXn78*MvJc$WL3(MA!jZso52zCh6`Jl9BdL)Q<}rE@jfWL>e!`GYI83~l zOG5GJ4%&c87->9C0X`)BnBNUpzEXFnX;bkj>gfV4`AQdcPY`mK#n?nUZ7Te8@xke9 zWblNT8#4&p^_*Dr;dL6IPkejHOdC2KLcvA6kv1fK2AxaWXE*htRkdU#C%5g)*tk34hy|&)Bn0=!zucP))^YE z(YI+)8y1&_=)qTvDl0kEs*TQz71Y>bd_9e7Q>F3Z`WzbUY7On_c>g5(0`HSi3^%Ib zL_Esq--9|h#b7sqe$pnl%k7CT+odQjHPzyBo#Sp&vB3&Cs3Aqe3ZKhyH7G%%VVP*J ztKXwkdEK66x)zTReK$4vN8sc0Jc?3xXGtLx>fpq#l^$%dQhg`B30sL@^|yv}bt^jU zHmA42A8v&5VSDBra;}r5M*D6=`Tf hEuEySJY#e?U5eMM#IH?FYpQjn_ye-s?~*&@KLHWIOo9La diff --git a/translations/pencil_id.ts b/translations/pencil_id.ts index a1c826936..b2ccb0d6a 100644 --- a/translations/pencil_id.ts +++ b/translations/pencil_id.ts @@ -13,13 +13,13 @@ - + Version: %1 Version Number in About Dialog - + Copy to clipboard Copy system info from About Dialog @@ -55,30 +55,30 @@ - + Exporting movie - + Finished. Open movie now? When movie export done. - - - - + + + + Layer Properties - - - - + + + + Layer name: Nama layer @@ -88,58 +88,63 @@ Klip suara telah tersedia dalam frame ini! Mohon pilih frame yang lain atau layer - + + Finished. Open file location? + + + + Exporting image sequence... Mengekspor gambar berurutan - + Abort Gagalkan - + Warning Peringatan - + Unable to export image. Tidak mampu mengekspor gambar. - + Bitmap Layer - + Vector Layer - + Camera Layer - + Sound Layer - + Delete Layer Windows title of Delete current layer pop-up. - + Are you sure you want to delete layer: - + Please keep at least one camera layer in project text when failed to delete camera layer @@ -148,57 +153,57 @@ BaseTool - + Pencil Pensil - + Eraser Penghapus - + Select Pilih - + Move Pindah - + Hand Tangan - + Smudge - + Pen - + Polyline - + Bucket Ember - + Eyedropper Tetes mata - + Brush Kuas @@ -224,69 +229,55 @@ ColorBox - - Color Wheel - Color Wheel's window title - Roda Warna + + Color Box + Color Box window title + ColorInspector - + HSV - + RGB - - - Red - Merah - - - - - Green - Hijau - - - - - Blue - Biru + + R + - - - - Alpha + + A - - Hue + + G - - Saturation - Kecerahan + + B + - - Value - Nilai + + Color Inspector + Window title of color inspector + ColorPalette - + Color Palette Window title of color palette. @@ -302,57 +293,57 @@ Buang Warna - - ... + + Native color dialog window - + List Mode - + Show palette as a list - + Grid Mode - + Show palette as icons - + Small swatch - + Sets swatch size to: 16x16px - + Medium Swatch - + Sets swatch size to: 26x26px - + Large Swatch - + Sets swatch size to: 36x36px @@ -360,11 +351,60 @@ ColorPaletteWidget - - + + Add + + + + + Replace + + + + + Remove + + + + + Colour name Nama warna + + + The color(s) you are about to delete are currently being used by one or multiple strokes. + + + + + Cancel + + + + + Delete + + + + + Palette Restriction + + + + + The palette requires at least one swatch to remain functional + + + + + ColorWheel + + + Color Wheel + Color Wheel's window title + + DisplayOption @@ -446,19 +486,19 @@ Editor - - + + Paste Tempel - + Remove frame - - + + Import Image Impor Gambar @@ -484,12 +524,12 @@ ExportImageDialog - + Export image sequence Ekspor gambar berurutan - + Export image Ekspor gambar @@ -531,11 +571,51 @@ Transparency Transparansi + + + Range + + + + + The last frame you want to include in the exported movie + + + + + End Frame + + + + + The first frame you want to include in the exported movie + + + + + Start Frame + + + + + <html><head/><body><p>End frame is set to last paintable keyframe (Useful when you only want to export to the last animated frame)</p></body></html> + + + + + To the end of sound clips + + ExportMovieDialog - + + Export Animated GIF + + + + Export Movie Ekspor Film @@ -627,67 +707,83 @@ + Import Animated GIF + + + + Import movie Impor film - + Import sound Impor suara - + Import palette Impor palet - + Save animation Simpan animasi - + Export image Ekspor gambar - + Export image sequence Ekspor gambar berurutan - + + Export Animated GIF + + + + Export movie Ekspor Film - + Export sound Ekspor suara - + Export palette Ekspor palet - + + + Animated GIF (*.gif) + + + + Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) Suara (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) - - - Palette (*.xml) - Palet (*.xml) + + + Pencil2D Palette (*.xml);; Gimp Palette (*.gpl) + - - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) + + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng) - + MyAnimation.pclx @@ -695,52 +791,72 @@ FileManager - - - + + + Could not open file + + + + + The file does not exist, so we are unable to open it. Please check to make sure the path is correct and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + Invalid Save Path - + The path ("%1") points to a directory. - + The directory ("%1") does not exist. - + The path ("%1") is not writable. - - + + Cannot Create Data Directory - + Failed to create directory "%1". Please make sure you have sufficient permissions. - + "%1" is a file. Please delete the file and try again. - - + + Miniz Error + + + + Internal Error Kerusakan Internal - - + + An internal error occurred. Your file may not be saved successfully. @@ -818,87 +934,97 @@ Garis kotak - + Czech - + Danish - + English - + German - + + Estonian + + + + Spanish - + French - + Hebrew - + Hungarian - + Indonesian - + Italian - + Japanese - + + Polish + + + + Portuguese - Portugal - + Portuguese - Brazil - + Russian - + Slovenian - + Vietnamese - + Chinese - Taiwan @@ -943,12 +1069,12 @@ Tablet dengan posisi resolusi tinggi - + Restart Required Membutuhkan dijalankan ulang - + The language change will take effect after a restart of Pencil2D Bahasa akan diganti setelah Pencil2D dijalankan ulang @@ -974,7 +1100,12 @@ ImportImageSeqDialog - + + Import Animated GIF + + + + Import image sequence @@ -998,7 +1129,7 @@ LayerBitmap - + Bitmap Layer @@ -1014,7 +1145,7 @@ LayerSound - + Sound Layer @@ -1045,686 +1176,745 @@ Impor - + Export Ekspor - + Edit - + Selection Seleksi - + View - + Onion Skin Kulit Bawang - + Animation Animasi - - + + Tools Peralatan - + Layer - - + + Help Bantuan - + Windows - + New - + Open - + Save - + Save As .. - + Exit - - + + Image Sequence... - - + + Image... - - + + Movie... - - + + Palette... Palet... - + Sound... Suara... - + Undo - + Redo - + Cut - + Copy - + Paste - + Crop - + Crop To Selection - + Select All - + Deselect All - - + + Clear Frame - + Preferences - + Reset Windows - + Zoom In - + Zoom Out - + Rotate Clockwise - + Rotate AntiClosewise - + Reset Zoom/Rotate - + Horizontal Flip - + Vertical Flip - + Preview - + Grid - + Previous - + Show previous onion skin - + Next - + Show next onion skin - - + + Play - + Loop - + Next Frame - + Previous Frame - + Extend Frame - + Add Frame - + Duplicate Frame - + Remove Frame - + Move - + Select - + Brush - + Polyline - + Smudge - + Pen - + Hand - + Pencil - + Bucket - + Eyedropper - + Eraser - + New Bitmap Layer - + New Vector Layer - + New Sound Layer - + New Camera Layer - + Delete Current Layer - + About - - + + Reset to default - + MultiLayer Onion Skin - + Range - + Pencil2D Website - + Report a Bug - + Quick Reference Guide - + F1 - - + + + Animated GIF... + + + + + Next KeyFrame - - + + Previous KeyFrame - + Timeline - + Options - + Color Wheel - + Color Palette - + Display Options - + Flip X - + Flip Y - + Move Frame Forward - + Move Frame Backward - + color palette:<br>use <b>(C)</b><br>toggle at cursor - + + Color inspector + + + + Lock Windows - + Open Recent - + You have successfully cleared the list - - - - - + + + + + Could not open file + + + + + The file you have selected is a directory, so we are unable to open it. If you are are trying to open a project that uses the old structure, please open the file ending with .pcl, not the data folder. + + + + + The file you have selected does not exist, so we are unable to open it. Please check to make sure that you've entered the correct path and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + + + Warning - - - Pencil cannot read this file. If you want to import images, use the command import. + + This program does not currently have permission to write to the file you have selected. Please make sure you have write permission for this file before attempting to save it. Alternatively, you can use the Save As... menu option to save to a writable location. - + Opening document... - - - + + + + Abort - + + An unknown error occurred while trying to load the file and we are not able to load your file. + + + + Saving document... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: - + This animation has been modified. Do you want to save your changes? - + The animation is not saved yet. Do you want to save now? - + Never ask again AutoSave reminder button - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. - + Importing image sequence... - + + was unable to import - - + + Importing Animated GIF... + + + + + Undo Menu item text - + Redo Menu item text - + Stop + + MoveTool + + + Layer switch + Windows title of layer switch pop-up. + + + + + You are about to switch layer, do you want to apply the transformation? + + + Object - + Black - + Red - + Dark Red - + Orange - + Dark Orange - + Yellow - + Dark Yellow - + Green - + Dark Green - + Cyan - + Dark Cyan - + Blue - + Dark Blue - + White - + Very Light Grey - + Light Grey - + Grey - + Dark Grey - + Light Skin - + Light Skin - shade - + Skin - + Skin - shade - + Dark Skin - + Dark Skin - shade @@ -1732,153 +1922,153 @@ PencilApplication - + Pencil2D is an animation/drawing software for Mac OS X, Windows, and Linux. It lets you create traditional hand-drawn animation (cartoon) using both bitmap and vector graphics. - + Path to the input pencil file. - - + + Render the file to <output_path> - - + + output_path - + Name of the camera layer to use - + layer_name - + Width of the output frames - - + + integer - + Height of the output frames - + The first frame you want to include in the exported movie - - + + frame - + The last frame you want to include in the exported movie. Can also be last or last-sound to automatically use the last frame containing animation or sound, respectively - + Render transparency when possible - + Warning: width value %1 is not an integer, ignoring. - + Warning: height value %1 is not an integer, ignoring. - + Warning: start value %1 is not an integer, ignoring. - + Warning: start value must be at least 1, ignoring. - + Warning: end value %1 is not an integer, last or last-sound, ignoring. - + Warning: end value %1 is smaller than start value %2, ignoring. - + Error: No input file specified. - + Error: the input file at '%1' does not exist Command line error - + Error: the input path '%1' is not a file Command line error - + Warning: the specified camera layer %1 was not found, ignoring. - + Warning: Output format is not specified or unsupported. Using PNG. Command line warning - + Warning: Transparency is not currently supported in movie files Command line warning - + Exporting movie... Command line task progress - - + + Done. Command line task done - + Exporting image sequence... Command line task progress @@ -1920,12 +2110,12 @@ QApplication - + Checking environment... - + Done @@ -1933,42 +2123,47 @@ QObject - + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) - - Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp) - + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp); + + + + Everything ok. - + Ooops, Something went wrong. - + File doesn't exist. - + Cannot open file. - + The file is not a valid xml document. - + The file is not valid pencil document. @@ -3317,6 +3512,16 @@ Black Hitam + + + Could not open file + + + + + There was an error processing your file. This usually means that your project has been at least partially corrupted. You can try again with a newer version of Pencil2D, or you can try to use a backup file if you have one. If you contact us through one of our offical channels we may be able to help you. For reporting issues, the best places to reach us are: + + RecentFileMenu @@ -3334,60 +3539,60 @@ ScribbleArea - + Warning - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). - + Delete Selection Undo Step: clear the selection area. - - + + Clear Image Undo step text - + There is a gap in your drawing (or maybe you have zoomed too much). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). - + Out of bound. - + Could not find a closed path. - + Could not find the root index. - + %1<br><br>Error: %2 - + Flood fill error @@ -3484,12 +3689,12 @@ - + Start Mulai - + Stop Hentikan @@ -3573,18 +3778,18 @@ - + Delete Layer Windows title of Delete current layer pop-up. - + Please keep at least one camera layer in project - + Are you sure you want to delete layer: Anda yakin ingin membuang layer: @@ -3592,12 +3797,12 @@ TimeLineCells - + Layer Properties - + Layer name: @@ -3674,6 +3879,16 @@ <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + + Playback + + + + + Show onion skin while playing + + Frame size diff --git a/translations/pencil_it.qm b/translations/pencil_it.qm index 5de283bc2b4efdf2432967920599abe0c9306fb3..08d21d3bab9843fa94d0a10749d774c63844006d 100644 GIT binary patch delta 2360 zcmXYzdsGzX8OER8otd58o!wQyTNIU>fLsMHfXJ-~f`FhXil#kS)1ZzuW6~rSN zV;b71foeeG!B|Bg#-NE+#Bec4QqiEIQIV2pLgEP=^aQcbcJkM6_M7?M>+^o!e%z$_ z^rGf%CmVoi7QnDfW!fKs#74j+4oHdx=5GO#cL1^%klqA%j{%m{@^?CU9*{Px^os$O zegs6^hfsPNn5{rK`e$HrF@$5UkaZBM3%EWF!Z`tOy#k?~w7CU9_|gM#_keI?51qR~ z_?C_(SC#IAWD78-mh1<{SX8=ShVXqL;Nb>wCLK&UsWM3qG43+=&sXU=6=D+iO|65t zWG?NeL41vY`!qt#ErAVw75{%g(oBfEtAT(M5cktSkR!y3VIa}~@i-k!zojyH1jI&u z7qS#$J1Y{>jew|LAR`okseb`da}n|_D?0HJ!hHsSnKde7a#W^;|H@W7S^tG`h=2F* z+~7ktlD|cQXBiOo5DDe`0WnSGBu|y;L6~pi`lxs$YcB!Oc}UsKjOOe_+LvpAl;c>q zw}BPO$C6zi0Lnd;epW2qew_)vp)x5OnN>DAPP&WC&)C!GFf4y9m=O=Ej5(ol(KEdK z6AeW+;pJbd0BaFeFJ8+Zb;IQ^_SU~{hogl5eFJDqQ9%GU(3SBq4pj?x@{d=l{bTyrk{8z5nW z=7%31a^qfYNOcx4+DlvLn+Le<)$VNxW9GND|9t6Hz*3{Fh@K0W+qKm~4-i7;T{8 zHM%6bVda1>e~1~(9n@{v!3?JubOjSTSec8u6Pp(TabN3B{K8Tjx^=f-&*u9sL7Kpd z#Rm)e6Q_Ym?+Rmfc5y1gY=TGWF2He>5U(Tx+J0ffXaC?RE)t6Jhk@AN3Hw(RG2_cZ zSp~Hr7O9-HLa0i$Yv2u`x+sI0mI=)z4SauArRxi!eG^;jwp_TTUCQZ7BRS&kyM@jR z=h>Plp|g?uN864FU8MzlxFtM(-p>p)qF~=RC0^859Hll6h;E7qghz{BL#064eldAt zH%l5IuCa?LqE=j=FvM}IROy!^z8T6&YD2_wpCf=?RvGl8c;qa<*UwQoJy-l7tdH{_ zHCa6FwH@%hDAt}kLlq~A7nZvMnw#RCr|F#2pH#;EP3(D?%EPE#913PhBY&1O0xRV6 zmZY;YLzLwE41DY-l5vO?G#-@3e3ZhTe<)2}NqY++d36_3Yg<)1@00u#Z_fYthf=6J z4Om=MTEnHVtJ7&9Qi}4K!OXr=>G!oX?~BV6=VK{xN&_{sRZ6}{M-$6bCeM);Hm_!Y zCDIBPY9m%FtxWBp+Am1i?|;X@T%~+T2Ta(g(s#eKWm*&G-^o#WZ{RmT%v7my(@7pQ zl~Vf-M(*V;eN}donf^(-dxpIa9F!h}$FMS?DknUbdN=-uM{=yn1y%kznOTM$=X@R*cT7&H9iX`Sz zHLgi*=6AWqlHo-Z`;Ws0rjG&npptt%%NuQsh8O{Nc;wiQw{^N*SK=vV=#4AVRH zxg5t{m2Tgd4tFUOqo?WADLu#biK(sAF8WNH>7LO67};X#t7m3j>l8VTB5@t1m^~P& zVWcwd5D%h7vlW->(>yqOl&DGzHDXj^Z{z^FSS2N}ljEDCWamEMogpYS(p_H3S;{9T z3mMpY<=@`4>)WO@j2d(4f^ z;k;X_%uhU-fXQIdGu&s%>&pUOim_b#11}i|N6VAt9Gj8x zmVsw1y+@j5&`!g4tH#|xL-(vkdr4iItX}ODsrRtT1(&S;eb<4gL)Ilj7OKA3`pQ*i z95KPVs)?1HbH{4yyhbq^t^5297>f}Ht!FxW_`x!3Q!ovUI?9G;l+~>^_{ycu4!)%} R2j99ajxHW`^`Xzb{|6Led4B)^ delta 2920 zcmZve2~>2kbMKw)&WtER?jxHhIv|LkxB#Lo$|i`27)~%Kg$xahOPZ7G%S!Du zxx6wHQ`3A(?rWxKxxAFhC48ArQ=gVfnR>J*>HChi<9X+ucjjK zs<-_;X+Uo?VE9#GelU=61PJ;87?A>GMFN@g0o^Vjdk1+1$Uh47*bEeG1@!I61AsJD zq3t|SxSi)i6()J1@dNK~LGb$I3l$DL0AbxUz!TIF!iMoQm;s@FCNS^{gna@K@&bfL zAHRg~btn+JAHunXbm}aG8+1$xQW&;~JPst5k@tY-)+!7uhHxti2-^#>FZG8HRhYF0 z;;=6$Kl~{@2tNdI1Ow% zqV;qn`)w3`#@Y|Lg|X!^3}A!8p(P3nHllbAYpvgnalcYu@-&Qlv>xzlj~7ObVo5Cu zbB%b>6ET}9|2O6Z4Wgn;SRZKv+O@`(RHi871a_@+0l~7$ac?CsAXfF#rA3VB4b@*m zRs+H@g=1A zs4pH@v!)+wT32&&Ol>rw$2bwAmS}oDsbOGony4f_^*zyy@aZ*2X{NU@fV2&oSLZXp zZmT?+nVrutHHDf@Q%3^n3pAS^odt}qXuhwRz>?GmQb(pN{hFZNv;*kcO9*`Z0{M*) z>U{(7e<-BN8G!npQ1#goHl--cnf@3^Z7VD}jB!6(=4qNuG~#~v9j2FoHa=&l&v;^ofB5HqW}JEAX(6Ma3ER3=uYw{ZTY z)yhSrB)-*;sZ_^{D5b@g893W?w*b>8xCa;xL0yESrRML;-z5AQg9Ia}3)qmE@dZ zx4WbXtA64%?2)ER8lbaQp)FE+wKo?_+fStT?hoNyUyzPW-pmD*FE!4mAHo*{;X+? z?yIU8$8BYv)MFRV~q9(~-owaxsAb(S_DJyGWK$>| zHLRE0edt?6x8<(&JGd`q$cd}XZ0h}T$~h;XNs+UnnmE25NuJ>Pk=7fB%4evQ8KQz!_)M14w%jAERFo52TCUaag zn{|k((+TP;eASeg$VmIVWJ+9B#r=?K$_O6BlFcx^Hg6v1zxNc=f}B7`+(BW&VTBos zOluze&IksZjvO1nE-y0O>BdOpRc4LrF-w+f7JRi#cx=``zZr;(Hzzsw@Sl)$v%9&B zr8{pvJ&7NkHlLX9jO7%yzG%MxJ4+FE!~DQUV+V^WM33<>O|ck!DGq+#65hzJjaZ^^ zq}yU^KFhCMuBD*G%o4;|#-FnBAB|HM`%$Jgak0hIbehdsXIW;`(?G0cSJO52gwb*| zhI#@AvH^-Rx3$;z)IFy|5-L#+yUv$7iGN~JW%We6x5%%3STY~EpFI$gE8Py38s;I+ zN~bHms;1geTI+Oq>xKn;pZ5#!rup^g+zR<{q6&73R-hJ_o{4MH+zx6@@jglI*yVpz zs8}!rAdh0TaKq*G3vWBvkY}%TyX>_U&Z_@o^{I%Af~S_8aKZ7+l2~A;r@jc-5d1xR zAlPg+tM_ZafNd-Nx`qy4j~qDYYbiaggq2r5&#kDY3%`+-d^&+Yhfh22U*@?3HFVL* zyYi<}4jQl`$9pF+(Bpfj0+aZ&Q>ucxDtO|ig#Awqik(u*``)QS*;7qEnQC6SsM-Es z?&jqFztGmX*w;k3}=cGyYsxqGY9((;F1GatM_mA%X0m1nJ0RR91 diff --git a/translations/pencil_it.ts b/translations/pencil_it.ts index 0a278f446..d1864e9c3 100644 --- a/translations/pencil_it.ts +++ b/translations/pencil_it.ts @@ -13,13 +13,13 @@ - + Version: %1 Version Number in About Dialog - + Copy to clipboard Copy system info from About Dialog @@ -55,30 +55,30 @@ - + Exporting movie - + Finished. Open movie now? When movie export done. - - - - + + + + Layer Properties Proprietà del livello - - - - + + + + Layer name: Nome del livello: @@ -88,58 +88,63 @@ Un clip audio esiste già in questo fotogramma! Perfavore selezionare un altro fotogramma o livello. - + + Finished. Open file location? + + + + Exporting image sequence... - + Abort - + Warning Avviso - + Unable to export image. - + Bitmap Layer Livello Bitmap - + Vector Layer Livello Vettoriale - + Camera Layer Livello Videocamera - + Sound Layer Livello Suono - + Delete Layer Windows title of Delete current layer pop-up. - + Are you sure you want to delete layer: - + Please keep at least one camera layer in project text when failed to delete camera layer @@ -148,57 +153,57 @@ BaseTool - + Pencil Matita - + Eraser Gomma - + Select Seleziona - + Move Sposta - + Hand Mano - + Smudge Sfuma - + Pen Penna - + Polyline Polilinea - + Bucket Secchiello - + Eyedropper Contagocce - + Brush Pennello @@ -224,69 +229,55 @@ ColorBox - - Color Wheel - Color Wheel's window title + + Color Box + Color Box window title ColorInspector - + HSV HSV - + RGB RGB - - - Red - Rosso - - - - - Green - Verde - - - - - Blue - Blu + + R + - - - - Alpha - Alfa + + A + - - Hue - Tonalità + + G + - - Saturation - Saturazione + + B + - - Value - Valore + + Color Inspector + Window title of color inspector + ColorPalette - + Color Palette Window title of color palette. @@ -302,57 +293,57 @@ Rimuovi colore - - ... - ... + + Native color dialog window + - + List Mode - + Show palette as a list - + Grid Mode - + Show palette as icons - + Small swatch - + Sets swatch size to: 16x16px - + Medium Swatch - + Sets swatch size to: 26x26px - + Large Swatch - + Sets swatch size to: 36x36px @@ -360,11 +351,60 @@ ColorPaletteWidget - - + + Add + + + + + Replace + + + + + Remove + + + + + Colour name Nome colore + + + The color(s) you are about to delete are currently being used by one or multiple strokes. + + + + + Cancel + + + + + Delete + + + + + Palette Restriction + + + + + The palette requires at least one swatch to remain functional + + + + + ColorWheel + + + Color Wheel + Color Wheel's window title + + DisplayOption @@ -446,19 +486,19 @@ Editor - - + + Paste Incolla - + Remove frame - - + + Import Image Importa immagine @@ -484,12 +524,12 @@ ExportImageDialog - + Export image sequence - + Export image Esporta immagine @@ -531,11 +571,51 @@ Transparency Trasparenza + + + Range + + + + + The last frame you want to include in the exported movie + + + + + End Frame + + + + + The first frame you want to include in the exported movie + + + + + Start Frame + + + + + <html><head/><body><p>End frame is set to last paintable keyframe (Useful when you only want to export to the last animated frame)</p></body></html> + + + + + To the end of sound clips + + ExportMovieDialog - + + Export Animated GIF + + + + Export Movie Esporta filmato @@ -627,67 +707,83 @@ - Import movie + Import Animated GIF + Import movie + + + + Import sound Importa Souno - + Import palette - + Save animation Salva Animazione - + Export image - + Export image sequence - + + Export Animated GIF + + + + Export movie - + Export sound - + Export palette - + + + Animated GIF (*.gif) + + + + Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) - - - Palette (*.xml) + + + Pencil2D Palette (*.xml);; Gimp Palette (*.gpl) - - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) + + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng) - + MyAnimation.pclx @@ -695,52 +791,72 @@ FileManager - - - + + + Could not open file + + + + + The file does not exist, so we are unable to open it. Please check to make sure the path is correct and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + Invalid Save Path Percorso di salvataggio non valido - + The path ("%1") points to a directory. - + The directory ("%1") does not exist. - + The path ("%1") is not writable. - - + + Cannot Create Data Directory Non posso creare una directory dati - + Failed to create directory "%1". Please make sure you have sufficient permissions. - + "%1" is a file. Please delete the file and try again. - - + + Miniz Error + + + + Internal Error Errore interno - - + + An internal error occurred. Your file may not be saved successfully. @@ -818,87 +934,97 @@ Griglia - + Czech Ceco - + Danish Danese - + English Inglese - + German Tedesco - + + Estonian + + + + Spanish Spagnolo - + French Francese - + Hebrew - + Hungarian Ungherese - + Indonesian - + Italian Italiano - + Japanese Giapponese - + + Polish + + + + Portuguese - Portugal - + Portuguese - Brazil Portoghese - Brasiliano - + Russian Russo - + Slovenian - + Vietnamese - + Chinese - Taiwan Cinese - Taiwanese @@ -943,12 +1069,12 @@ Posizione ad alta risoluzione della tavoletta - + Restart Required Richiesto il riavvio - + The language change will take effect after a restart of Pencil2D La lingua verrà cambiata dopo il riavvio di Pencil2D @@ -974,7 +1100,12 @@ ImportImageSeqDialog - + + Import Animated GIF + + + + Import image sequence @@ -998,7 +1129,7 @@ LayerBitmap - + Bitmap Layer Livello bitmap @@ -1014,7 +1145,7 @@ LayerSound - + Sound Layer Livello audio @@ -1045,687 +1176,746 @@ Importa - + Export Esporta - + Edit Modifica - + Selection Selezione - + View Vista - + Onion Skin Velina - + Animation Animazione - - + + Tools Strumenti - + Layer Livello - - + + Help Aiuto - + Windows Finestre - + New Nuovo - + Open Apri - + Save Salva - + Save As .. Salva come... - + Exit Esci - - + + Image Sequence... Sequenza immagini... - - + + Image... Immagine... - - + + Movie... Animazione... - - + + Palette... Tavolozza... - + Sound... Audio... - + Undo Annulla - + Redo Ripeti - + Cut Taglia - + Copy Copia - + Paste Incolla - + Crop Ritaglia - + Crop To Selection Ritaglia alla selezione - + Select All Seleziona tutto - + Deselect All Deseleziona tutto - - + + Clear Frame Pulisci fotogramma - + Preferences Preferenze - + Reset Windows Ripristina finestra - + Zoom In Ingrandisci - + Zoom Out Rimpicciolisci - + Rotate Clockwise Ruota in senso orario - + Rotate AntiClosewise Ruota in senso antiorario - + Reset Zoom/Rotate Ripristina ingrandimento/rotazione - + Horizontal Flip Rifletti orizzontalmente - + Vertical Flip Rifletti verticalmente - + Preview Anteprima - + Grid Griglia - + Previous Precedente - + Show previous onion skin Mostra velina precedente - + Next Successivo - + Show next onion skin Mostra velina seguente - - + + Play Riproduci - + Loop Ciclo - + Next Frame Fotogramma successivo - + Previous Frame Fotogramma precedente - + Extend Frame Estendi fotogramma - + Add Frame Aggiungi fotogramma - + Duplicate Frame Duplica fotogramma - + Remove Frame Cancella fotogramma - + Move Sposta - + Select Seleziona - + Brush Pennello - + Polyline Polilinea - + Smudge Sfuma - + Pen Penna - + Hand Mano - + Pencil Matita - + Bucket Secchiello - + Eyedropper Preleva colore - + Eraser Gomma - + New Bitmap Layer Nuovo livello bitmap - + New Vector Layer Nuovo livello vettoriale - + New Sound Layer Nuovo livello audio - + New Camera Layer Nuovo livello videocamera - + Delete Current Layer Elimina livello - + About Informazioni - - + + Reset to default Ripristina predefiniti - + MultiLayer Onion Skin Velina multilivello - + Range Intervallo - + Pencil2D Website - + Report a Bug - + Quick Reference Guide - + F1 - - + + + Animated GIF... + + + + + Next KeyFrame KeyFrame seguente - - + + Previous KeyFrame KeyFrame precedente - + Timeline Linea del tempo - + Options Opzioni - + Color Wheel Ruota dei colori - + Color Palette Tavolozza dei colori - + Display Options Opzioni di visualizzazione - + Flip X Rifletti X - + Flip Y Rifletti Y - + Move Frame Forward Sposta fotogramma in avanti - + Move Frame Backward Sposta fotogramma indietro - + color palette:<br>use <b>(C)</b><br>toggle at cursor tavolozza colori:<br>usare<b>(C)</b><br>per aprire/chiudere al cursore - + + Color inspector + + + + Lock Windows - + Open Recent Apri recenti - + You have successfully cleared the list - - - - - + + + + + Could not open file + + + + + The file you have selected is a directory, so we are unable to open it. If you are are trying to open a project that uses the old structure, please open the file ending with .pcl, not the data folder. + + + + + The file you have selected does not exist, so we are unable to open it. Please check to make sure that you've entered the correct path and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + + + Warning Attenzione - - - Pencil cannot read this file. If you want to import images, use the command import. - Pencil non può leggere questo file. Per importare immagini usare il comando importa. + + This program does not currently have permission to write to the file you have selected. Please make sure you have write permission for this file before attempting to save it. Alternatively, you can use the Save As... menu option to save to a writable location. + - + Opening document... Apertura del documento... - - - + + + + Abort Annulla - + + An unknown error occurred while trying to load the file and we are not able to load your file. + + + + Saving document... Salvataggio del documento... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: - + This animation has been modified. Do you want to save your changes? Questa animazione è stata modificata. Vuoi salavare i cambiamenti? - + The animation is not saved yet. Do you want to save now? L'animazione non è ancora salvata. Vuoi salvarla ora? - + Never ask again AutoSave reminder button Non chiederlo più - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Impossibile caricare l'immagine.<br><b>Suggerimento:</b> usare un livello bitmap per importarla. - + Importing image sequence... - + + was unable to import - - + + Importing Animated GIF... + + + + + Undo Menu item text - + Redo Menu item text - + Stop Stop + + MoveTool + + + Layer switch + Windows title of layer switch pop-up. + + + + + You are about to switch layer, do you want to apply the transformation? + + + Object - + Black Nero - + Red Rosso - + Dark Red Rosso scuro - + Orange Arancio - + Dark Orange Arancio scuro - + Yellow Giallo - + Dark Yellow Giallo scuro - + Green Verde - + Dark Green Verde scuro - + Cyan Ciano - + Dark Cyan Ciano scuro - + Blue Blu - + Dark Blue Blu scuro - + White Bianco - + Very Light Grey Grigio molto chiaro - + Light Grey Grigio chiaro - + Grey Grigio - + Dark Grey Grigio scuro - + Light Skin Pelle chiaro - + Light Skin - shade Pelle chiaro - sfumato - + Skin Pelle - + Skin - shade Pelle - sfumato - + Dark Skin Pelle scuro - + Dark Skin - shade Pelle scuro - sfumato @@ -1733,153 +1923,153 @@ Vuoi salavare i cambiamenti? PencilApplication - + Pencil2D is an animation/drawing software for Mac OS X, Windows, and Linux. It lets you create traditional hand-drawn animation (cartoon) using both bitmap and vector graphics. - + Path to the input pencil file. - - + + Render the file to <output_path> - - + + output_path - + Name of the camera layer to use - + layer_name - + Width of the output frames - - + + integer Integer - + Height of the output frames - + The first frame you want to include in the exported movie - - + + frame - + The last frame you want to include in the exported movie. Can also be last or last-sound to automatically use the last frame containing animation or sound, respectively - + Render transparency when possible Renderizza la trasparenza quando possibile - + Warning: width value %1 is not an integer, ignoring. - + Warning: height value %1 is not an integer, ignoring. - + Warning: start value %1 is not an integer, ignoring. - + Warning: start value must be at least 1, ignoring. - + Warning: end value %1 is not an integer, last or last-sound, ignoring. - + Warning: end value %1 is smaller than start value %2, ignoring. - + Error: No input file specified. Errore: file non specificato. - + Error: the input file at '%1' does not exist Command line error - + Error: the input path '%1' is not a file Command line error - + Warning: the specified camera layer %1 was not found, ignoring. - + Warning: Output format is not specified or unsupported. Using PNG. Command line warning - + Warning: Transparency is not currently supported in movie files Command line warning - + Exporting movie... Command line task progress - - + + Done. Command line task done - + Exporting image sequence... Command line task progress @@ -1921,12 +2111,12 @@ Vuoi salavare i cambiamenti? QApplication - + Checking environment... - + Done @@ -1934,42 +2124,47 @@ Vuoi salavare i cambiamenti? QObject - + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) - - Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp) - + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp); + + + + Everything ok. Tutto ok. - + Ooops, Something went wrong. Oops, qualcosa è andato storto. - + File doesn't exist. Il file non esiste. - + Cannot open file. Impossible aprire il file. - + The file is not a valid xml document. Il file non è un documento xml valido. - + The file is not valid pencil document. Il file non è un documento di Pencil valido. @@ -3318,6 +3513,16 @@ Vuoi salavare i cambiamenti? Black + + + Could not open file + + + + + There was an error processing your file. This usually means that your project has been at least partially corrupted. You can try again with a newer version of Pencil2D, or you can try to use a backup file if you have one. If you contact us through one of our offical channels we may be able to help you. For reporting issues, the best places to reach us are: + + RecentFileMenu @@ -3335,60 +3540,60 @@ Vuoi salavare i cambiamenti? ScribbleArea - + Warning Attenzione - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Si sta disegnando su un livello nascosto! Scegliere un altro livello (o rendere visibile questo livello). - + Delete Selection Undo Step: clear the selection area. - - + + Clear Image Undo step text Cancella immagine - + There is a gap in your drawing (or maybe you have zoomed too much). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). - + Out of bound. - + Could not find a closed path. - + Could not find the root index. - + %1<br><br>Error: %2 %1<br><br>Errore: %2 - + Flood fill error Errore di riempimento @@ -3485,12 +3690,12 @@ Vuoi salavare i cambiamenti? - + Start Inizio - + Stop Stop @@ -3574,18 +3779,18 @@ Vuoi salavare i cambiamenti? - + Delete Layer Windows title of Delete current layer pop-up. - + Please keep at least one camera layer in project - + Are you sure you want to delete layer: Conferma eliminazione del livello: @@ -3593,12 +3798,12 @@ Vuoi salavare i cambiamenti? TimeLineCells - + Layer Properties - + Layer name: @@ -3675,6 +3880,16 @@ Vuoi salavare i cambiamenti? <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + + Playback + + + + + Show onion skin while playing + + Frame size diff --git a/translations/pencil_ja.qm b/translations/pencil_ja.qm index ffe6755b5a96518f7e3a4e32be5e7537eab913c6..9b3b3310dcd8d52cb19f013aafb2527d4f7e7c7d 100644 GIT binary patch delta 2678 zcmXAqdt6QF8pof#*JZE0*4k^6F2bR!VkaqOQz*LVvbS9-H8?IGV#f8OsWEl5&qU3b z&^bDD#;JznayW(%Vq6XhF$l%P$aNZqGtJD0PCApE-?skx?zQ&&KJWAVp5ObdUoL1m z&T9VRY&R2)Qi%8)DyQ0s;yj4N+e8TsM4r!ylA?*?ONlJSMBF{1sc}S7I8o|FB0sE4 z^TYFEqVz+EBY>xg*w0m(MiFHkCK|Jx*s>!;qYH@L^)ccm6T4>)k=-+&*qQ?Tv6a{p zERnYhu}uyxCic27k$ag+9}}_9kO&*0(&qtqi72cXd`0B4R;5oZvHuAo@|B1S!vRCh zDie~3i#?D13serRBrfR{*=d*)ap^HcQxb{GLgvGs5Vvw2k*QE+!bilF)DVpjiQ9|- zfyap3){BZtiQ9_p~E(3Ce_I)5yrDP$8XyY87R;{N_Oq9H|K1Gt~!{VJf;Op34EOvLv`b zCVWTl?M5Pr5%k_E^mu$D&BzKN3f8Hd7)!H$#eVY;n)Ul`B7-Z6=AF(Ts*O$;-ZC?!j?;MEpL*`-@)lR4xi8^1q_eDr!!oK7fJSG(Z3R1J=*cI%l9DV}RCNGat%4 z)fNWiz+30FrI*IR(5_nhR|6KHVoAF#Dh95PS80gW*0Am9`9W>n;1(h!T>DKI5*c|@ zd&;ria87%+z7zk4skD}8FZd!cK1+N5k`}$LXPj1e6A6Wk*UMoj)}nHrZ9Q`u z_uu6J+uDFYE*|W?vH~!LeevcM4ldwWM*!b8PPc6r%%|bJWsWE`oAd7}!w}lVSyntj z3s!K89Ht!;%PooT!TsK^(v-oiAB$FKHglDx9T;4sa^#2Hj&HD@^Ls}-1=Vsp$92HH zS=?TKWag*m4xOmOwF%?S%w{FE!_aiEz`7+Me0jpi+9anO)9m5D#{DUI`x-~fK6 zCpXTvF?pZOEmve!WJBmsS{Sg?R`6S z-XC8giY(Pd%|(Hp|I}H&y#}v6)UCHSeMuA`>5ksOKr!FZHP4)e0kcx~=q&>J$EmcG z=pHAD=-C&#=e0Okvn!T#=tVYN`jK~iO(O7~vj${0VQ{%3`&Of3?O5L&9^u`y0) zxf2R08-$j2R5H3lxb>m{@2?5%$Iz;Q&xE&EHxl(3t#{7E0frvEWg*t-pX*nhg!Hxp z`ihBtVCGzXO)3(PA8OZM-WmwASoKej;vly*`rcn08>&Sv8JzS|biTVCpW1xU6b#9t zL&bnnR2Xw#Tx4s+`ZMCXUMQydPTaIS4T=0uEZ61cKnjlLXm`==vU}@9wl`yA4rFXZq{ho|TxkcLBIv11fnsnfR4s+t9bn+%9 z;N&RjYAbHp&<5$D=!E;1i2B*lk z`{5arrL7+4m|EY_P7})IA7`VIfGYXd?X56hw?P>bOf=w};SZNP5HQ6M8HvgR^9+$y z%P^3Z7!tfEKw$BCwWs$?ApZCy%E$9(j*Q>ogJgG8)K^HO|P`yNu7 zYaQ#xE5FTvnfeY^I=j&_-%zE?LB7YR@zLXe3r5k=0ss4k zCY|wO2m(7VHD33$BH$m5ulZ1TqUwE&zslNj@gZ0CrcXfGw7vn`StqeJVUTrTZKm1P F^ndFs%!>d3 delta 3203 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 - + Version: %1 Version Number in About Dialog - + Copy to clipboard Copy system info from About Dialog @@ -55,30 +55,30 @@ - + Exporting movie - + Finished. Open movie now? When movie export done. - - - - + + + + Layer Properties レイヤーのプロパティ - - - - + + + + Layer name: レイヤー名: @@ -88,58 +88,63 @@ このフレームにには既に音声クリップが存在します。他のフレーム、またはレイヤーを選択して下さい。 - + + Finished. Open file location? + + + + Exporting image sequence... - + Abort - + Warning - + Unable to export image. - + Bitmap Layer ビットマップレイヤー - + Vector Layer ベクターレイヤー - + Camera Layer カメラレイヤー - + Sound Layer 音声レイヤー - + Delete Layer Windows title of Delete current layer pop-up. - + Are you sure you want to delete layer: - + Please keep at least one camera layer in project text when failed to delete camera layer @@ -148,57 +153,57 @@ BaseTool - + Pencil 鉛筆 - + Eraser 消しゴム - + Select 選択 - + Move 移動 - + Hand 手のひら - + Smudge こする - + Pen ペン - + Polyline 折れ線 - + Bucket バケツ - + Eyedropper スポイト - + Brush ブラシ @@ -224,69 +229,55 @@ ColorBox - - Color Wheel - Color Wheel's window title + + Color Box + Color Box window title ColorInspector - + HSV HSV - + RGB RGB - - - Red - - - - - - Green - - - - - - Blue - + + R + - - - - Alpha - アルファ + + A + - - Hue - 色相 + + G + - - Saturation - 彩度 + + B + - - Value - 明度 + + Color Inspector + Window title of color inspector + ColorPalette - + Color Palette Window title of color palette. @@ -302,57 +293,57 @@ 色の削除 - - ... + + Native color dialog window - + List Mode - + Show palette as a list - + Grid Mode - + Show palette as icons - + Small swatch - + Sets swatch size to: 16x16px - + Medium Swatch - + Sets swatch size to: 26x26px - + Large Swatch - + Sets swatch size to: 36x36px @@ -360,11 +351,60 @@ ColorPaletteWidget - - + + Add + + + + + Replace + + + + + Remove + + + + + Colour name 色名 + + + The color(s) you are about to delete are currently being used by one or multiple strokes. + + + + + Cancel + + + + + Delete + + + + + Palette Restriction + + + + + The palette requires at least one swatch to remain functional + + + + + ColorWheel + + + Color Wheel + Color Wheel's window title + + DisplayOption @@ -446,19 +486,19 @@ Editor - - + + Paste 貼り付け - + Remove frame - - + + Import Image イメージを読み込む @@ -484,12 +524,12 @@ ExportImageDialog - + Export image sequence 連番画像の書き出し - + Export image 画像の書き出し @@ -531,11 +571,51 @@ Transparency 透明度 + + + Range + + + + + The last frame you want to include in the exported movie + + + + + End Frame + + + + + The first frame you want to include in the exported movie + + + + + Start Frame + + + + + <html><head/><body><p>End frame is set to last paintable keyframe (Useful when you only want to export to the last animated frame)</p></body></html> + + + + + To the end of sound clips + + ExportMovieDialog - + + Export Animated GIF + + + + Export Movie 動画の書き出し @@ -627,67 +707,83 @@ + Import Animated GIF + + + + Import movie 動画の読み込み - + Import sound 音声の読み込み - + Import palette パレットの読み込み - + Save animation アニメーションを保存 - + Export image 画像の書き出し - + Export image sequence 連番画像の書き出し - + + Export Animated GIF + + + + Export movie 動画の書き出し - + Export sound 音声の書き出し - + Export palette パレットの書き出し - + + + Animated GIF (*.gif) + + + + Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) 音声ファイル (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) - - - Palette (*.xml) - パレット (*.xml) + + + Pencil2D Palette (*.xml);; Gimp Palette (*.gpl) + - - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) + + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng) - + MyAnimation.pclx MyAnimation.pclx @@ -695,52 +791,72 @@ FileManager - - - + + + Could not open file + + + + + The file does not exist, so we are unable to open it. Please check to make sure the path is correct and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + Invalid Save Path セーブ先が不正です - + The path ("%1") points to a directory. - + The directory ("%1") does not exist. - + The path ("%1") is not writable. - - + + Cannot Create Data Directory データフォルダーが作成できません - + Failed to create directory "%1". Please make sure you have sufficient permissions. - + "%1" is a file. Please delete the file and try again. - - + + Miniz Error + + + + Internal Error 内部エラー - - + + An internal error occurred. Your file may not be saved successfully. @@ -818,87 +934,97 @@ グリッド - + Czech チェコ語 - + Danish Danish - + English - + German German - + + Estonian + + + + Spanish Spanish - + French French - + Hebrew - + Hungarian Hungarian - + Indonesian - + Italian Italian - + Japanese 日本語 - + + Polish + + + + Portuguese - Portugal - + Portuguese - Brazil Portuguese - Brazil - + Russian Russian - + Slovenian - + Vietnamese - + Chinese - Taiwan Chinese - Taiwan @@ -943,12 +1069,12 @@ - + Restart Required プログラムの再起動が必要です - + The language change will take effect after a restart of Pencil2D 使用言語の変更はプログラムの再起動後に適用されます @@ -974,7 +1100,12 @@ ImportImageSeqDialog - + + Import Animated GIF + + + + Import image sequence 連番画像を読み込む @@ -998,7 +1129,7 @@ LayerBitmap - + Bitmap Layer ビットマップレイヤー @@ -1014,7 +1145,7 @@ LayerSound - + Sound Layer 音声レイヤー @@ -1045,687 +1176,746 @@ 読み込む - + Export エクスポート - + Edit 編集 - + Selection 選択範囲 - + View 表示 - + Onion Skin オニオンスキン - + Animation アニメーション - - + + Tools ツール - + Layer レイヤー - - + + Help ヘルプ - + Windows ウィンドウ - + New 新規 - + Open 開く - + Save 保存 - + Save As .. 名前を付けて保存... - + Exit 終了 - - + + Image Sequence... 連番画像... - - + + Image... 画像... - - + + Movie... 動画... - - + + Palette... パレット... - + Sound... 音声... - + Undo 元に戻す - + Redo やり直す - + Cut 切り取り - + Copy コピー - + Paste 貼り付け - + Crop 切り抜き - + Crop To Selection 選択範囲でクロップ - + Select All すべて選択 - + Deselect All すべての選択を解除 - - + + Clear Frame フレームをクリア - + Preferences 詳細設定 - + Reset Windows ウィンドウをリセット - + Zoom In ズームイン - + Zoom Out ズームアウト - + Rotate Clockwise 時計回りに回転 - + Rotate AntiClosewise 反時計回りに回転 - + Reset Zoom/Rotate ズームと回転をリセット - + Horizontal Flip 水平反転 - + Vertical Flip 垂直反転 - + Preview プレビュー - + Grid グリッド - + Previous - + Show previous onion skin 前のフレームのオニオンスキンを表示 - + Next - + Show next onion skin 次のフレームのオニオンスキンを表示 - - + + Play 再生 - + Loop ループ - + Next Frame 次のフレーム - + Previous Frame 前のフレーム - + Extend Frame フレーム - + Add Frame フレームを追加 - + Duplicate Frame フレームを複製 - + Remove Frame フレームを削除 - + Move 移動 - + Select 選択 - + Brush ブラシ - + Polyline 折れ線 - + Smudge 指先 - + Pen ペン - + Hand 手のひら - + Pencil 鉛筆 - + Bucket バケツ - + Eyedropper スポイト - + Eraser 消しゴム - + New Bitmap Layer 新しいビットマップレイヤー - + New Vector Layer 新しいベクターレイヤー - + New Sound Layer 新しい音声レイヤー - + New Camera Layer 新しいカメラレイヤー - + Delete Current Layer 現在のレイヤーを削除 - + About About - - + + Reset to default 初期状態に戻す - + MultiLayer Onion Skin 複数レイヤーのオニオンスキンを表示 - + Range 範囲 - + Pencil2D Website - + Report a Bug - + Quick Reference Guide - + F1 - - + + + Animated GIF... + + + + + Next KeyFrame 次のキーフレーム - - + + Previous KeyFrame 前のキーフレーム - + Timeline タイムライン - + Options オプション - + Color Wheel カラーホイール - + Color Palette カラーパレット - + Display Options 表示オプション - + Flip X 水平反転 - + Flip Y 垂直反転 - + Move Frame Forward 次のフレームに移動 - + Move Frame Backward 前のフレームに移動 - + color palette:<br>use <b>(C)</b><br>toggle at cursor - + + Color inspector + + + + Lock Windows - + Open Recent 最近使ったファイル - + You have successfully cleared the list リストは正常に削除されました - - - - - + + + + + Could not open file + + + + + The file you have selected is a directory, so we are unable to open it. If you are are trying to open a project that uses the old structure, please open the file ending with .pcl, not the data folder. + + + + + The file you have selected does not exist, so we are unable to open it. Please check to make sure that you've entered the correct path and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + + + Warning 警告 - - - Pencil cannot read this file. If you want to import images, use the command import. - 読み込みエラーです。画像を読み込む場合は「読み込む」コマンドを使用して下さい。 + + This program does not currently have permission to write to the file you have selected. Please make sure you have write permission for this file before attempting to save it. Alternatively, you can use the Save As... menu option to save to a writable location. + - + Opening document... ドキュメントを開いています... - - - + + + + Abort 中断 - + + An unknown error occurred while trying to load the file and we are not able to load your file. + + + + Saving document... ドキュメントを保存しています... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>エラーによってファイルが正常に保存されなかった可能性があります。もしこのエラーがPencil2Dによって起こったと推測される場合は, <br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>にアクセスして新しい"issue"として報告してください。ご報告の際は、以下の詳細を追記してください: - + This animation has been modified. Do you want to save your changes? ファイルの変更があります。 これらの変更を保存しますか? - + The animation is not saved yet. Do you want to save now? - + Never ask again AutoSave reminder button - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. 画像が読み込めません。<br><b>ヒント:</b> ビットマップファイルはビットマップレイヤーに読み込んでください。 - + Importing image sequence... - + + was unable to import - - + + Importing Animated GIF... + + + + + Undo Menu item text - + Redo Menu item text - + Stop 停止 + + MoveTool + + + Layer switch + Windows title of layer switch pop-up. + + + + + You are about to switch layer, do you want to apply the transformation? + + + Object - + Black - + Red - + Dark Red 暗い赤 - + Orange オレンジ - + Dark Orange 暗いオレンジ - + Yellow 黄色 - + Dark Yellow 暗い黄色 - + Green - + Dark Green 暗い緑 - + Cyan シアン - + Dark Cyan 暗いシアン - + Blue - + Dark Blue 暗い青 - + White - + Very Light Grey 非常に明るい灰色 - + Light Grey 明るい灰色 - + Grey 灰色 - + Dark Grey 暗い灰色 - + Light Skin 明るい肌色 - + Light Skin - shade 明るい肌色 (陰) - + Skin 肌色 - + Skin - shade 肌色 (陰) - + Dark Skin 暗い肌色 - + Dark Skin - shade 暗い肌色 (陰) @@ -1733,153 +1923,153 @@ PencilApplication - + Pencil2D is an animation/drawing software for Mac OS X, Windows, and Linux. It lets you create traditional hand-drawn animation (cartoon) using both bitmap and vector graphics. Pencil2DはMac OS X, Windows, and Linuxに対応したアニメーション及びドローイングソフトです。 本ソフトウェアのベクター・ビットマップ両方の描画機能を使用して、一般的なコマ送りアニメーションを作成できます。 - + Path to the input pencil file. 読み込むPencilファイルの場所。 - - + + Render the file to <output_path> ファイルを<output_path>内に書き出す - - + + output_path 保存場所 - + Name of the camera layer to use - + layer_name - + Width of the output frames 出力されるフレームの幅 - - + + integer 整数 - + Height of the output frames 出力されるフレームの高さ - + The first frame you want to include in the exported movie - - + + frame - + The last frame you want to include in the exported movie. Can also be last or last-sound to automatically use the last frame containing animation or sound, respectively - + Render transparency when possible 透明ピクセルを出力する(可能なファイル形式のみ) - + Warning: width value %1 is not an integer, ignoring. 警告:幅の値 %1 が整数ではありません。無視されます。 - + Warning: height value %1 is not an integer, ignoring. 警告:高さの値 %1 が整数ではありません。無視されます。 - + Warning: start value %1 is not an integer, ignoring. - + Warning: start value must be at least 1, ignoring. - + Warning: end value %1 is not an integer, last or last-sound, ignoring. - + Warning: end value %1 is smaller than start value %2, ignoring. - + Error: No input file specified. エラー:読み込むファイルが指定されていません。 - + Error: the input file at '%1' does not exist Command line error - + Error: the input path '%1' is not a file Command line error - + Warning: the specified camera layer %1 was not found, ignoring. - + Warning: Output format is not specified or unsupported. Using PNG. Command line warning - + Warning: Transparency is not currently supported in movie files Command line warning - + Exporting movie... Command line task progress - - + + Done. Command line task done - + Exporting image sequence... Command line task progress @@ -1921,12 +2111,12 @@ QApplication - + Checking environment... - + Done @@ -1934,42 +2124,47 @@ QObject - + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) - - Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp) - + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp); + + + + Everything ok. 正常終了 - + Ooops, Something went wrong. エラーが発生しました。 - + File doesn't exist. ファイルは存在しません。 - + Cannot open file. ファイルの読み込みに失敗しました。 - + The file is not a valid xml document. 正常なXMLファイルではありません。 - + The file is not valid pencil document. 正常なPencil2Dのドキュメントではありません。 @@ -3318,6 +3513,16 @@ Black + + + Could not open file + + + + + There was an error processing your file. This usually means that your project has been at least partially corrupted. You can try again with a newer version of Pencil2D, or you can try to use a backup file if you have one. If you contact us through one of our offical channels we may be able to help you. For reporting issues, the best places to reach us are: + + RecentFileMenu @@ -3335,60 +3540,60 @@ ScribbleArea - + Warning 警告 - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). 選択中のレイヤーは非表示に設定されています。このレイヤーを表示するか他のレイヤーを選択して下さい。 - + Delete Selection Undo Step: clear the selection area. - - + + Clear Image Undo step text 画像をクリア - + There is a gap in your drawing (or maybe you have zoomed too much). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). - + Out of bound. 有効範囲の外です。 - + Could not find a closed path. 閉じられたパスがありません。 - + Could not find the root index. - + %1<br><br>Error: %2 %1<br><br>エラー: %2 - + Flood fill error 塗りつぶし中にエラーが発生しました @@ -3485,12 +3690,12 @@ - + Start 最初のフレームに移動 - + Stop 停止 @@ -3574,18 +3779,18 @@ キーフレームと同期機能のオン・オフ - + Delete Layer Windows title of Delete current layer pop-up. - + Please keep at least one camera layer in project - + Are you sure you want to delete layer: レイヤーを削除してよろしいですか: @@ -3593,12 +3798,12 @@ TimeLineCells - + Layer Properties - + Layer name: @@ -3675,6 +3880,16 @@ <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + + Playback + + + + + Show onion skin while playing + + Frame size diff --git a/translations/pencil_pl.qm b/translations/pencil_pl.qm index a6858c8a2df1b30c508942e363c6baa4f10e8835..e7a2af35754d2026c650af66409feda1a1a7b0df 100644 GIT binary patch delta 6010 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 diff --git a/translations/pencil_pl.ts b/translations/pencil_pl.ts index 4716ee95b..427d00240 100644 --- a/translations/pencil_pl.ts +++ b/translations/pencil_pl.ts @@ -14,13 +14,13 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">reptile@o2.pl</a>, <a href="http://www.rpgmaker.pl">www.rpgmaker.pl</a></a>) - + Version: %1 Version Number in About Dialog Wersja %1 - + Copy to clipboard Copy system info from About Dialog Kopiuj do schowka @@ -56,30 +56,30 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">re Warstwa dźwiękowa - + Exporting movie Eksportowanie filmu - + Finished. Open movie now? When movie export done. Gotowe. Czy otworzyć film? - - - - + + + + Layer Properties Właściwości warstwy - - - - + + + + Layer name: Nazwa warstwy: @@ -89,58 +89,63 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">re Do tej ramki już dźwięk został przyposany! Wybierz inną ramkę lub warstwę. - + + Finished. Open file location? + + + + Exporting image sequence... Eksportowanie sekwencji obrazów ... - + Abort Anuluj - + Warning Uwaga - + Unable to export image. Nie można wyeksportować obrazu. - + Bitmap Layer Warstwa bitmapowa - + Vector Layer Warstwa wektorowa - + Camera Layer Warstwa kamery - + Sound Layer Warstwa dźwiękowa - + Delete Layer Windows title of Delete current layer pop-up. Usuń warstwę - + Are you sure you want to delete layer: Czy na pewno usunąć zaznaczoną warstwę: - + Please keep at least one camera layer in project text when failed to delete camera layer Nie można usunąć warstwy kamery.Chociaż jedna warstwa kamery jest potrzebna w projekcie @@ -149,57 +154,57 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">re BaseTool - + Pencil Ołówek - + Eraser Gumka - + Select Zaznaczenie - + Move Przesunięcie - + Hand Ręka - + Smudge Rozmazanie - + Pen Pióro - + Polyline Linia - + Bucket Wypełniacz - + Eyedropper Selektor kolorów - + Brush Pędzel @@ -225,69 +230,55 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">re ColorBox - - Color Wheel - Color Wheel's window title - Koło kolorów + + Color Box + Color Box window title + ColorInspector - + HSV HSV - + RGB RGB - - - Red - Czerwony + + R + - - - Green - Zielony + + A + - - - Blue - Niebieski + + G + - - - - Alpha - Alfa - - - - Hue - Odcień + + B + - - Saturation - Nasycenie - - - - Value - Wartość + + Color Inspector + Window title of color inspector + ColorPalette - + Color Palette Window title of color palette. Paleta kolorów @@ -303,57 +294,57 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">re Usuń kolor - - ... - ... + + Native color dialog window + - + List Mode Lista - + Show palette as a list Wyświetlenie kolorów w palecie jako lista - + Grid Mode Kafelki - + Show palette as icons Wyświetlenie kolorów w palecie jako kafelki - + Small swatch Małe ikony - + Sets swatch size to: 16x16px Ustawienie próbki kolorów na rozmiar: 16x16px - + Medium Swatch Średnie ikony - + Sets swatch size to: 26x26px Ustawienie próbki kolorów na rozmiar: 26x26px - + Large Swatch Duże ikony - + Sets swatch size to: 36x36px Ustawienie próbki kolorów na rozmiar: 36x36px @@ -361,11 +352,60 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">re ColorPaletteWidget - - + + Add + + + + + Replace + + + + + Remove + + + + + Colour name Nazwa koloru + + + The color(s) you are about to delete are currently being used by one or multiple strokes. + + + + + Cancel + + + + + Delete + + + + + Palette Restriction + + + + + The palette requires at least one swatch to remain functional + + + + + ColorWheel + + + Color Wheel + Color Wheel's window title + + DisplayOption @@ -447,19 +487,19 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">re Editor - - + + Paste Wklej - + Remove frame Usuń kratke - - + + Import Image Importuj obraz @@ -485,12 +525,12 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">re ExportImageDialog - + Export image sequence Eksportuj sekwencję obrazów - + Export image Eksportuj obraz @@ -532,11 +572,51 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">re Transparency Przezroczystość + + + Range + + + + + The last frame you want to include in the exported movie + + + + + End Frame + + + + + The first frame you want to include in the exported movie + + + + + Start Frame + + + + + <html><head/><body><p>End frame is set to last paintable keyframe (Useful when you only want to export to the last animated frame)</p></body></html> + + + + + To the end of sound clips + + ExportMovieDialog - + + Export Animated GIF + + + + Export Movie Eksportuj film @@ -628,67 +708,83 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">re + Import Animated GIF + + + + Import movie Importuj film - + Import sound Importuj dźwięk - + Import palette Importuj palete - + Save animation Zapisz animacje - + Export image Eksportuj obraz - + Export image sequence Eksportuj sekwencje obrazów - + + Export Animated GIF + + + + Export movie Eksportuj film - + Export sound Eksportuj dźwięk - + Export palette Eksportuj palete - + + + Animated GIF (*.gif) + + + + Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) Dźwięk (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) - - - Palette (*.xml) - Paleta (*.xml) + + + Pencil2D Palette (*.xml);; Gimp Palette (*.gpl) + - - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) + + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng) + - + MyAnimation.pclx moja_animacja.pclx @@ -696,52 +792,72 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">re FileManager - - - + + + Could not open file + + + + + The file does not exist, so we are unable to open it. Please check to make sure the path is correct and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + Invalid Save Path Nieprawidłowa ścieżka zapisu - + The path ("%1") points to a directory. Ścieżka ("%1") odnosi się do folderu. - + The directory ("%1") does not exist. Folder ("%1") nie istnieje. - + The path ("%1") is not writable. Ścieżka ("%1") nie umożliwia zapisu. - - + + Cannot Create Data Directory Nie można utworzyć folderu danych - + Failed to create directory "%1". Please make sure you have sufficient permissions. Nie można utworzyć folderu "%1". Upewnij się, że masz wystarczające uprawnienia. - + "%1" is a file. Please delete the file and try again. "%1" jest plikiem. Usuń plik i spróbuj ponownie. - - + + Miniz Error + + + + Internal Error Błąd wewnętrzny - - + + An internal error occurred. Your file may not be saved successfully. Wystąpił błąd wewnętrzny. Twój plik może nie zostać pomyślnie zapisany. @@ -819,87 +935,97 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">re Siatka - + Czech Czech - + Danish Danish - + English English - + German German - + + Estonian + + + + Spanish Spanish - + French French - + Hebrew Hebrew - + Hungarian Hungarian - + Indonesian Indonesian - + Italian Italian - + Japanese Japanese - + + Polish + + + + Portuguese - Portugal Portuguese - Portugal - + Portuguese - Brazil Portuguese - Brazil - + Russian Russian - + Slovenian Slovenian - + Vietnamese Vietnamese - + Chinese - Taiwan Chinese - Taiwan @@ -944,12 +1070,12 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">re Tablet wysokiej rozdzielczości - + Restart Required Wymagane jest ponowne uruchomienie - + The language change will take effect after a restart of Pencil2D Zmiana języka zostanie zastosowana po ponownym uruchomieniu Pencil2D @@ -975,7 +1101,12 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">re ImportImageSeqDialog - + + Import Animated GIF + + + + Import image sequence Import sekwencji obrazów @@ -999,7 +1130,7 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">re LayerBitmap - + Bitmap Layer Warstwa bitmapowa @@ -1015,7 +1146,7 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">re LayerSound - + Sound Layer Warstwa dźwięku @@ -1046,473 +1177,484 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">re Import - + Export Eksport - + Edit Edycja - + Selection Zaznaczenie - + View Widok - + Onion Skin Skóra cebuli - + Animation Animacja - - + + Tools Narzędzia - + Layer Warstwa - - + + Help Pomoc - + Windows Okna - + New Nowy - + Open Otwórz - + Save Zapisz - + Save As .. Zapisz jako .. - + Exit Zamknij - - + + Image Sequence... Sekwencje obrazów... - - + + Image... Obraz... - - + + Movie... Film... - - + + Palette... Paleta... - + Sound... Dźwięk... - + Undo Cofnij - + Redo Ponów - + Cut Wytnij - + Copy Kopiuj - + Paste Wklej - + Crop Przytnij - + Crop To Selection Przytnij do zaznaczenia - + Select All Zaznacz wszystko - + Deselect All Odznacz wszystko - - + + Clear Frame Czyść klate - + Preferences Preferencje - + Reset Windows Resetuj okna - + Zoom In Powiększenie - + Zoom Out Pomniejszenie - + Rotate Clockwise Obrót w prawo (wg wskazówek zegarka) - + Rotate AntiClosewise Obrót w lewo (przeciwnie do wskazówek zegarka) - + Reset Zoom/Rotate Resetuj powiększenie/obrót - + Horizontal Flip Obrót poziomy - + Vertical Flip Obrót pionowy - + Preview Podgląd - + Grid Siatka - + Previous Poprzednia - + Show previous onion skin Wyświetl poprzednią skórę cebuli - + Next Następna - + Show next onion skin Wyświetl następną skórę cebuli - - + + Play Graj - + Loop Pętla - + Next Frame Następna klatka - + Previous Frame Poprzednia klatka - + Extend Frame Wydłuż klatkę - + Add Frame Dodaj klatkę - + Duplicate Frame Duplikuj klatki - + Remove Frame Usuń klatkę - + Move Przesuń - + Select Zaznacz - + Brush Pędzel - + Polyline Linia - + Smudge Rozmazanie - + Pen Pióro - + Hand Ręka - + Pencil Ołówek - + Bucket Wypełniacz - + Eyedropper Selektor kolorów - + Eraser Gumka - + New Bitmap Layer Nowa warstwa bitmapowa - + New Vector Layer Nowa warstwa wektorowa - + New Sound Layer Nowa warstwa dźwiękowa - + New Camera Layer Nowa warstwa kamery - + Delete Current Layer Usuń aktualną warstwę - + About O programie - - + + Reset to default Ustawienie podstawowe - + MultiLayer Onion Skin Wielowarstwowa skóra cebuli - + Range Zasięg - + Pencil2D Website Strona Pencil2D - + Report a Bug Zgłoś błąd - + Quick Reference Guide Szybka instrukcja obsługi - + F1 F1 - - + + + Animated GIF... + + + + + Next KeyFrame Następna kluczowa klatka - - + + Previous KeyFrame Poprzednia kluczowa klatka - + Timeline Oś czasu - + Options Opcje - + Color Wheel Koło koloru - + Color Palette Paleta kolorów - + Display Options Właściwości wyświetlenia - + Flip X Obrót X - + Flip Y Obrót Y - + Move Frame Forward Przesuń klatkę do przodu - + Move Frame Backward Przesuń klatkę do tyłu - + color palette:<br>use <b>(C)</b><br>toggle at cursor Paleta kolorów: <br>użyj <b>(C)</b><br>by przełączyć kursor - + + Color inspector + + + + Lock Windows Zablokuj okna - + Open Recent Otwórz ostatnie pliki - + You have successfully cleared the list @@ -1521,215 +1663,263 @@ Polskie tłumaczenie: Reptile (<a href=mailto:"reptile@o2.pl">re Pomyślnie wyczyszczono listę - - - - - + + + + + Could not open file + + + + + The file you have selected is a directory, so we are unable to open it. If you are are trying to open a project that uses the old structure, please open the file ending with .pcl, not the data folder. + + + + + The file you have selected does not exist, so we are unable to open it. Please check to make sure that you've entered the correct path and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + + + Warning Uwaga - - - Pencil cannot read this file. If you want to import images, use the command import. - Pencil nie może odczytać tego pliku. Jeżeli chcesz wczytać obraz, użyj polecenia <b>importu</b>. + + This program does not currently have permission to write to the file you have selected. Please make sure you have write permission for this file before attempting to save it. Alternatively, you can use the Save As... menu option to save to a writable location. + - + Opening document... Otwórz dokument... - - - + + + + Abort Anuluj - + + An unknown error occurred while trying to load the file and we are not able to load your file. + + + + Saving document... Zapisuje dokument... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>Wystąpił błąd i plik nie został pomyślnie zapisany. Jeśli uważasz, że ten błąd dotyczy programu Pencil2D, utwórz nowy problem na stronie:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Pamiętaj, by w swoim zgłoszeniu uwzględnić następujące szczegóły: - + This animation has been modified. Do you want to save your changes? Animacja została zmieniona. Czy zapisać zmiany? - + The animation is not saved yet. Do you want to save now? Animacja jeszcze nie została zapisana. Czy zapisać ją teraz? - + Never ask again AutoSave reminder button Nigdy więcej nie pytaj - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Nie można importować obrazu.<br><b>Podpowiedź:</b> Użyj warstwy bitmapowej dla importu bitmapy. - + Importing image sequence... Importowanie sekwencji obrazów... - + + was unable to import nie można importować - - + + Importing Animated GIF... + + + + + Undo Menu item text Cofnij - + Redo Menu item text Ponów - + Stop Stop + + MoveTool + + + Layer switch + Windows title of layer switch pop-up. + + + + + You are about to switch layer, do you want to apply the transformation? + + + Object - + Black czarny - + Red Czerwony - + Dark Red Ciemny czerwony - + Orange Pomarańczowy - + Dark Orange Ciemny pomarańczowy - + Yellow Żółty - + Dark Yellow Ciemny żółty - + Green Zielony - + Dark Green Ciemny zielony - + Cyan Cyan - + Dark Cyan Ciemny cyan - + Blue Niebieski - + Dark Blue Ciemny niebieski - + White Biały - + Very Light Grey Bardzo jasny szary - + Light Grey Jasny szary - + Grey Szary - + Dark Grey Ciemny szary - + Light Skin Jasna skóra - + Light Skin - shade Jasna skóra - odcień - + Skin Skóra - + Skin - shade Skóra - odcień - + Dark Skin Ciemna skóra - + Dark Skin - shade Ciemna skóra - odcień @@ -1737,153 +1927,153 @@ Czy zapisać ją teraz? PencilApplication - + Pencil2D is an animation/drawing software for Mac OS X, Windows, and Linux. It lets you create traditional hand-drawn animation (cartoon) using both bitmap and vector graphics. Pencil2D to program do animacji / rysowania dla systemów Mac OS X, Windows i Linux. Pozwala tworzyć tradycyjne ręcznie rysowane animacje (rysunki) za pomocą zarówno bitmapy, jak i grafiki wektorowej. - + Path to the input pencil file. Ścieżka dla pliku programu pencil. - - + + Render the file to <output_path> Renderuj plik do: <output_path> - - + + output_path ścieżka wyjścia - + Name of the camera layer to use Nazwa warstwy kamery do użycia - + layer_name Nazwa warstwy - + Width of the output frames Szerokość krawędzi klatek - - + + integer liczba całkowita - + Height of the output frames Wysokość krawędzi klatek - + The first frame you want to include in the exported movie Pierwsza klatka, którą chcesz uwzględnić w wyeksportowanym filmie - - + + frame klatka - + The last frame you want to include in the exported movie. Can also be last or last-sound to automatically use the last frame containing animation or sound, respectively Ostatnia klatka, którą chcesz uwzględnić w wyeksportowanym filmie. Może również być ostatnią lub ostatnim-dźwiękiem, aby automatycznie użyć ostatniej klatki zawierającej odpowiednio animację lub dźwięk - + Render transparency when possible Renderuj przezroczystość, gdy to możliwe - + Warning: width value %1 is not an integer, ignoring. Uwaga: szerokość: %1 nie jest wartością całkowitą, wprowadzonie zostaje zignorowane. - + Warning: height value %1 is not an integer, ignoring. Uwaga: wysokość: %1 nie jest wartością całkowitą, wprowadzonie zostaje zignorowane. - + Warning: start value %1 is not an integer, ignoring. Uwaga: wartość początkowa: %1 nie jest wartością całkowitą, wprowadzonie zostaje zignorowane. - + Warning: start value must be at least 1, ignoring. Uwaga: wartość początkowa musi wynosić co najmniej 1, wprowadzonie zostaje zignorowane. - + Warning: end value %1 is not an integer, last or last-sound, ignoring. Uwaga: wartość końcowa: %1 nie jest wartością całkowitą, wprowadzonie zostaje zignorowane. - + Warning: end value %1 is smaller than start value %2, ignoring. Uwaga: wartość końca: %1 jest mniejsza niż wartość początkowa %2, wprowadzonie zostaje zignorowane. - + Error: No input file specified. Błąd: nie określono pliku. - + Error: the input file at '%1' does not exist Command line error Błąd: wskazany plik w '%1' nie istnieje - + Error: the input path '%1' is not a file Command line error Błąd: wskazana ścieżka '%1' nie jest plikiem - + Warning: the specified camera layer %1 was not found, ignoring. Uwaga: nie znaleziono określonej warstwa kamery %1, ignoruję akcję. - + Warning: Output format is not specified or unsupported. Using PNG. Command line warning Uwaga: format wyjściowy jest nie określony lub nie obsługiwany. Przejście do użycia PNG. - + Warning: Transparency is not currently supported in movie files Command line warning Uwaga: przezroczystość aktualnie nie jest obsługiwana dla plików filmowych - + Exporting movie... Command line task progress Eksportuje film... - - + + Done. Command line task done Gotowe. - + Exporting image sequence... Command line task progress Eksportowanie sekwencji obrazów... @@ -1925,12 +2115,12 @@ Czy zapisać ją teraz? QApplication - + Checking environment... Sprawdzanie środowiska... - + Done Gotowe @@ -1938,42 +2128,47 @@ Czy zapisać ją teraz? QObject - + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) - - Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) - Obrazy (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp) + + + + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp); + - + Everything ok. Wszystko ok. - + Ooops, Something went wrong. Oj, coś poszło nie tak. - + File doesn't exist. Plik nie istnieje. - + Cannot open file. Nie można otworzyć pliku. - + The file is not a valid xml document. Plik nie jest prawidłowym dokumentem XML. - + The file is not valid pencil document. Plik nie jest prawidłowym dokumentem ołówka. @@ -3322,6 +3517,16 @@ Czy zapisać ją teraz? Black Czarny + + + Could not open file + + + + + There was an error processing your file. This usually means that your project has been at least partially corrupted. You can try again with a newer version of Pencil2D, or you can try to use a backup file if you have one. If you contact us through one of our offical channels we may be able to help you. For reporting issues, the best places to reach us are: + + RecentFileMenu @@ -3339,61 +3544,61 @@ Czy zapisać ją teraz? ScribbleArea - + Warning Uwaga - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Aktualnie rysujesz na ukrytej warstwie! Użyj innej warstwy (albo zmień obecną warstwę na widoczną). - + Delete Selection Undo Step: clear the selection area. Usuń zaznaczenie - - + + Clear Image Undo step text Czyść obraz - + There is a gap in your drawing (or maybe you have zoomed too much). Znaleziono lukę w rysunku (bądź obraz został za bardzo powiększony). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). Przepraszam! Ta opcja nie zawsze działa poprawnie. Spróbuj ponownie (powiększ nieco, kliknij w inne miejsce...)<br> jeżeli to nie pomoże, to spróbuj powiększyć i sprawdź, czy ścieżki są połączone (naciskając klawisz F1). - + Out of bound. Brak powiązania. - + Could not find a closed path. Nie można znaleźć zamkniętej ścieżki. - + Could not find the root index. Nie można znaleźć głównego indeksu. - + %1<br><br>Error: %2 %1<br><br>Błąd: %2 - + Flood fill error Błąd napełnianiu wypełnienia @@ -3490,12 +3695,12 @@ jeżeli to nie pomoże, to spróbuj powiększyć i sprawdź, czy ścieżki są p - + Start Początek - + Stop Stop @@ -3579,18 +3784,18 @@ jeżeli to nie pomoże, to spróbuj powiększyć i sprawdź, czy ścieżki są p Przełącz dopasowane klatki kluczowe - + Delete Layer Windows title of Delete current layer pop-up. Usuń warstwę - + Please keep at least one camera layer in project Zachowaj co najmniej jedną warstwę kamery w projekcie - + Are you sure you want to delete layer: Czy na pewno chcesz usunąć warstwę: @@ -3598,12 +3803,12 @@ jeżeli to nie pomoże, to spróbuj powiększyć i sprawdź, czy ścieżki są p TimeLineCells - + Layer Properties Właściwości warstwy - + Layer name: Nazwa warstwy: @@ -3680,6 +3885,16 @@ jeżeli to nie pomoże, to spróbuj powiększyć i sprawdź, czy ścieżki są p <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> <html><head/><body><p>(Ustawienie dotyczy narzędzi: ołówek, gumka, pióro, linia, wypełniacz i pędzel)</p></body></html> + + + Playback + + + + + Show onion skin while playing + + Frame size diff --git a/translations/pencil_pt.qm b/translations/pencil_pt.qm index 684f561f985eaa494817c9dabf0725f28e56b68e..e053209342135d64c01d227debb2dad93cefc443 100644 GIT binary patch delta 10319 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 delta 6977 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 diff --git a/translations/pencil_pt.ts b/translations/pencil_pt.ts index 82294336f..1370c408d 100644 --- a/translations/pencil_pt.ts +++ b/translations/pencil_pt.ts @@ -13,13 +13,13 @@ Site Oficial: <a href="https://www.pencil2d.org">pencil2d.org</a><br>Desenvolvido por: <b>Pascal Naidon, Patrick Corrieri, Matt Chang</b><br>Agradecimentos a: Qt Framework <a href="https://www.qt.io/download">https://www.qt.io/</a><br>miniz: <a href="https://github.com/richgel999/miniz">https://github.com/richgel999/miniz</a><br>Distribuído através de: <a href="http://www.gnu.org/licenses/gpl-2.0.html">GNU General Public License, versão 2</a> - + Version: %1 Version Number in About Dialog Versão: %1 - + Copy to clipboard Copy system info from About Dialog Copiar para área de transferência @@ -55,30 +55,30 @@ Camada de Som - + Exporting movie - Exportar filme + Exportando vídeo - + Finished. Open movie now? When movie export done. - Concluído. Abrir o filme agora? + Concluído. Abrir o vídeo agora? - - - - + + + + Layer Properties Propriedades da Camada - - - - + + + + Layer name: Nome da Camada: @@ -88,58 +88,63 @@ Já existe um clipe de som neste quadro! Por favor seleccione outro quadro ou camada - + + Finished. Open file location? + Finalizado. Abrir localização do ficheiro? + + + Exporting image sequence... Exportando sequência de imagens - + Abort Abortar - + Warning Aviso - + Unable to export image. Não é possível exportar imagem - + Bitmap Layer Camada Bitmap - + Vector Layer Camada Vectorial - + Camera Layer Camada da Câmara - + Sound Layer Camada de Som - + Delete Layer Windows title of Delete current layer pop-up. Excluir Camada - + Are you sure you want to delete layer: Tem certeza de que quer excluir a camada: - + Please keep at least one camera layer in project text when failed to delete camera layer Por favor, mantenha pelo menos uma câmara no projecto @@ -148,57 +153,57 @@ BaseTool - + Pencil Lápis - + Eraser Borracha - + Select Seleccionar - + Move Mover - + Hand Mão - + Smudge Espalhar - + Pen Caneta - + Polyline Polilinha - + Bucket Balde - + Eyedropper Conta-gotas - + Brush Pincel @@ -224,69 +229,55 @@ ColorBox - - Color Wheel - Color Wheel's window title - Roda de Cor + + Color Box + Color Box window title + Caixa de cor ColorInspector - + HSV HSV - + RGB RGB - - - Red - Vermelho - - - - - Green - Verde + + R + R - - - Blue - Azul - - - - - - Alpha - Transparência + + A + A - - Hue - Matiz + + G + G - - Saturation - Saturação + + B + B - - Value - Valor + + Color Inspector + Window title of color inspector + Selector de cor ColorPalette - + Color Palette Window title of color palette. Paleta de cor @@ -302,57 +293,57 @@ Remover Cor - - ... - ... + + Native color dialog window + - + List Mode Modo Lista - + Show palette as a list Mostrar paleta como Lista - + Grid Mode Modo Grelha - + Show palette as icons Mostrar paleta como Icones - + Small swatch Amostra pequena - + Sets swatch size to: 16x16px Dimensionar amostra a: 16x16px - + Medium Swatch Amostra média - + Sets swatch size to: 26x26px Dimensionar amostra a: 26x26px - + Large Swatch Amostra grande - + Sets swatch size to: 36x36px Dimensionar amostra a: 36x36px @@ -360,11 +351,60 @@ ColorPaletteWidget - - + + Add + Adicionar + + + + Replace + Substituir + + + + Remove + Remover + + + + Colour name Nome da cor + + + The color(s) you are about to delete are currently being used by one or multiple strokes. + A cor (ou cores) que está a tentar excluir está a ser utilizada. + + + + Cancel + Cancelar + + + + Delete + Excluir + + + + Palette Restriction + + + + + The palette requires at least one swatch to remain functional + + + + + ColorWheel + + + Color Wheel + Color Wheel's window title + Roda de cores + DisplayOption @@ -446,19 +486,19 @@ Editor - - + + Paste Colar - + Remove frame Remover quadro - - + + Import Image Importar imagem @@ -484,12 +524,12 @@ ExportImageDialog - + Export image sequence Exportar sequência de imagens - + Export image Exportar imagem @@ -531,11 +571,51 @@ Transparency Transparência + + + Range + Intervalo + + + + The last frame you want to include in the exported movie + Último quadro a ser incluído na exportação do vídeo + + + + End Frame + Último Quadro + + + + The first frame you want to include in the exported movie + Primeiro quadro a ser incluído na exportação do vídeo + + + + Start Frame + Primeiro Quadro + + + + <html><head/><body><p>End frame is set to last paintable keyframe (Useful when you only want to export to the last animated frame)</p></body></html> + + + + + To the end of sound clips + + ExportMovieDialog - + + Export Animated GIF + Exportar GIF Animado + + + Export Movie Exportar vídeo @@ -585,7 +665,7 @@ Start Frame - Quadro de início + Primeiro Quadro @@ -627,67 +707,83 @@ + Import Animated GIF + Importar GIF Animado + + + Import movie Importar vídeo - + Import sound Importar som - + Import palette Importar paleta - + Save animation Gravar animação - + Export image Exportar imagem - + Export image sequence Exportar sequência de imagens - + + Export Animated GIF + Exportar GIF Animado + + + Export movie Exportar vídeo - + Export sound Exportar som - + Export palette Exportar paleta - + + + Animated GIF (*.gif) + GIF Animado (*.gif) + + + Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) Sons (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) - - - Palette (*.xml) - Paleta (*.xml) + + + Pencil2D Palette (*.xml);; Gimp Palette (*.gpl) + Paleta Pencil2D (*.xml);; Paleta Gimp (*.gpl) - - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) + + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng) + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng) - + MyAnimation.pclx MinhaAnimação.pclx @@ -695,52 +791,72 @@ FileManager - - - + + + Could not open file + Não foi possível abrir o ficheiro + + + + The file does not exist, so we are unable to open it. Please check to make sure the path is correct and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + Invalid Save Path Caminho de gravação inválido - + The path ("%1") points to a directory. O caminho ("%1") aponta para um directório. - + The directory ("%1") does not exist. O directório ("%1") não existe. - + The path ("%1") is not writable. O caminho ("%1") não está acessível para escrita - - + + Cannot Create Data Directory Não é possível criar um directório de dados - + Failed to create directory "%1". Please make sure you have sufficient permissions. Falha na criação do directório "%1". Verifique se tem permissões suficientes. - + "%1" is a file. Please delete the file and try again. "%1" é um ficheiro. Por favor exclua o ficheiro e tente novamente. - - + + Miniz Error + + + + Internal Error Erro interno - - + + An internal error occurred. Your file may not be saved successfully. Um erro interno ocorreu. O ficheiro pode não ter sido gravado com sucesso. @@ -818,87 +934,97 @@ Grelha - + Czech Checo - + Danish Dinamarquês - + English Inglês - + German Alemão - + + Estonian + Estónia + + + Spanish Espanhol - + French Francês - + Hebrew Hebreu - + Hungarian Húngaro - + Indonesian Indonésio - + Italian Italiano - + Japanese Japonês - + + Polish + Polónia + + + Portuguese - Portugal Português - Portugal - + Portuguese - Brazil Português - Brasil - + Russian Russo - + Slovenian Eslovénia - + Vietnamese Vietname - + Chinese - Taiwan Chinês - Taiwan @@ -943,12 +1069,12 @@ Alta resolução para tablet - + Restart Required Reinício requerido - + The language change will take effect after a restart of Pencil2D A mudança de idioma tomará efeito após reiniciar Pencil2D @@ -974,7 +1100,12 @@ ImportImageSeqDialog - + + Import Animated GIF + Importar GIF Animado + + + Import image sequence Importar sequência de imagens @@ -998,7 +1129,7 @@ LayerBitmap - + Bitmap Layer Camada Bitmap @@ -1014,7 +1145,7 @@ LayerSound - + Sound Layer Camada de Som @@ -1045,473 +1176,484 @@ Importar - + Export Exportar - + Edit Editar - + Selection Selecção - + View Visualizar - + Onion Skin Transparência - + Animation Animação - - + + Tools Ferramentas - + Layer Camada - - + + Help Ajuda - + Windows Janelas - + New Novo - + Open Abrir - + Save Gravar - + Save As .. Gravar como... - + Exit Sair - - + + Image Sequence... Sequência de imagens... - - + + Image... Imagem... - - + + Movie... - Filme... + Vídeo... - - + + Palette... Paleta... - + Sound... Som... - + Undo Desfazer - + Redo Refazer - + Cut Cortar - + Copy Copiar - + Paste Colar - + Crop Recortar - + Crop To Selection Ajustar à selecção - + Select All Seleccionar Tudo - + Deselect All Desmarcar Tudo - - + + Clear Frame Limpar Quadro - + Preferences Preferências - + Reset Windows Reiniciar Janelas - + Zoom In Aproximar - + Zoom Out Afastar - + Rotate Clockwise Girar no sentido horário - + Rotate AntiClosewise Girar no sentido anti-horário - + Reset Zoom/Rotate Restaurar zoom/rotação - + Horizontal Flip Virar horizontalmente - + Vertical Flip Virar verticalmente - + Preview Pré-visualização - + Grid Grelha - + Previous Anterior - + Show previous onion skin Mostrar transparência anterior - + Next Seguinte - + Show next onion skin Mostra transparência seguinte - - + + Play Reproduzir - + Loop Repetir - + Next Frame Quadro seguinte - + Previous Frame Quadro anterior - + Extend Frame Estender quadro - + Add Frame Adicionar quadro - + Duplicate Frame Duplicar quadro - + Remove Frame Remover quadro - + Move Mover - + Select Seleccionar - + Brush Pincel - + Polyline Polilinha - + Smudge Espalhar - + Pen Caneta - + Hand Mão - + Pencil Lápis - + Bucket Balde - + Eyedropper Conta-gotas - + Eraser Borracha - + New Bitmap Layer Nova Camada Bitmap - + New Vector Layer Nova Camada Vectorial - + New Sound Layer Nova Camada de Som - + New Camera Layer Nova camada da câmara - + Delete Current Layer Excluir Camada Actual - + About Sobre - - + + Reset to default Restaurar definições padrão - + MultiLayer Onion Skin Transparência Multicamadas - + Range Intervalo - + Pencil2D Website Site Pencil2D - + Report a Bug Reportar falha - + Quick Reference Guide Manual de Consulta Rápida - + F1 F1 - - + + + Animated GIF... + GIF Animado + + + + Next KeyFrame Quadro-chave seguinte - - + + Previous KeyFrame Quadro-chave anterior - + Timeline Linha do tempo - + Options Opções - + Color Wheel Roda de Cores - + Color Palette Paleta de Cores - + Display Options Opções de visualização - + Flip X Virar X - + Flip Y Virar Y - + Move Frame Forward Mover Quadro para Frente - + Move Frame Backward Mover Quadro para Trás - + color palette:<br>use <b>(C)</b><br>toggle at cursor Paleta de cores:<br>Utilize <b>(C)</b><br>para alternar no cursor - + + Color inspector + Selector de cor + + + Lock Windows Bloquear Janelas - + Open Recent Abrir Recente - + You have successfully cleared the list @@ -1519,214 +1661,262 @@ Acabou de limpar a lista com sucesso - - - - - + + + + + Could not open file + Não foi possível abrir o ficheiro + + + + The file you have selected is a directory, so we are unable to open it. If you are are trying to open a project that uses the old structure, please open the file ending with .pcl, not the data folder. + + + + + The file you have selected does not exist, so we are unable to open it. Please check to make sure that you've entered the correct path and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + + + Warning Aviso - - - Pencil cannot read this file. If you want to import images, use the command import. - Pencil não consegue ler este arquivo. Se você quiser importar imagens, use o comando Importar. + + This program does not currently have permission to write to the file you have selected. Please make sure you have write permission for this file before attempting to save it. Alternatively, you can use the Save As... menu option to save to a writable location. + - + Opening document... Abrindo documento... - - - + + + + Abort Abortar - + + An unknown error occurred while trying to load the file and we are not able to load your file. + Um erro interno ocorreu enquanto carregava o ficheiro. Não é possível carregar o ficheiro. + + + Saving document... Gravando documento... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>Ocorreu um erro e seu ficheiro pode não ter sido gravado com sucesso. Se você achar que é um problema com Pencil2D, por favor crie um tópico em: <br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Por favor, certifique-se de incluir os seguintes detalhes: - + This animation has been modified. Do you want to save your changes? Esta animação foi modificada. Deseja gravar as alterações? - + The animation is not saved yet. Do you want to save now? A animação não foi gravada. Quer gravá-la agora? - + Never ask again AutoSave reminder button Não voltar a perguntar - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Não é possível importar imagem. <br><b>DICA:</b> Use uma Camada Bitmap para importar bitmaps. - + Importing image sequence... Importando sequência de imagens... - + + was unable to import - + Não foi possível importar + + + + Importing Animated GIF... + Importando GIF Animado... - - + + Undo Menu item text Desfazer - + Redo Menu item text Refazer - + Stop Parar + + MoveTool + + + Layer switch + Windows title of layer switch pop-up. + Troca de camada + + + + You are about to switch layer, do you want to apply the transformation? + Está prestes a trocar de camada, quer aplicar as alterações? + + Object - + Black Preto - + Red Vermelho - + Dark Red Vermelho escuro - + Orange Laranja - + Dark Orange Laranja escuro - + Yellow Amarelo - + Dark Yellow Amarelo escuro - + Green Verde - + Dark Green Verde escuro - + Cyan Ciano - + Dark Cyan Ciano escuro - + Blue Azul - + Dark Blue Azul escuro - + White Branco - + Very Light Grey Cinza muito claro - + Light Grey Cinza claro - + Grey Cinza - + Dark Grey Cinza escuro - + Light Skin Pele clara - + Light Skin - shade Pele clara - sombra - + Skin Pele - + Skin - shade Pele - sombra - + Dark Skin Pele escura - + Dark Skin - shade Pele escura - sombra @@ -1734,153 +1924,153 @@ Deseja gravar as alterações? PencilApplication - + Pencil2D is an animation/drawing software for Mac OS X, Windows, and Linux. It lets you create traditional hand-drawn animation (cartoon) using both bitmap and vector graphics. Pencil2D é um programa de animação/desenho para Mac OS X, Windows e Linux. Permite criar animações tradicionais feitas a mão (desenhos animados) utilizando bitmaps e vectores gráficos. - + Path to the input pencil file. Caminho para o ficheiro de Pencil2D - - + + Render the file to <output_path> Renderizar o ficheiro no <output_path> - - + + output_path caminho_saída - + Name of the camera layer to use Nome da Câmara a utilizar - + layer_name Nome_Camada - + Width of the output frames Largura dos quadros de saída - - + + integer Número Inteiro - + Height of the output frames Altura dos quadros de saída - + The first frame you want to include in the exported movie - Primeiro quadro a ser incluído na exportação do filme + Primeiro quadro a ser incluído na exportação do vídeo - - + + frame Quadro - + The last frame you want to include in the exported movie. Can also be last or last-sound to automatically use the last frame containing animation or sound, respectively - Último quadro a ser incluído na exportação do filme. Poderá ser utilizado automaticamente por um quadro contendo uma animação ou som + Último quadro a ser incluído na exportação do vídeo. Poderá ser utilizado automaticamente por um quadro contendo uma animação ou som - + Render transparency when possible Renderizar transparência quando possível - + Warning: width value %1 is not an integer, ignoring. Aviso: valor da largura %1 não é um número inteiro. Ignorando. - + Warning: height value %1 is not an integer, ignoring. Aviso: valor da altura %1 não é um número inteiro. Ignorando. - + Warning: start value %1 is not an integer, ignoring. Aviso: valor de início %1 não é um número inteiro. Ignorando. - + Warning: start value must be at least 1, ignoring. Aviso: valor de início deve ser pelo menos 1. Ignorando. - + Warning: end value %1 is not an integer, last or last-sound, ignoring. Aviso: valor final %1 não é um número inteiro. Ignorando. - + Warning: end value %1 is smaller than start value %2, ignoring. Aviso: valor final %1 é mais pequeno que o valor de início %2. Ignorando. - + Error: No input file specified. - Erro: Nenhum arquivo especificado. + Erro: Nenhum ficheiro especificado. - + Error: the input file at '%1' does not exist Command line error Erro: o ficheiro em '%1' não existe - + Error: the input path '%1' is not a file Command line error Erro: O caminho seleccionado '%1' não é um ficheiro - + Warning: the specified camera layer %1 was not found, ignoring. Aviso: a camada da câmara especificada %1 não foi encontrada. Ignorando. - + Warning: Output format is not specified or unsupported. Using PNG. Command line warning Aviso: O formato de saída não foi especificado ou não é suportado. Utilizar PNG. - + Warning: Transparency is not currently supported in movie files Command line warning - Aviso: Transparência não é actualmente suportada em ficheiros de filme + Aviso: Transparência não é actualmente suportada em ficheiros de vídeo - + Exporting movie... Command line task progress - Exportando filme... + Exportando vídeo... - - + + Done. Command line task done Concluído. - + Exporting image sequence... Command line task progress Exportando Sequência de Imagens @@ -1922,12 +2112,12 @@ Deseja gravar as alterações? QApplication - + Checking environment... Verificando o sistema... - + Done Concluído @@ -1935,42 +2125,47 @@ Deseja gravar as alterações? QObject - + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) - - Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) - + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp) + Imagens (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp) - + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp); + Imagens (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp); + + + Everything ok. Tudo certo. - + Ooops, Something went wrong. Opa! Alguma coisa deu errado. - + File doesn't exist. O ficheiro não existe. - + Cannot open file. Não é possível abrir o ficheiro. - + The file is not a valid xml document. O ficheiro não é um documento XML válido. - + The file is not valid pencil document. O ficheiro não é um documento Pencil2D válido. @@ -3319,6 +3514,16 @@ Deseja gravar as alterações? Black Preto + + + Could not open file + Não foi possível abrir o ficheiro + + + + There was an error processing your file. This usually means that your project has been at least partially corrupted. You can try again with a newer version of Pencil2D, or you can try to use a backup file if you have one. If you contact us through one of our offical channels we may be able to help you. For reporting issues, the best places to reach us are: + + RecentFileMenu @@ -3336,60 +3541,60 @@ Deseja gravar as alterações? ScribbleArea - + Warning Aviso - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Você está desenhando em uma camada oculta! Por favor, seleccione outra camada (ou torne a camada actual visível). - + Delete Selection Undo Step: clear the selection area. Excluir selecção - - + + Clear Image Undo step text Limpar Imagem - + There is a gap in your drawing (or maybe you have zoomed too much). Há uma abertura no seu desenho (ou talvez tenha aumentado o zoom demasiado). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). Desculpe! Isto nem sempre funciona. Por favor tente novamente (aumente um pouco o zoom, clique em outro lugar... )<br>Caso não funcione, aumente um pouco o zoom e certifique-se que os caminhos estão conectados pressionando F1). - + Out of bound. Fora do limite - + Could not find a closed path. Não é possível encontrar um caminho fechado. - + Could not find the root index. Não é possível encontrar o índice principal - + %1<br><br>Error: %2 %1<br><br>Erro: %2 - + Flood fill error Erro de preenchimento @@ -3486,12 +3691,12 @@ Deseja gravar as alterações? - + Start Início - + Stop Parar @@ -3575,18 +3780,18 @@ Deseja gravar as alterações? Alternância quadros-chaves - + Delete Layer Windows title of Delete current layer pop-up. Excluir Camada - + Please keep at least one camera layer in project Por favor, mantenha pelo menos uma câmara no projecto - + Are you sure you want to delete layer: Tem certeza de que quer excluir a camada: @@ -3594,12 +3799,12 @@ Deseja gravar as alterações? TimeLineCells - + Layer Properties Propriedades da Camada - + Layer name: Nome da Camada: @@ -3639,43 +3844,53 @@ Deseja gravar as alterações? Drawing - + Desenho When drawing on an empty frame: - + Quando desenhe num quadro vazio: Create a new (blank) key-frame and start drawing on it. - + Adicione um novo quadro-chave e comece a desenhar nele. Create a new (blank) key-frame - + Adicione um quadro-chave novo Duplicate the previous key-frame and start drawing on the duplicate. - + Duplique o quadro-chave anterior e comece a desenhar nele. Duplicate the previous key-frame - + Duplicar quadro-chave anterior Keep drawing on the previous key-frame - + Continue desenhando no quadro-chave anterior <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + + Playback + Ciclo de reprodução + + + + Show onion skin while playing + Mostrar transparência enquanto reproduz animação + Frame size diff --git a/translations/pencil_pt_BR.qm b/translations/pencil_pt_BR.qm index bde27bc13445ca104e511f046bfe0df178e3154f..6f4aa427e4f2eb01f0d84c17e6b5ec3796569c38 100644 GIT binary patch delta 9274 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 F`hP??DjNU* diff --git a/translations/pencil_pt_BR.ts b/translations/pencil_pt_BR.ts index 68eb85ff1..e186adfb4 100644 --- a/translations/pencil_pt_BR.ts +++ b/translations/pencil_pt_BR.ts @@ -13,13 +13,13 @@ Site oficial: <a href="https://www.pencil2d.org">pencil2d.org</a><br>Desenvolvido por: <b>Pascal Naidon, Patrick Corrieri, Matt Chang</b><br>Graças a QT Framework <a href="https://www.qt.io/download">https://www.qt.io/</a><br>miniz: <a href="https://github.com/richgel999/miniz">https://github.com/richgel999/miniz</a><br>Distribuído sob a <a href="http://www.gnu.org/licenses/gpl-2.0.html">Licença Pública Geral GNU, versão 2</a> - + Version: %1 Version Number in About Dialog Versão: %1 - + Copy to clipboard Copy system info from About Dialog Copiar para área de transferência @@ -55,30 +55,30 @@ Camada de Som - + Exporting movie Exportando vídeo - + Finished. Open movie now? When movie export done. Finalizado. Abrir vídeo agora? - - - - + + + + Layer Properties Propriedades da camada - - - - + + + + Layer name: Nome da camada: @@ -88,58 +88,63 @@ Já existe um clipe de som neste quadro! Por favor selecione outro quadro ou camada - + + Finished. Open file location? + Finalizado. Abrir local do arquivo? + + + Exporting image sequence... Exportando sequência de imagens... - + Abort Abortar - + Warning Aviso - + Unable to export image. Impossível exportar imagem. - + Bitmap Layer Camada Bitmap - + Vector Layer Camada Vetorial - + Camera Layer Camada de Câmera - + Sound Layer Camada de Som - + Delete Layer Windows title of Delete current layer pop-up. Apagar Camada - + Are you sure you want to delete layer: Você tem certeza de que deseja apagar a camada: - + Please keep at least one camera layer in project text when failed to delete camera layer Por favor, mantenha ao menos uma camada de câmera no projeto @@ -148,57 +153,57 @@ BaseTool - + Pencil Lápis - + Eraser Borracha - + Select Selecionar - + Move Mover - + Hand Mão - + Smudge Borrar - + Pen Caneta - + Polyline Polilinha - + Bucket Balde - + Eyedropper Conta-gotas - + Brush Pincel @@ -224,69 +229,55 @@ ColorBox - - Color Wheel - Color Wheel's window title - Roda de Cores + + Color Box + Color Box window title + ColorInspector - + HSV HSV - + RGB RGB - - - Red - Vermelho - - - - - Green - Verde - - - - - Blue - Azul + + R + R - - - - Alpha - Alfa + + A + A - - Hue - Matiz + + G + G - - Saturation - Saturação + + B + B - - Value - Valor + + Color Inspector + Window title of color inspector + Inspetor de Cores ColorPalette - + Color Palette Window title of color palette. Paleta de Cores @@ -302,57 +293,57 @@ Remover Cor - - ... - ... + + Native color dialog window + - + List Mode Modo Lista - + Show palette as a list Mostrar paleta como lista - + Grid Mode Modo Grade - + Show palette as icons Mostrar paleta como ícones - + Small swatch Amostra pequena - + Sets swatch size to: 16x16px Dimensiona amostra para: 16x16px - + Medium Swatch Amostra Média - + Sets swatch size to: 26x26px Dimensionar amostra para: 26x26px - + Large Swatch Amostra Grande - + Sets swatch size to: 36x36px Dimensionar amostra para: 36x36px @@ -360,11 +351,60 @@ ColorPaletteWidget - - + + Add + Adicionar + + + + Replace + Substituir + + + + Remove + Remover + + + + Colour name Nome da cor + + + The color(s) you are about to delete are currently being used by one or multiple strokes. + + + + + Cancel + Cancelar + + + + Delete + Apagar + + + + Palette Restriction + + + + + The palette requires at least one swatch to remain functional + + + + + ColorWheel + + + Color Wheel + Color Wheel's window title + + DisplayOption @@ -446,19 +486,19 @@ Editor - - + + Paste Colar - + Remove frame Remover quadro - - + + Import Image Importar imagem @@ -484,12 +524,12 @@ ExportImageDialog - + Export image sequence Exportar sequência de imagens - + Export image Exportar imagem @@ -531,11 +571,51 @@ Transparency Transparência + + + Range + Intervalo + + + + The last frame you want to include in the exported movie + + + + + End Frame + Quadro Final + + + + The first frame you want to include in the exported movie + + + + + Start Frame + Quadro inicial + + + + <html><head/><body><p>End frame is set to last paintable keyframe (Useful when you only want to export to the last animated frame)</p></body></html> + <html><head/><body><p>Quadro final é ajustado para o último quadro pintável (Útil quando você quiser exportar até o último quadro da animação)</p></body></html> + + + + To the end of sound clips + Até o final dos clipes de som + ExportMovieDialog - + + Export Animated GIF + Exportar GIF animado + + + Export Movie Exportar vídeo @@ -627,67 +707,83 @@ + Import Animated GIF + Importar GIF animado + + + Import movie Importar vídeo - + Import sound Importar som - + Import palette Importar paleta - + Save animation Salvar animação - + Export image Exportar imagem - + Export image sequence Exportar sequência de imagens - + + Export Animated GIF + Exportar GIF animado + + + Export movie Exportar vídeo - + Export sound Exportar som - + Export palette Exportar paleta - + + + Animated GIF (*.gif) + GIF animado (*.gif) + + + Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) Sons (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) - - - Palette (*.xml) - Paleta (*.xml) + + + Pencil2D Palette (*.xml);; Gimp Palette (*.gpl) + Paleta do Pencil2D (*.xml);; Paleta do GIMP (*.gpl) - - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) + + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng) + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng) - + MyAnimation.pclx MinhaAnimação.pclx @@ -695,52 +791,72 @@ FileManager - - - + + + Could not open file + Não foi possível abrir o arquivo + + + + The file does not exist, so we are unable to open it. Please check to make sure the path is correct and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + Invalid Save Path Caminho inválido - + The path ("%1") points to a directory. O caminho ("%1") aponta para uma pasta. - + The directory ("%1") does not exist. A pasta ("%1") não existe. - + The path ("%1") is not writable. O caminho ("%1") não pode ser escrito. - - + + Cannot Create Data Directory Impossível criar uma pasta de dados - + Failed to create directory "%1". Please make sure you have sufficient permissions. Falha ao criar a pasta "%1". Por favor, tenha certeza de que você tem permissões suficientes. - + "%1" is a file. Please delete the file and try again. "%1" é um arquivo. Por favor, apague o arquivo e tente novamente. - - + + Miniz Error + Erro do Miniz + + + Internal Error Erro interno - - + + An internal error occurred. Your file may not be saved successfully. Um erro interno ocorreu. Seu arquivo pode não ter sido salvo com sucesso. @@ -818,87 +934,97 @@ Grade - + Czech Checo - + Danish Dinamarquês - + English Inglês - + German Alemão - + + Estonian + + + + Spanish Espanhol - + French Francês - + Hebrew Hebraico - + Hungarian Húngaro - + Indonesian Indonésio - + Italian Italiano - + Japanese Japonês - + + Polish + Polonês + + + Portuguese - Portugal Português - Portugal - + Portuguese - Brazil Português - Brasil - + Russian Russo - + Slovenian Esloveno - + Vietnamese Vietnamita - + Chinese - Taiwan Chinês - Taiwan @@ -943,12 +1069,12 @@ Posição de alta resolução do tablet - + Restart Required Reinício requerido - + The language change will take effect after a restart of Pencil2D A mudança de idioma tomará efeito depois de reiniciar Pencil2D @@ -974,7 +1100,12 @@ ImportImageSeqDialog - + + Import Animated GIF + Importar GIF animado + + + Import image sequence Importar sequência de imagens @@ -998,7 +1129,7 @@ LayerBitmap - + Bitmap Layer Camada Bitmap @@ -1014,7 +1145,7 @@ LayerSound - + Sound Layer Camada de Som @@ -1045,473 +1176,484 @@ Importar - + Export Exportar - + Edit Editar - + Selection Seleção - + View Visualizar - + Onion Skin Transparência - + Animation Animação - - + + Tools Ferramentas - + Layer Camada - - + + Help Ajuda - + Windows Janelas - + New Novo - + Open Abrir - + Save Salvar - + Save As .. Salvar como... - + Exit Sair - - + + Image Sequence... Sequência de imagens... - - + + Image... Imagem... - - + + Movie... Vídeo... - - + + Palette... Paleta... - + Sound... Som... - + Undo Desfazer - + Redo Refazer - + Cut Cortar - + Copy Copiar - + Paste Colar - + Crop Recortar - + Crop To Selection Recortar para a seleção - + Select All Selecionar Tudo - + Deselect All Desmarcar Tudo - - + + Clear Frame Limpar Quadro - + Preferences Preferências - + Reset Windows Reiniciar Janelas - + Zoom In Aproximar - + Zoom Out Afastar - + Rotate Clockwise Girar em sentido horário - + Rotate AntiClosewise Girar em sentido anti-horário - + Reset Zoom/Rotate Restaurar zoom/rotação - + Horizontal Flip Inverter horizontalmente - + Vertical Flip Virar verticalmente - + Preview Prévia - + Grid Grade - + Previous Anterior - + Show previous onion skin Mostrar transparência anterior - + Next Próxima - + Show next onion skin Mostrar próxima transparência - - + + Play Reproduzir - + Loop Repetir - + Next Frame Próximo Quadro - + Previous Frame Quadro Anterior - + Extend Frame Estender Quadro - + Add Frame Adicionar Quadro - + Duplicate Frame Duplicar Quadro - + Remove Frame Remover Quadro - + Move Mover - + Select Selecionar - + Brush Pincel - + Polyline Polilinha - + Smudge Borrar - + Pen Caneta - + Hand Mão - + Pencil Lápis - + Bucket Balde - + Eyedropper Conta-gotas - + Eraser Borracha - + New Bitmap Layer Nova camada Bitmap - + New Vector Layer Nova camada Vetorial - + New Sound Layer Nova camada de Som - + New Camera Layer Nova camada de Câmera - + Delete Current Layer Apagar camada atual - + About Sobre - - + + Reset to default Restaurar para o padrão - + MultiLayer Onion Skin Transparência Multicamadas - + Range Intervalo - + Pencil2D Website Website do Pencil2D - + Report a Bug Reportar um Bug - + Quick Reference Guide Guia Rápido de Referência - + F1 F1 - - + + + Animated GIF... + GIF animado... + + + + Next KeyFrame Próximo quadro-chave - - + + Previous KeyFrame Quadro-chave anterior - + Timeline Linha do tempo - + Options Opções - + Color Wheel Roda de Cores - + Color Palette Paleta de Cores - + Display Options Opções da tela - + Flip X Inverter X - + Flip Y Inverter Y - + Move Frame Forward Mover Quadro para Frente - + Move Frame Backward Mover Quadro para Trás - + color palette:<br>use <b>(C)</b><br>toggle at cursor Paleta de cores:<br>Use <b>(C)</b><br>para alternar no cursor - + + Color inspector + Inspetor de cores + + + Lock Windows Bloquear Janelas - + Open Recent Abrir Recente - + You have successfully cleared the list @@ -1519,215 +1661,263 @@ Você limpou a lista com sucesso - - - - - + + + + + Could not open file + Não foi possível abrir o arquivo + + + + The file you have selected is a directory, so we are unable to open it. If you are are trying to open a project that uses the old structure, please open the file ending with .pcl, not the data folder. + + + + + The file you have selected does not exist, so we are unable to open it. Please check to make sure that you've entered the correct path and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + + + Warning Aviso - - - Pencil cannot read this file. If you want to import images, use the command import. - Pencil não consegue ler este arquivo. Se você quiser importar imagens, use o comando Importar. + + This program does not currently have permission to write to the file you have selected. Please make sure you have write permission for this file before attempting to save it. Alternatively, you can use the Save As... menu option to save to a writable location. + - + Opening document... Abrindo documento... - - - + + + + Abort Abortar - + + An unknown error occurred while trying to load the file and we are not able to load your file. + + + + Saving document... Salvando documento... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>Um erro ocorreu e seu arquivo pode não ter sido salvo com sucesso. Se você acredita que é um problema com Pencil2D, por favor crie um tópico em: <br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Por favor, certifique-se de incluir os seguintes detalhes: - + This animation has been modified. Do you want to save your changes? Esta animação foi modificada. Você deseja salvar suas alterações? - + The animation is not saved yet. Do you want to save now? A animação não foi salva. Gostaria de salvar agora? - + Never ask again AutoSave reminder button Não pergunte novamente - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Impossível importar imagem. <br><b>DICA:</b> Use uma camada Bitmap para importar bitmaps. - + Importing image sequence... Importando sequência de imagens... - + + was unable to import não é possivel importar - - + + Importing Animated GIF... + Importando GIF animado... + + + + Undo Menu item text Desfazer - + Redo Menu item text Refazer - + Stop Parar + + MoveTool + + + Layer switch + Windows title of layer switch pop-up. + + + + + You are about to switch layer, do you want to apply the transformation? + Você irá trocar de camada. Deseja aplicar a transformação? + + Object - + Black Preto - + Red Vermelho - + Dark Red Vermelho escuro - + Orange Laranja - + Dark Orange Laranja escuro - + Yellow Amarelo - + Dark Yellow Amarelo escuro - + Green Verde - + Dark Green Verde escuro - + Cyan Ciano - + Dark Cyan Ciano escuro - + Blue Azul - + Dark Blue Azul escuro - + White Branco - + Very Light Grey Cinza muito claro - + Light Grey Cinza claro - + Grey Cinza - + Dark Grey Cinza escuro - + Light Skin Pele clara - + Light Skin - shade Pele clara - sombra - + Skin Pele - + Skin - shade Pele - sombra - + Dark Skin Pele escura - + Dark Skin - shade Pele escura - sombra @@ -1735,153 +1925,153 @@ Gostaria de salvar agora? PencilApplication - + Pencil2D is an animation/drawing software for Mac OS X, Windows, and Linux. It lets you create traditional hand-drawn animation (cartoon) using both bitmap and vector graphics. Pencil2D é um software de animação/desenho para Mac OS X, Windows e Linux. Permite criar animações tradicionais feitas a mão (desenhos animados) utilizando bitmaps e gráficos vetoriais. - + Path to the input pencil file. Caminho para o ficheiro de Pencil2D - - + + Render the file to <output_path> Renderizar o ficheiro no <caminho_saída> - - + + output_path caminho_saída - + Name of the camera layer to use Nome da camada de câmera a ser usada - + layer_name nome_da_camada - + Width of the output frames Largura dos quadros de saída - - + + integer Inteiro - + Height of the output frames Altura dos quadros de saída - + The first frame you want to include in the exported movie O primeiro quadro a incluir no vídeo exportado - - + + frame quadro - + The last frame you want to include in the exported movie. Can also be last or last-sound to automatically use the last frame containing animation or sound, respectively O último quadro a ser incluído no vídeo exportado. Pode também ser ajustado para 'último' ou 'último-som' para escolher, de forma automática, o último quadro contendo animação ou som, respectivamente. - + Render transparency when possible Renderizar transparência quando possível - + Warning: width value %1 is not an integer, ignoring. Aviso: valor da largura %1 não é um inteiro, ignorando. - + Warning: height value %1 is not an integer, ignoring. Aviso: valor da altura %1 não é um inteiro, ignorando. - + Warning: start value %1 is not an integer, ignoring. Aviso: valor de início %1 não é um inteiro, ignorando. - + Warning: start value must be at least 1, ignoring. Aviso: valor de início deve ser no mínimo 1, ignorando. - + Warning: end value %1 is not an integer, last or last-sound, ignoring. Aviso: valor de final %1 não é um número inteiro, 'último' ou 'último-som', ignorando. - + Warning: end value %1 is smaller than start value %2, ignoring. Aviso: valor de final %1 é menor que o valor de início %2, ignorando. - + Error: No input file specified. Erro: Nenhum arquivo especificado. - + Error: the input file at '%1' does not exist Command line error Erro: O arquivo selecionado em '%1' não existe - + Error: the input path '%1' is not a file Command line error Erro: O caminho selecionado em '%1' não é um arquivo - + Warning: the specified camera layer %1 was not found, ignoring. Aviso: a camada de câmera %1 não foi encontrada, ignorando. - + Warning: Output format is not specified or unsupported. Using PNG. Command line warning Aviso: O formato de saída não foi especificado ou não é suportado. Utilizando PNG. - + Warning: Transparency is not currently supported in movie files Command line warning Aviso: Transparência não é suportada atualmente em arquivos de vídeo - + Exporting movie... Command line task progress Exportando vídeo... - - + + Done. Command line task done Concluído. - + Exporting image sequence... Command line task progress Exportando sequência de imagens... @@ -1923,12 +2113,12 @@ Gostaria de salvar agora? QApplication - + Checking environment... Checando ambiente... - + Done Concluído @@ -1936,42 +2126,47 @@ Gostaria de salvar agora? QObject - + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) - - Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) - Imagens (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp) + Imagens (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp) - + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp); + Imagens (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp); + + + Everything ok. Tudo certo. - + Ooops, Something went wrong. Opa! Alguma coisa deu errado. - + File doesn't exist. O arquivo não existe. - + Cannot open file. Impossível abrir o arquivo. - + The file is not a valid xml document. O arquivo não é um documento XML válido. - + The file is not valid pencil document. O arquivo não é um documento Pencil válido. @@ -3320,6 +3515,16 @@ Gostaria de salvar agora? Black Preto + + + Could not open file + Não foi possível abrir o arquivo + + + + There was an error processing your file. This usually means that your project has been at least partially corrupted. You can try again with a newer version of Pencil2D, or you can try to use a backup file if you have one. If you contact us through one of our offical channels we may be able to help you. For reporting issues, the best places to reach us are: + Houve um erro ao processar o seu arquivo. Isto normalmente significa que o seu projeto foi ao menos parcialmente corrompido. Você pode tentar novamente com uma nova versão do Pencil2D ou tentar usar um arquivo de backup, se tiver algum. Se você entrar em contato conosco através de um dos nossos canais oficiais, poderemos lhe ajudar. Para reportar problemas, os melhores lugares para nos encontrar são: + RecentFileMenu @@ -3337,60 +3542,60 @@ Gostaria de salvar agora? ScribbleArea - + Warning Aviso - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Você está desenhando em uma camada oculta! Por favor, selecione outra camada (ou torne a camada atual visível). - + Delete Selection Undo Step: clear the selection area. Apagar seleção - - + + Clear Image Undo step text Limpar Imagem - + There is a gap in your drawing (or maybe you have zoomed too much). Há um espaço no seu desenho (ou talvez você tenha aumentado o zoom demais). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). Desculpe! Isto nem sempre funciona. Por favor tente novamente (aumente um pouco o zoom, clique em outro lugar... )<br>Caso não funcione, aumente um pouco o zoom e tenha a certeza que os caminhos estão conectados pressionando F1 - + Out of bound. Fora do limite - + Could not find a closed path. Não encontro um caminho fechado. - + Could not find the root index. Não encontro o índice principal - + %1<br><br>Error: %2 %1<br><br>Erro: %2 - + Flood fill error Erro de preenchimento @@ -3487,12 +3692,12 @@ Gostaria de salvar agora? - + Start Início - + Stop Parar @@ -3576,18 +3781,18 @@ Gostaria de salvar agora? Alternância quadros-chaves - + Delete Layer Windows title of Delete current layer pop-up. Apagar Camada - + Please keep at least one camera layer in project Por favor, mantenha ao menos uma camada de câmera no projeto - + Are you sure you want to delete layer: Você tem certeza de que deseja apagar a camada: @@ -3595,12 +3800,12 @@ Gostaria de salvar agora? TimeLineCells - + Layer Properties Propriedades da camada - + Layer name: Nome da camada: @@ -3677,6 +3882,16 @@ Gostaria de salvar agora? <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> <html><head/><body><p>(Aplicável para as ferramentas Lápis, Borracha, Caneta, Polilinha, Balde e Pincel)</p></body></html> + + + Playback + + + + + Show onion skin while playing + + Frame size diff --git a/translations/pencil_ru.qm b/translations/pencil_ru.qm index 8eb7454d84b1cb7b24455eb34922d42b43aabbaf..adbd92938147282fcd32457b04e5e9e62852b5bb 100644 GIT binary patch delta 3661 zcmXArd0b8T8^=HQ-gC}9_ug~Q9VxQZ5EYU=L_=wzRI-#3Qbc1PYeZL3qf%zXXl%oX zF+WQ)lCqnA8B55n8OvD57-N~i;5CNd=l;%L@3VcM^DLj|`Fd7HABv0^;`oLpMRN7guoc3UA(UnE z`C15jLxF_75Do}{|1b!34)Xq-C!JfPvDX(6uJEVnks6o(4dFLBXlbso_agEnFk~e8 z0`ReG>^%f_;g3#0?;Q}k^T!{p);PZuV%RYn2-Vm}gc!+%K`s#E=ur9sh~pVizxEJk z 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 - + Version: %1 Version Number in About Dialog Версия: %1 - + Copy to clipboard Copy system info from About Dialog Скопировать в буфер @@ -55,30 +55,30 @@ Звуковой слой - + Exporting movie Экспорт фильма - + Finished. Open movie now? When movie export done. Завершено. Открыть фильм сейчас? - - - - + + + + Layer Properties Свойства слоя - - - - + + + + Layer name: Имя слоя: @@ -88,58 +88,63 @@ Звуковой клип уже существует на этом кадре! Выберите другой кадр или слой. - + + Finished. Open file location? + + + + Exporting image sequence... Экспорт последовательности изображений... - + Abort Отменить - + Warning Предупреждение - + Unable to export image. Не удалось экспортировать изображение. - + Bitmap Layer Слой битовой карты - + Vector Layer Векторный слой - + Camera Layer Слой камеры - + Sound Layer Звуковой слой - + Delete Layer Windows title of Delete current layer pop-up. Удалить слой - + Are you sure you want to delete layer: Вы уверены, что хотите удалить слой: - + Please keep at least one camera layer in project text when failed to delete camera layer Пожалуйста, сохраните хотя бы один слой камеры в проекте. @@ -148,57 +153,57 @@ BaseTool - + Pencil Карандаш - + Eraser Ластик - + Select Выделение - + Move Перемещение - + Hand Рука - + Smudge Коррекция - + Pen Перо - + Polyline Ломаная - + Bucket Заливка - + Eyedropper Пипетка - + Brush Кисть @@ -224,69 +229,55 @@ ColorBox - - Color Wheel - Color Wheel's window title - Цветовой круг + + Color Box + Color Box window title + ColorInspector - + HSV HSV - + RGB RGB - - - Red - Красный - - - - - Green - Зелёный - - - - - Blue - Синий + + R + - - - - Alpha - Альфа-канал + + A + - - Hue - Тон + + G + - - Saturation - Насыщенность + + B + - - Value - Яркость + + Color Inspector + Window title of color inspector + ColorPalette - + Color Palette Window title of color palette. Палитра @@ -302,57 +293,57 @@ Удалить цвет - - ... - ... + + Native color dialog window + - + List Mode Режим списка - + Show palette as a list Показать палитру в виде списка - + Grid Mode Режим сетки - + Show palette as icons Показать палитру в виде значков - + Small swatch Маленький образец - + Sets swatch size to: 16x16px Устанавливает размер образца: 16x16px - + Medium Swatch Средний образец - + Sets swatch size to: 26x26px Устанавливает размер образца: 26x26px - + Large Swatch Большой образец - + Sets swatch size to: 36x36px Устанавливает размер образца: 36x36px @@ -360,11 +351,60 @@ ColorPaletteWidget - - + + Add + + + + + Replace + + + + + Remove + + + + + Colour name Параметры образца + + + The color(s) you are about to delete are currently being used by one or multiple strokes. + + + + + Cancel + + + + + Delete + + + + + Palette Restriction + + + + + The palette requires at least one swatch to remain functional + + + + + ColorWheel + + + Color Wheel + Color Wheel's window title + + DisplayOption @@ -446,19 +486,19 @@ Editor - - + + Paste Вставить - + Remove frame Удалить кадр - - + + Import Image Импорт изображения @@ -484,12 +524,12 @@ ExportImageDialog - + Export image sequence Экспорт последовательности изображений - + Export image Экспорт @@ -531,11 +571,51 @@ Transparency Прозрачность + + + Range + + + + + The last frame you want to include in the exported movie + + + + + End Frame + + + + + The first frame you want to include in the exported movie + + + + + Start Frame + + + + + <html><head/><body><p>End frame is set to last paintable keyframe (Useful when you only want to export to the last animated frame)</p></body></html> + + + + + To the end of sound clips + + ExportMovieDialog - + + Export Animated GIF + + + + Export Movie Экспорт фильма @@ -627,67 +707,83 @@ + Import Animated GIF + + + + Import movie Импорт фильма - + Import sound Импорт звука - + Import palette Импорт палитры - + Save animation Сохранить анимацию - + Export image Экспорт изображения - + Export image sequence Экспорт последовательности изображений - + + Export Animated GIF + + + + Export movie Экспорт фильма - + Export sound Экспорт звука - + Export palette Экспорт палитры - + + + Animated GIF (*.gif) + + + + Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) Звуки (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) - - - Palette (*.xml) - Палитра (*.xml) + + + Pencil2D Palette (*.xml);; Gimp Palette (*.gpl) + - - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) + + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng) - + MyAnimation.pclx МояАнимация.pclx @@ -695,52 +791,72 @@ FileManager - - - + + + Could not open file + + + + + The file does not exist, so we are unable to open it. Please check to make sure the path is correct and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + Invalid Save Path Недопустимый путь сохранения - + The path ("%1") points to a directory. Путь ("%1") указывает на каталог. - + The directory ("%1") does not exist. Папка ("%1") не существует. - + The path ("%1") is not writable. Путь ("%1") не доступен для записи. - - + + Cannot Create Data Directory Не удается создать каталог данных - + Failed to create directory "%1". Please make sure you have sufficient permissions. Не удалось создать каталог "%1". Убедитесь, что у вас есть достаточные права. - + "%1" is a file. Please delete the file and try again. "%1" - это файл. Удалите файл и повторите попытку. - - + + Miniz Error + + + + Internal Error Внутренняя ошибка - - + + An internal error occurred. Your file may not be saved successfully. Возникла внутренняя ошибка. Возможно, файл не сохранен. @@ -818,87 +934,97 @@ Сетка - + Czech Чешский - + Danish Датский - + English Английский - + German Немецкий - + + Estonian + + + + Spanish Испанский - + French Французский - + Hebrew - + Hungarian Венгерский - + Indonesian - + Italian Итальянский - + Japanese Японский - + + Polish + + + + Portuguese - Portugal - + Portuguese - Brazil Португальский - Бразилия - + Russian Русский - + Slovenian - + Vietnamese - + Chinese - Taiwan Китайский - Тайвань @@ -943,12 +1069,12 @@ Повышенная точность позиционирования для графического планшета - + Restart Required Необходим перезапуск - + The language change will take effect after a restart of Pencil2D Изменение языка вступит в силу после перезапуска Pencil2D @@ -974,7 +1100,12 @@ ImportImageSeqDialog - + + Import Animated GIF + + + + Import image sequence Импорт последовательности изображений @@ -998,7 +1129,7 @@ LayerBitmap - + Bitmap Layer Растровый слой @@ -1014,7 +1145,7 @@ LayerSound - + Sound Layer Звуковой слой @@ -1045,473 +1176,484 @@ Импорт - + Export Экспорт - + Edit Правка - + Selection Выделение - + View Вид - + Onion Skin Калька - + Animation Анимация - - + + Tools Инструменты - + Layer Слой - - + + Help Помощь - + Windows Окна - + New Создать - + Open Открыть - + Save Сохранить - + Save As .. Сохранить как... - + Exit Выход - - + + Image Sequence... Последовательность изображений... - - + + Image... Изображение... - - + + Movie... Ролик... - - + + Palette... Палитра... - + Sound... Звук... - + Undo Отменить - + Redo Повторить - + Cut Вырезать - + Copy Копировать - + Paste Вставить - + Crop Обрезать - + Crop To Selection Кадрировать - + Select All Выделить всё - + Deselect All Снять выделение - - + + Clear Frame Очистить кадр - + Preferences Настройки - + Reset Windows Окна по умолчанию - + Zoom In Приблизить - + Zoom Out Отдалить - + Rotate Clockwise Вращать по часовой стрелке - + Rotate AntiClosewise Вращать против часовой стрелки - + Reset Zoom/Rotate Сбросить масштабирование/поворот - + Horizontal Flip Отразить по горизонтали - + Vertical Flip Отразить по вертикали - + Preview Предпросмотр - + Grid Сетка - + Previous Предыдущий кадр - + Show previous onion skin - + Next Следующий кадр - + Show next onion skin - - + + Play Воспроизведение - + Loop Повтор - + Next Frame Следующий кадр - + Previous Frame Предыдущий кадр - + Extend Frame Продлить кадр - + Add Frame Добавить кадр - + Duplicate Frame Дублировать кадр - + Remove Frame Удалить кадр - + Move Перемещение - + Select Выделение - + Brush Кисть - + Polyline Ломаная - + Smudge Коррекция - + Pen Перо - + Hand Рука - + Pencil Карандаш - + Bucket Заливка - + Eyedropper Пипетка - + Eraser Ластик - + New Bitmap Layer Новый растровый слой - + New Vector Layer Новый векторный слой - + New Sound Layer Новый звуковой слой - + New Camera Layer Новый слой камеры - + Delete Current Layer Удалить текущий слой - + About О программе - - + + Reset to default Вернуть настройки по умолчанию - + MultiLayer Onion Skin - + Range Диапазон - + Pencil2D Website Сайт Pencil2D - + Report a Bug Сообщить о проблеме - + Quick Reference Guide - + F1 - - + + + Animated GIF... + + + + + Next KeyFrame Следующий ключевой кадр - - + + Previous KeyFrame Предыдущий ключевой кадр - + Timeline Временная шкала - + Options Параметры - + Color Wheel Цветовой круг - + Color Palette Палитра - + Display Options Настройки отображения - + Flip X Отразить по оси X - + Flip Y Отразить по оси Y - + Move Frame Forward Переместить кадр вперед - + Move Frame Backward Переместить кадр назад - + color palette:<br>use <b>(C)</b><br>toggle at cursor - + + Color inspector + + + + Lock Windows Закрепить окна - + Open Recent Последние документы - + You have successfully cleared the list @@ -1520,216 +1662,263 @@ Вы успешно очистили список - - - - - + + + + + Could not open file + + + + + The file you have selected is a directory, so we are unable to open it. If you are are trying to open a project that uses the old structure, please open the file ending with .pcl, not the data folder. + + + + + The file you have selected does not exist, so we are unable to open it. Please check to make sure that you've entered the correct path and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + + + Warning Предупреждение - - - Pencil cannot read this file. If you want to import images, use the command import. - Pencil не удалось открыть данный файл. ->br<Подсказка: для изображений воспользуйтесь командой Файл -> Импорт + + This program does not currently have permission to write to the file you have selected. Please make sure you have write permission for this file before attempting to save it. Alternatively, you can use the Save As... menu option to save to a writable location. + - + Opening document... Открытие документа... - - - + + + + Abort Отмена - + + An unknown error occurred while trying to load the file and we are not able to load your file. + + + + Saving document... Сохранение документа... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: - + This animation has been modified. Do you want to save your changes? Эта анимация была изменена. Вы хотите сохранить свои изменения? - + The animation is not saved yet. Do you want to save now? Анимация еще не сохранена. Вы хотите сохранить ее сейчас? - + Never ask again AutoSave reminder button Больше не спрашивать - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. - + Importing image sequence... - + + was unable to import - - + + Importing Animated GIF... + + + + + Undo Menu item text - + Redo Menu item text - + Stop Стоп + + MoveTool + + + Layer switch + Windows title of layer switch pop-up. + + + + + You are about to switch layer, do you want to apply the transformation? + + + Object - + Black Чёрный - + Red Красный - + Dark Red Тёмно-красный - + Orange Оранжевый - + Dark Orange Тёмно-оранжевый - + Yellow Жёлтый - + Dark Yellow Тёмно-жёлтый - + Green Зелёный - + Dark Green Тёмно-зелёный - + Cyan Сине-зелёный - + Dark Cyan Тёмный сине-зелёный - + Blue Синий - + Dark Blue Тёмно-синий - + White Белый - + Very Light Grey Серый 12% - + Light Grey Серый 25% - + Grey Серый 37% - + Dark Grey Серый 50% - + Light Skin Цвет кожи, светлый - + Light Skin - shade Цвет кожи, светлый с тенью - + Skin Цвет кожи - + Skin - shade Цвет кожи, с тенью - + Dark Skin Цвет кожи, тёмный - + Dark Skin - shade Цвет кожи, тёмный с тенью @@ -1737,153 +1926,153 @@ PencilApplication - + Pencil2D is an animation/drawing software for Mac OS X, Windows, and Linux. It lets you create traditional hand-drawn animation (cartoon) using both bitmap and vector graphics. - + Path to the input pencil file. - - + + Render the file to <output_path> - - + + output_path - + Name of the camera layer to use Название используемого слоя камеры - + layer_name - + Width of the output frames Ширина выходных кадров - - + + integer - + Height of the output frames Высота выходных кадров - + The first frame you want to include in the exported movie Первый кадр, который вы хотите включить в экспортированный фильм - - + + frame кадр - + The last frame you want to include in the exported movie. Can also be last or last-sound to automatically use the last frame containing animation or sound, respectively - + Render transparency when possible - + Warning: width value %1 is not an integer, ignoring. - + Warning: height value %1 is not an integer, ignoring. - + Warning: start value %1 is not an integer, ignoring. - + Warning: start value must be at least 1, ignoring. - + Warning: end value %1 is not an integer, last or last-sound, ignoring. - + Warning: end value %1 is smaller than start value %2, ignoring. - + Error: No input file specified. Ошибка: не указан входной файл. - + Error: the input file at '%1' does not exist Command line error - + Error: the input path '%1' is not a file Command line error - + Warning: the specified camera layer %1 was not found, ignoring. - + Warning: Output format is not specified or unsupported. Using PNG. Command line warning - + Warning: Transparency is not currently supported in movie files Command line warning - + Exporting movie... Command line task progress - - + + Done. Command line task done - + Exporting image sequence... Command line task progress @@ -1925,12 +2114,12 @@ QApplication - + Checking environment... Проверка среды... - + Done Готово @@ -1938,42 +2127,47 @@ QObject - + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) - - Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp) + + + + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp); - + Everything ok. Все в порядке. - + Ooops, Something went wrong. Ой, что-то пошло не так. - + File doesn't exist. Файл не существует. - + Cannot open file. Невозможно открыть файл. - + The file is not a valid xml document. Файл не является допустимым XML-документом. - + The file is not valid pencil document. Файл не является допустимым документом Pencil. @@ -3322,6 +3516,16 @@ Black Чёрный + + + Could not open file + + + + + There was an error processing your file. This usually means that your project has been at least partially corrupted. You can try again with a newer version of Pencil2D, or you can try to use a backup file if you have one. If you contact us through one of our offical channels we may be able to help you. For reporting issues, the best places to reach us are: + + RecentFileMenu @@ -3339,60 +3543,60 @@ ScribbleArea - + Warning Предупреждение - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Вы рисуете на скрытом слое! Пожалуйста, выберите другой слой или сделайте текущий видимым. - + Delete Selection Undo Step: clear the selection area. Удалить выделение - - + + Clear Image Undo step text Очистить изображение - + There is a gap in your drawing (or maybe you have zoomed too much). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). - + Out of bound. Вне границы. - + Could not find a closed path. - + Could not find the root index. - + %1<br><br>Error: %2 %1<br><br>Ошибка: %2 - + Flood fill error Ошибка заливки @@ -3489,12 +3693,12 @@ - + Start В начало - + Stop Стоп @@ -3578,18 +3782,18 @@ - + Delete Layer Windows title of Delete current layer pop-up. Удалить слой - + Please keep at least one camera layer in project Пожалуйста, оставьте хотя бы один слой камеры в проекте - + Are you sure you want to delete layer: Вы уверены, что хотите удалить слой: @@ -3597,12 +3801,12 @@ TimeLineCells - + Layer Properties Свойства слоя - + Layer name: Имя слоя: @@ -3679,6 +3883,16 @@ <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + + Playback + + + + + Show onion skin while playing + + Frame size diff --git a/translations/pencil_sl.qm b/translations/pencil_sl.qm index 627c9001137a06e05e46efce135049ea21a40068..bf357f7324cf4bd9cb79e61e5aff92ca21c6dc39 100644 GIT binary patch delta 5902 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 delta 6780 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 X;KRc7;emg@H_e*RC?`BPD(8OyaGm*5 diff --git a/translations/pencil_sl.ts b/translations/pencil_sl.ts index 521a00b26..bc6f0b2a0 100644 --- a/translations/pencil_sl.ts +++ b/translations/pencil_sl.ts @@ -13,13 +13,13 @@ Uradna stran:<a href="https://www.pencil2d.org">pencil2d.org</a><br>Razvijalci:<b>Pascal Naidon, Patrick Corrieri, Matt Chang</b><br>Zahvaljujoč QT Ogrodju<a href="https://www.qt.io/download">https://www.qt.io/</a><br>miniz:<a href="https://github.com/richgel999/miniz">https://github.com/richgel999/miniz</a><br>Distribuirano z licenco:<a href="http://www.gnu.org/licenses/gpl-2.0.html">GNU General Public License, version 2</a> - + Version: %1 Version Number in About Dialog Verzija: 1% - + Copy to clipboard Copy system info from About Dialog Kopiraj na odložišče @@ -55,30 +55,30 @@ Zvočni sloj - + Exporting movie Izvažanje posnetka - + Finished. Open movie now? When movie export done. Dokončano. Predvajaj posnetek? - - - - + + + + Layer Properties Lastnosti sloja - - - - + + + + Layer name: Ime sloja: @@ -88,58 +88,63 @@ V temu razdelku že obstaja zvočni posnetek! Prosim izberite drug razdelek ali sloj. - + + Finished. Open file location? + + + + Exporting image sequence... Izvažanje animacije sličic... - + Abort Prekini - + Warning Opozorilo - + Unable to export image. Slike ni mogoče izvoziti. - + Bitmap Layer Bitni sloj - + Vector Layer Vektorski sloj - + Camera Layer Sloj kamere - + Sound Layer Zvočni sloj - + Delete Layer Windows title of Delete current layer pop-up. Izbriši sloj - + Are you sure you want to delete layer: Res želite izbrisati sloj: - + Please keep at least one camera layer in project text when failed to delete camera layer Prosim ohranite vsaj en sloj s kamero v projektu @@ -148,57 +153,57 @@ BaseTool - + Pencil Svinčnik - + Eraser Radirka - + Select Izbor - + Move Premakni - + Hand Roka - + Smudge Zamaži - + Pen Penkalo - + Polyline Večsegmentna črta - + Bucket Vedro - + Eyedropper Kapalka - + Brush Čopič @@ -224,69 +229,55 @@ ColorBox - - Color Wheel - Color Wheel's window title - Barvno kolo + + Color Box + Color Box window title + ColorInspector - + HSV HSV - + RGB RGB - - - Red - Rdeča - - - - - Green - Zelena - - - - - Blue - Modra + + R + - - - - Alpha - Prosojnost + + A + - - Hue - Odtenek + + G + - - Saturation - Zasičenost + + B + - - Value - Vrednost + + Color Inspector + Window title of color inspector + ColorPalette - + Color Palette Window title of color palette. Paleta barv @@ -302,57 +293,57 @@ Odstrani barvo - - ... - ... + + Native color dialog window + - + List Mode Seznam - + Show palette as a list Pokaži paleto kot seznam - + Grid Mode Mreža - + Show palette as icons Prikaži paleto z ikonami - + Small swatch Majhen vzorec - + Sets swatch size to: 16x16px Spremeni velikost vzorca na 16x16px - + Medium Swatch Srednji vzorec - + Sets swatch size to: 26x26px Spremeni velikost vzorca na 26x26px - + Large Swatch Veliki vzorec - + Sets swatch size to: 36x36px Spremeni velikost vzorca na 36x36px @@ -360,11 +351,60 @@ ColorPaletteWidget - - + + Add + + + + + Replace + + + + + Remove + + + + + Colour name Ime barve + + + The color(s) you are about to delete are currently being used by one or multiple strokes. + + + + + Cancel + + + + + Delete + + + + + Palette Restriction + + + + + The palette requires at least one swatch to remain functional + + + + + ColorWheel + + + Color Wheel + Color Wheel's window title + + DisplayOption @@ -446,19 +486,19 @@ Editor - - + + Paste Prilepi - + Remove frame Odstrani razdelek - - + + Import Image Uvozi sliko @@ -484,12 +524,12 @@ ExportImageDialog - + Export image sequence Izvozi animacijo sličic... - + Export image Izvozi sliko @@ -531,11 +571,51 @@ Transparency Prosojnost + + + Range + + + + + The last frame you want to include in the exported movie + + + + + End Frame + + + + + The first frame you want to include in the exported movie + + + + + Start Frame + + + + + <html><head/><body><p>End frame is set to last paintable keyframe (Useful when you only want to export to the last animated frame)</p></body></html> + + + + + To the end of sound clips + + ExportMovieDialog - + + Export Animated GIF + + + + Export Movie Izvozi posnetek @@ -627,67 +707,83 @@ + Import Animated GIF + + + + Import movie Uvozi posnetek - + Import sound Uvozi zvok - + Import palette Uvozi paleto - + Save animation Shrani animacijo - + Export image Izvozi sliko - + Export image sequence Izvozi zaporedje sličic - + + Export Animated GIF + + + + Export movie Izvozi posnetek - + Export sound Izvozi zvok - + Export palette Izvozi paleto - + + + Animated GIF (*.gif) + + + + Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) Zvoki (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) - - - Palette (*.xml) - Paleta (*.xml) + + + Pencil2D Palette (*.xml);; Gimp Palette (*.gpl) + - - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) - MP4 (*.mp4);;AVI (*.avi);; WebM (*.webm);; GIF (*.gif);;APNG (*.apng) + + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng) + - + MyAnimation.pclx MojaAnimacija.pclx @@ -695,52 +791,72 @@ FileManager - - - + + + Could not open file + + + + + The file does not exist, so we are unable to open it. Please check to make sure the path is correct and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + Invalid Save Path Napačna pot shranjevanja - + The path ("%1") points to a directory. Pot ("%1") kaže na mapo. - + The directory ("%1") does not exist. Mapa ("%1") ne obstaja. - + The path ("%1") is not writable. V mapo ("%1") se ne da pisati. - - + + Cannot Create Data Directory Ne morem ustvariti podatkovne mape - + Failed to create directory "%1". Please make sure you have sufficient permissions. Ni bilo možno ustvariti mape "%1". Preverite ali imate zadostne pravice. - + "%1" is a file. Please delete the file and try again. "%1" je datoteka. Prosim izbriošite datoteko in poizkusite znova. - - + + Miniz Error + + + + Internal Error Notranja napaka - - + + An internal error occurred. Your file may not be saved successfully. Prišlo je do notranje napake. Vaša datoteka se lahko poškoduje med zapisovanjem. @@ -818,87 +934,97 @@ Mreža - + Czech Češko - + Danish Dansko - + English Angleško - + German Nemško - + + Estonian + + + + Spanish Špansko - + French Francosko - + Hebrew Hebrejščina - + Hungarian Madžarsko - + Indonesian Indonezijsko - + Italian Italijansko - + Japanese Japonsko - + + Polish + + + + Portuguese - Portugal - + Portuguese - Brazil Portugalsko-Brazilsko - + Russian Rusko - + Slovenian - + Vietnamese - + Chinese - Taiwan Kitajsko-Tajvansko @@ -943,12 +1069,12 @@ Pozicija za visoko ločljivostno tablico - + Restart Required Potreben je ponovni zagon - + The language change will take effect after a restart of Pencil2D Sprememba jezika bo aktivna po ponovnem zagonu Svinčnika2D @@ -974,7 +1100,12 @@ ImportImageSeqDialog - + + Import Animated GIF + + + + Import image sequence Uvozi zaporedje sličic @@ -998,7 +1129,7 @@ LayerBitmap - + Bitmap Layer Bitni sloj @@ -1014,7 +1145,7 @@ LayerSound - + Sound Layer Zvočni sloj @@ -1045,473 +1176,484 @@ Uvoz - + Export Izvoz - + Edit Urejanje - + Selection Izbor - + View Pogled - + Onion Skin Prosojnica - + Animation Animacija - - + + Tools Orodja - + Layer Sloj - - + + Help Pomoč - + Windows Okna - + New Nov - + Open Odpri - + Save Shrani - + Save As .. Shrani kot... - + Exit Izhod - - + + Image Sequence... Zaporedje sličic... - - + + Image... Slika... - - + + Movie... Posnetek... - - + + Palette... Paleta... - + Sound... Zvok... - + Undo Korak nazaj - + Redo Korak naprej - + Cut Izreži - + Copy Kopiraj - + Paste Prilepi - + Crop Obreži - + Crop To Selection Obreži do izbora - + Select All Izberi vse - + Deselect All Razveljavi izbor - - + + Clear Frame Počisti razdelek - + Preferences Nastavitve - + Reset Windows Ponastavi okna - + Zoom In Približaj - + Zoom Out Oddalji - + Rotate Clockwise Zavrti desno - + Rotate AntiClosewise Zavrti levo - + Reset Zoom/Rotate Ponastavi Povečavo/Vrtenje - + Horizontal Flip Prezrcali horizontalno - + Vertical Flip Prezrcali vertikalno - + Preview Predogled - + Grid Mreža - + Previous Prejšnji - + Show previous onion skin Pokaži prejšnjo prosojnico - + Next Naslednji - + Show next onion skin Pokaži naslednjo prosojnico - - + + Play Predvajaj - + Loop Ponavljanje - + Next Frame Naslednji razdelek - + Previous Frame Prejšnji razdelek - + Extend Frame Razširi razdelek - + Add Frame Dodaj razdelek - + Duplicate Frame Podvoji razdelek - + Remove Frame Odstrani razdelek - + Move Premakni - + Select Izbor - + Brush Čopič - + Polyline Večsegmentna črta - + Smudge Zamaži - + Pen Penkalo - + Hand Roka - + Pencil Svinčnik - + Bucket Vedro - + Eyedropper Kapalka - + Eraser Radirka - + New Bitmap Layer Novi bitni sloj - + New Vector Layer Novi vektorski sloj - + New Sound Layer Novi zvočni sloj - + New Camera Layer Novi sloj kamere - + Delete Current Layer Ibriši trenutni sloj - + About O programu - - + + Reset to default Ponastavi na osnovne nastavitve - + MultiLayer Onion Skin Večslojna prosojnica - + Range Razpon - + Pencil2D Website Internetna stran Svinčnik2D - + Report a Bug Sporoči napako - + Quick Reference Guide - + F1 - - + + + Animated GIF... + + + + + Next KeyFrame Naslednji ključni razdelek - - + + Previous KeyFrame Prejšnji ključni razdelek - + Timeline Časovnica - + Options Možnosti - + Color Wheel Barvno kolo - + Color Palette Paleta barv - + Display Options Možnosti prikaza - + Flip X Zrcali X - + Flip Y Zrcali Y - + Move Frame Forward Premakni razdelek naprej - + Move Frame Backward Premakni razdelek nazaj - + color palette:<br>use <b>(C)</b><br>toggle at cursor barvna paleta:<br>uporabi<b>(C)</b><br>izmenjaj pri kazalcu - + + Color inspector + + + + Lock Windows Zakleni okna - + Open Recent Odpri nedavne - + You have successfully cleared the list @@ -1520,215 +1662,263 @@ Uspešno ste izbpraznili seznam - - - - - + + + + + Could not open file + + + + + The file you have selected is a directory, so we are unable to open it. If you are are trying to open a project that uses the old structure, please open the file ending with .pcl, not the data folder. + + + + + The file you have selected does not exist, so we are unable to open it. Please check to make sure that you've entered the correct path and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + + + Warning Opozorilo - - - Pencil cannot read this file. If you want to import images, use the command import. - Svinčnik ne more prebrati te datoteke. Če želite uvoziti slike uporabite ukaz za uvoz. + + This program does not currently have permission to write to the file you have selected. Please make sure you have write permission for this file before attempting to save it. Alternatively, you can use the Save As... menu option to save to a writable location. + - + Opening document... Odpiranje dokumenta... - - - + + + + Abort Prekini - + + An unknown error occurred while trying to load the file and we are not able to load your file. + + + + Saving document... Shranjevanje dokumenta... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>Pojavila se je napaka in vaša datoteka morda ni pravilno shranjena. Če sumite, da napaka kaže na problem s Svinčnikom2D kreirajtenovo poročilo na:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Prosimo, da v svoje poročilo vključite naslednje podatke: - + This animation has been modified. Do you want to save your changes? Ta animacija je bila spremenjena. Želite shraniti spremembe? - + The animation is not saved yet. Do you want to save now? Animacija še ni shranjena. Želite shraniti sedaj? - + Never ask again AutoSave reminder button Ne sprašuj več - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Ni mogoče uvoziti slike.<br><b>Namig:</b>Uporabite bitni sloj za uvoz bitnih slik. - + Importing image sequence... Uvažanje zaporedja sličic... - + + was unable to import - - + + Importing Animated GIF... + + + + + Undo Menu item text Korak nazaj - + Redo Menu item text Korak naprej - + Stop Stop + + MoveTool + + + Layer switch + Windows title of layer switch pop-up. + + + + + You are about to switch layer, do you want to apply the transformation? + + + Object - + Black Črna - + Red Rdeča - + Dark Red Temno rdeča - + Orange Oranžna - + Dark Orange Temno oranžna - + Yellow Rumena - + Dark Yellow Temno rumena - + Green Zelena - + Dark Green Temno zelena - + Cyan Sinja - + Dark Cyan Temno sinja - + Blue Modra - + Dark Blue Temno modra - + White Bela - + Very Light Grey Zelo svetlo siva - + Light Grey Svetlo siva - + Grey Siva - + Dark Grey Temno siva - + Light Skin Svetla koža - + Light Skin - shade Svetla koža-senca - + Skin Koža - + Skin - shade Koža-senca - + Dark Skin Temna koža - + Dark Skin - shade Temna koža-senca @@ -1736,153 +1926,153 @@ Uspešno ste izbpraznili seznam PencilApplication - + Pencil2D is an animation/drawing software for Mac OS X, Windows, and Linux. It lets you create traditional hand-drawn animation (cartoon) using both bitmap and vector graphics. Svinčnik2D je program za animacijo/risanje v Mac OS X, Windows in Linux-u. Z njim lahko ustvarite tradicionalno ročno risano animacijo (risanko) s pomočjo bitne in vektorske grafike  - + Path to the input pencil file. Pot do vnosne datoteke svinčnika. - - + + Render the file to <output_path> Izriši datoteko v<output_path> - - + + output_path izhodna_pot - + Name of the camera layer to use Ime sloja kamere za uporabo - + layer_name sloj_ime - + Width of the output frames Širina izhodnih razdelkov - - + + integer celo število - + Height of the output frames Višina izhodnih razdelkov - + The first frame you want to include in the exported movie Prvi razdelek, ki ga želite vključiti v izvoz posnetka - - + + frame razdelek - + The last frame you want to include in the exported movie. Can also be last or last-sound to automatically use the last frame containing animation or sound, respectively Zadnji razdelek, ki ga želite vključiti v izvoz posnetka. Lahko je tudi zadnji zvok ki avtomatično zaključi uporabo razdelkov ob lastnem zaključku. - + Render transparency when possible Izriši prosojnost kadar je to mogoče - + Warning: width value %1 is not an integer, ignoring. Opozorilo: širina %1 ni celo število, preskočeno. - + Warning: height value %1 is not an integer, ignoring. Opozorilo: višina %1 ni celo število, preskočeno. - + Warning: start value %1 is not an integer, ignoring. Opozorilo: začetna vrednost %1 ni celo število, preskočeno. - + Warning: start value must be at least 1, ignoring. Opozorilo: začetna vrednost mora biti vsaj 1, preskočeno. - + Warning: end value %1 is not an integer, last or last-sound, ignoring. Opozorilo: končna vrednost %1 ni celo število, zadnji razdelek ali zvok, preskočeno. - + Warning: end value %1 is smaller than start value %2, ignoring. Opozorilo: končna vrednost %1 je manjša kot začetna vrednost %2, preskočeno. - + Error: No input file specified. Napaka: Vhodna datoteka ni določena. - + Error: the input file at '%1' does not exist Command line error Napaka: vhodna datoteka na '%1' ne obstaja - + Error: the input path '%1' is not a file Command line error Napaka: vhodna pot '%1' ni datoteka - + Warning: the specified camera layer %1 was not found, ignoring. Opozorilo: izbrani sloj kamere %1 ni bil najden, preskočeno. - + Warning: Output format is not specified or unsupported. Using PNG. Command line warning Opozorilo: Izhodna oblika ni določena ali je nepodprta. Uporabljam PNG. - + Warning: Transparency is not currently supported in movie files Command line warning Opozorilo: Prosojnost v posnetkih trenutno ni podprta - + Exporting movie... Command line task progress Izvažanje posnetka... - - + + Done. Command line task done Narejeno. - + Exporting image sequence... Command line task progress Izvažanje zaporedja sličic... @@ -1924,12 +2114,12 @@ Uspešno ste izbpraznili seznam QApplication - + Checking environment... Preverjanje okolja... - + Done Narejeno. @@ -1937,42 +2127,47 @@ Uspešno ste izbpraznili seznam QObject - + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) - - Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp) + + + + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp); - + Everything ok. Vse v redu. - + Ooops, Something went wrong. Jejhata na, nekaj se je zalomilo. - + File doesn't exist. Datoteka ne obstaja. - + Cannot open file. Ne morem odpreti datoteke - + The file is not a valid xml document. Datoteka ni veljaven xml dokument. - + The file is not valid pencil document. Datoteka ni veljaven svinčnikov dokument. @@ -3321,6 +3516,16 @@ Uspešno ste izbpraznili seznam Black Črna + + + Could not open file + + + + + There was an error processing your file. This usually means that your project has been at least partially corrupted. You can try again with a newer version of Pencil2D, or you can try to use a backup file if you have one. If you contact us through one of our offical channels we may be able to help you. For reporting issues, the best places to reach us are: + + RecentFileMenu @@ -3338,60 +3543,60 @@ Uspešno ste izbpraznili seznam ScribbleArea - + Warning Opozorilo - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Rišete po skritem sloju! Izberite drug sloj (ali spremenite trenutni sloj v vidnega). - + Delete Selection Undo Step: clear the selection area. Izbriši označeno - - + + Clear Image Undo step text Počisti sliko - + There is a gap in your drawing (or maybe you have zoomed too much). V risbi je razmik (ali pa je preveč približana). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). Žal, to vedno ne deluje. Poizkusite znova (malce približajte ali oddaljite, kliknite na drugo lokacijo,...)<br>Če ne deluje malce približajte ali oddaljite in preverite če so poti spojene s pritiskom na F1.). - + Out of bound. Izven mej. - + Could not find a closed path. Ne najdem zaprte poti. - + Could not find the root index. Ne najdem korenskega kazala. - + %1<br><br>Error: %2 %1<br><br>Napaka: %2 - + Flood fill error Napaka pri polnenju. @@ -3488,12 +3693,12 @@ Uspešno ste izbpraznili seznam - + Start Začetek - + Stop Stop @@ -3577,18 +3782,18 @@ Uspešno ste izbpraznili seznam Preklopi ujemanje ključnih razdelkov - + Delete Layer Windows title of Delete current layer pop-up. Izbriši sloj - + Please keep at least one camera layer in project Prosim ohranite vsaj en sloj s kamero v projektu - + Are you sure you want to delete layer: Res želite izbrisati sloj: @@ -3596,12 +3801,12 @@ Uspešno ste izbpraznili seznam TimeLineCells - + Layer Properties Lastnosti sloja - + Layer name: Ime sloja: @@ -3678,6 +3883,16 @@ Uspešno ste izbpraznili seznam <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + + Playback + + + + + Show onion skin while playing + + Frame size diff --git a/translations/pencil_vi.qm b/translations/pencil_vi.qm index d88ed78619420fb0e6c7456f02461393cdf74b88..ad9a3aac02efeb41412fc599586d41c9c4540443 100644 GIT binary patch delta 5173 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 Cg1zPd diff --git a/translations/pencil_vi.ts b/translations/pencil_vi.ts index d2a17b95a..54bcf1b5b 100644 --- a/translations/pencil_vi.ts +++ b/translations/pencil_vi.ts @@ -13,13 +13,13 @@ - + Version: %1 Version Number in About Dialog - + Copy to clipboard Copy system info from About Dialog @@ -55,30 +55,30 @@ - + Exporting movie - + Finished. Open movie now? When movie export done. - - - - + + + + Layer Properties Thuộc tính của Layer - - - - + + + + Layer name: Tên Layer @@ -88,58 +88,63 @@ Clip âm thanh này Đã có sẵn trên frame! Hãy chọn một frame khác hay một Layer khác - + + Finished. Open file location? + + + + Exporting image sequence... Đang xuất hình ảnh trong clip... - + Abort Từ chối yêu cầu - + Warning Cảnh báo - + Unable to export image. Không thể xuất Được hình ảnh - + Bitmap Layer Bitmap Layer - + Vector Layer Vector Layer - + Camera Layer Layer của máy quay - + Sound Layer Layer âm thanh - + Delete Layer Windows title of Delete current layer pop-up. - + Are you sure you want to delete layer: - + Please keep at least one camera layer in project text when failed to delete camera layer @@ -148,57 +153,57 @@ BaseTool - + Pencil Bút chì - + Eraser Tẩy xóa - + Select Công cụ chọn - + Move Di chuyển - + Hand Bàn tay - + Smudge Làm mờ - + Pen Bút mực - + Polyline Polyline - + Bucket Tô màu - + Eyedropper Chọn màu - + Brush Cọ vẽ @@ -224,69 +229,55 @@ ColorBox - - Color Wheel - Color Wheel's window title - Bánh xe chọn màu + + Color Box + Color Box window title + ColorInspector - + HSV Hệ màu HSV - + RGB Hệ màu RGB - - - Red - Đỏ - - - - - Green - Xanh lá cây - - - - - Blue - Xanh dương + + R + - - - - Alpha - Màu Alpha + + A + - - Hue - Màu Hue + + G + - - Saturation - Độ phân tán màu + + B + - - Value - Giá trị + + Color Inspector + Window title of color inspector + ColorPalette - + Color Palette Window title of color palette. @@ -302,57 +293,57 @@ Xóa màu - - ... - Đang xử lý... + + Native color dialog window + - + List Mode - + Show palette as a list - + Grid Mode - + Show palette as icons - + Small swatch - + Sets swatch size to: 16x16px - + Medium Swatch - + Sets swatch size to: 26x26px - + Large Swatch - + Sets swatch size to: 36x36px @@ -360,11 +351,60 @@ ColorPaletteWidget - - + + Add + + + + + Replace + + + + + Remove + + + + + Colour name Tên màu + + + The color(s) you are about to delete are currently being used by one or multiple strokes. + + + + + Cancel + + + + + Delete + + + + + Palette Restriction + + + + + The palette requires at least one swatch to remain functional + + + + + ColorWheel + + + Color Wheel + Color Wheel's window title + + DisplayOption @@ -446,19 +486,19 @@ Editor - - + + Paste Dán - + Remove frame - - + + Import Image Nhập vào hình ảnh @@ -484,12 +524,12 @@ ExportImageDialog - + Export image sequence Xuất hàng Đợi hình ảnh - + Export image Xuất hình ảnh @@ -531,11 +571,51 @@ Transparency Trong suốt + + + Range + + + + + The last frame you want to include in the exported movie + + + + + End Frame + + + + + The first frame you want to include in the exported movie + + + + + Start Frame + + + + + <html><head/><body><p>End frame is set to last paintable keyframe (Useful when you only want to export to the last animated frame)</p></body></html> + + + + + To the end of sound clips + + ExportMovieDialog - + + Export Animated GIF + + + + Export Movie Xuất Video @@ -627,67 +707,83 @@ + Import Animated GIF + + + + Import movie Nhập vào Video - + Import sound Nhập vào âm thanh - + Import palette Nhập vào bảng màu - + Save animation Lưu file hoạt hình - + Export image Xuất ra hình ảnh - + Export image sequence Xuất ra hàng chờ hình ảnh - + + Export Animated GIF + + + + Export movie Xuất ra video - + Export sound Xuất ra âm thanh - + Export palette Xuất ra bảng màu - + + + Animated GIF (*.gif) + + + + Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) Sounds - Âm thanh (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) - - - Palette (*.xml) - Palette - Bảng màu (*.xml) + + + Pencil2D Palette (*.xml);; Gimp Palette (*.gpl) + - - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) + + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng) - + MyAnimation.pclx HoatHinhCuaToi.pclx @@ -695,52 +791,72 @@ FileManager - - - + + + Could not open file + + + + + The file does not exist, so we are unable to open it. Please check to make sure the path is correct and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + Invalid Save Path Đường dẫn lưu tập tin không hợp lệ - + The path ("%1") points to a directory. - + The directory ("%1") does not exist. - + The path ("%1") is not writable. - - + + Cannot Create Data Directory Không thể tạo Được thư mục dữ liệu - + Failed to create directory "%1". Please make sure you have sufficient permissions. - + "%1" is a file. Please delete the file and try again. - - + + Miniz Error + + + + Internal Error Lỗi phát sinh nội tại! - - + + An internal error occurred. Your file may not be saved successfully. @@ -818,87 +934,97 @@ Lưới - + Czech Tiếng Cộng hòa Czech - + Danish Tiếng Đan mạch - + English Tiếng Anh - + German Tiếng Đức - + + Estonian + + + + Spanish Tiếng Tây Ban Nha - + French Tiếng Pháp - + Hebrew - + Hungarian Tiếng Hungary - + Indonesian - + Italian Tiếng Ý - + Japanese Tiếng Nhật - + + Polish + + + + Portuguese - Portugal - + Portuguese - Brazil Tiếng Bồ Đào Nha - Brazil - + Russian Tiếng Nga - + Slovenian - + Vietnamese - + Chinese - Taiwan Tiếng Đài Loan - Trung Quốc @@ -943,12 +1069,12 @@ Vị trí Độ phân giải cao dành cho máy tính bản - + Restart Required Yêu cầu khởi Động lại - + The language change will take effect after a restart of Pencil2D Thay Đổi ngôn ngữ sẽ Được thực hiện sau khi khỏi Đông lại phần mềm Pencil 2D @@ -974,7 +1100,12 @@ ImportImageSeqDialog - + + Import Animated GIF + + + + Import image sequence Nhập vào nhiều hình ảnh @@ -998,7 +1129,7 @@ LayerBitmap - + Bitmap Layer Bitmap Layer @@ -1014,7 +1145,7 @@ LayerSound - + Sound Layer Layer âm thanh @@ -1045,473 +1176,484 @@ Nhập vào - + Export Xuất ra - + Edit Chỉnh sửa - + Selection Chọn - + View Hiển thị - + Onion Skin Onion skin - + Animation Diễn hoạt - - + + Tools Công cụ - + Layer Layer - - + + Help Trợ giúp - + Windows Cửa sổ - + New Tạo Mới - + Open Mở ra - + Save Lưu lại - + Save As .. Lưu ở nơi khác - + Exit Thoát - - + + Image Sequence... Hàng chờ hình ảnh - - + + Image... Hình ảnh... - - + + Movie... Video... - - + + Palette... Bảng màu... - + Sound... Âm thanh... - + Undo Quay lại bước trước Đó - + Redo Thực hiện tiếp - + Cut Cắt - + Copy Sao chép - + Paste Dán - + Crop Gọt hình ảnh - + Crop To Selection Gọt hình ảnh theo vùng chọn - + Select All Chọn tất cả - + Deselect All Bỏ chọn tất cả - - + + Clear Frame Làm sạch Frame - + Preferences Cài Đặt chung - + Reset Windows Khởi Động lại - + Zoom In Phóng to - + Zoom Out Thu nhỏ - + Rotate Clockwise Xoay theo chiều kim Đồng hồ - + Rotate AntiClosewise Xoay ngược chiều kim Đồng hồ - + Reset Zoom/Rotate Đưa về mặc Định Phóng to/Xoay góc - + Horizontal Flip Lật theo chiều ngang - + Vertical Flip Lật theo chiều dọc - + Preview Xem trước - + Grid Lưới - + Previous Trước Đó - + Show previous onion skin HIển thị Onion Skin trước Đó - + Next Kế tiếp - + Show next onion skin Hiển thị Onion skin kế tiếp - - + + Play Chạy - + Loop Lập lại - + Next Frame Frame kế tiếp - + Previous Frame Frame trước Đó - + Extend Frame Frame mở rộng - + Add Frame Thêm Frame vào - + Duplicate Frame Sao chép frame - + Remove Frame Gỡ bỏ frame - + Move Di chuyển - + Select Chọn - + Brush Cọ vẽ - + Polyline Polyline - + Smudge Làm mờ - + Pen Viết mực - + Hand Bàn tay - + Pencil Bút chì - + Bucket Xô màu - + Eyedropper Chọn màu - + Eraser Tẩy xóa - + New Bitmap Layer Layer Bitmap mới - + New Vector Layer Layer Vector mới - + New Sound Layer Layer âm thanh mới - + New Camera Layer Layer máy quay mới - + Delete Current Layer Xóa layer hiện hành - + About Giới thiệu - - + + Reset to default Đưa về mặc Định - + MultiLayer Onion Skin Onion skin Đa layer - + Range Khoảng vùng - + Pencil2D Website - + Report a Bug - + Quick Reference Guide - + F1 - - + + + Animated GIF... + + + + + Next KeyFrame Key Frame tiếp theo - - + + Previous KeyFrame Key frame trước Đó - + Timeline Dòng thời gian - + Options Các lựa chọn - + Color Wheel Bánh xe màu - + Color Palette Bảng màu - + Display Options Lựa chọn hiển thị - + Flip X Lật theo trục X - + Flip Y Lật theo trục Y - + Move Frame Forward Di chuyển Frame tới trước - + Move Frame Backward Di chuyển Frame về sau - + color palette:<br>use <b>(C)</b><br>toggle at cursor <b>Bảng màu:<br>Sử dụng(C)</b><br>bật tắt con trỏ - + + Color inspector + + + + Lock Windows Khóa cửa sổ hiển thị - + Open Recent Mở file gần Đây - + You have successfully cleared the list @@ -1520,215 +1662,263 @@ Bạn Đã xóa thành công danh sách - - - - - + + + + + Could not open file + + + + + The file you have selected is a directory, so we are unable to open it. If you are are trying to open a project that uses the old structure, please open the file ending with .pcl, not the data folder. + + + + + The file you have selected does not exist, so we are unable to open it. Please check to make sure that you've entered the correct path and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + + + Warning Cảnh báo - - - Pencil cannot read this file. If you want to import images, use the command import. - Pencil không thể mở file này. Nếu như bạn muốn nhập vào hình ảnh, hãy sử dụng chức nhăn "Nhập vào" + + This program does not currently have permission to write to the file you have selected. Please make sure you have write permission for this file before attempting to save it. Alternatively, you can use the Save As... menu option to save to a writable location. + - + Opening document... Đang mở file... - - - + + + + Abort Từ chối - + + An unknown error occurred while trying to load the file and we are not able to load your file. + + + + Saving document... Đang lưu file... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>Có lỗi phát sinh và file của bạn không thể lưu lại. Nếu bạn cho rằng Đây là lỗi thuộc về Pencil2D, hãy thông báo cho chúng tôi biết tại<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Hãy chắc rằng bạn Đã gửi những chi tiết lỗi sau Đây cho chúng tôi: - + This animation has been modified. Do you want to save your changes? File hoạt hình Đã Được thay Đổi Bạn có chắc rằng muốn lưu lại những thay Đổi này? - + The animation is not saved yet. Do you want to save now? File này chưa Được lưu. Bạn có muốn lưu ngay không? - + Never ask again AutoSave reminder button Đừng hỏi lại - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. Không thể nhập vào hình ảnh.<br><b>Cách giải quyết:</b>Hãy sử dụng Layer Bitmap Để nhập vào ảnh Bitmaps. - + Importing image sequence... - + + was unable to import - - + + Importing Animated GIF... + + + + + Undo Menu item text - + Redo Menu item text - + Stop Ngừng ngay + + MoveTool + + + Layer switch + Windows title of layer switch pop-up. + + + + + You are about to switch layer, do you want to apply the transformation? + + + Object - + Black Trở lại - + Red Đỏ - + Dark Red Đỏ Đậm - + Orange Cam - + Dark Orange Cam Đậm - + Yellow Vàng - + Dark Yellow Vàng Đậm - + Green Xanh lá cây - + Dark Green Xanh lá cây Đậm - + Cyan Lục lam - + Dark Cyan Lục lam sậm - + Blue Xanh dương - + Dark Blue Xanh dương Đậm - + White Trắng - + Very Light Grey Xám nhạt - + Light Grey Xám nhẹ - + Grey Xám - + Dark Grey Xám Đậm - + Light Skin Màu da sáng - + Light Skin - shade Màu da sáng Đổ bóng - + Skin Màu da - + Skin - shade Bóng da - + Dark Skin Da sậm - + Dark Skin - shade Bóng da sậm @@ -1736,153 +1926,153 @@ Bạn có muốn lưu ngay không? PencilApplication - + Pencil2D is an animation/drawing software for Mac OS X, Windows, and Linux. It lets you create traditional hand-drawn animation (cartoon) using both bitmap and vector graphics. Pencil2D là một phần mềm làm phim hoạt hình dành cho hệ Điều hành Mac OS X, Windows và Linux. Pencil2D cho phép bạn có Được cảm giác vẽ tay truyền thống(Hoạt hình vẽ tay) khi sử dụng cả hai chế Độ ảnh Bitmap và Vector. - + Path to the input pencil file. Đường Dẫn Đến file nhập vào - - + + Render the file to <output_path> Xuất file thành <output_path> - - + + output_path Đường dẫn xuất ra - + Name of the camera layer to use - + layer_name - + Width of the output frames Chiều rộng của Frame xuất ra - - + + integer Kiểu số nguyên - + Height of the output frames Chiều cao của Frame xuất ra - + The first frame you want to include in the exported movie - - + + frame - + The last frame you want to include in the exported movie. Can also be last or last-sound to automatically use the last frame containing animation or sound, respectively - + Render transparency when possible Xuất nền trong suốt nếu khả thi - + Warning: width value %1 is not an integer, ignoring. Cảnh báo: Giá trị chiều rộng nhập vào %1 không phải thuộc kiểu số nguyên, sẽ không thể xử lý. - + Warning: height value %1 is not an integer, ignoring. Cảnh báo: Giá trị chiều cao nhập vào %1 không phải là kiểu số nguyên, sẽ không thể xử lý. - + Warning: start value %1 is not an integer, ignoring. - + Warning: start value must be at least 1, ignoring. - + Warning: end value %1 is not an integer, last or last-sound, ignoring. - + Warning: end value %1 is smaller than start value %2, ignoring. - + Error: No input file specified. Lỗi: Không thể xác Định file Đưa vào - + Error: the input file at '%1' does not exist Command line error - + Error: the input path '%1' is not a file Command line error - + Warning: the specified camera layer %1 was not found, ignoring. - + Warning: Output format is not specified or unsupported. Using PNG. Command line warning - + Warning: Transparency is not currently supported in movie files Command line warning - + Exporting movie... Command line task progress - - + + Done. Command line task done - + Exporting image sequence... Command line task progress @@ -1924,12 +2114,12 @@ Bạn có muốn lưu ngay không? QApplication - + Checking environment... - + Done @@ -1937,42 +2127,47 @@ Bạn có muốn lưu ngay không? QObject - + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) AVI - Video (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) - - Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp) - + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp); + + + + Everything ok. Mọi thứ Đã sẵn sàng - + Ooops, Something went wrong. Ooops, Đã có lỗi phát sinh - + File doesn't exist. File không tồn tại - + Cannot open file. Không thể mở file này - + The file is not a valid xml document. File này không có Định dạng chuẩn của tài liệu XML - + The file is not valid pencil document. File này không phải là file Định dạng chuẩn của Pencil2D @@ -3321,6 +3516,16 @@ Bạn có muốn lưu ngay không? Black Đen + + + Could not open file + + + + + There was an error processing your file. This usually means that your project has been at least partially corrupted. You can try again with a newer version of Pencil2D, or you can try to use a backup file if you have one. If you contact us through one of our offical channels we may be able to help you. For reporting issues, the best places to reach us are: + + RecentFileMenu @@ -3338,60 +3543,60 @@ Bạn có muốn lưu ngay không? ScribbleArea - + Warning Cảnh báo - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). Bạn Đang vẽ trên một Layer có thuộc tính ẩn! Hãy chọn một Layer khác (Hoặc Điều chỉnh thuộc tính Layer hiện tại thành hiển thị). - + Delete Selection Undo Step: clear the selection area. - - + + Clear Image Undo step text Làm sạch hình ảnh - + There is a gap in your drawing (or maybe you have zoomed too much). Xuất hiện hiện tượng rổ trên ảnh của bạn (hoặc bạn Đã phóng to quá nhiều). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). Thật xin lỗi! Chức năng này vẫn chưa Được hoàn thiện. Hãy thử lại một lần nữa (Phóng to một chút thôi, và chọn chỗ khác...) <br>Nếu chức năng vẫn không hoạt Động, Phóng to vào một chút và kiểm tra Đường dẫn chính xác bằng cách nhấn F1.). - + Out of bound. Ngoài giới hạn xử lý - + Could not find a closed path. Không thể tìm Được Đường dẫn Đúng - + Could not find the root index. Không thể tìm Được chỉ mục gốc - + %1<br><br>Error: %2 %1<br><br>Lỗi: %2 - + Flood fill error Lỗi tô màu @@ -3488,12 +3693,12 @@ Bạn có muốn lưu ngay không? - + Start Bắt Đầu - + Stop Ngưng lại @@ -3577,18 +3782,18 @@ Bạn có muốn lưu ngay không? Chuyển Đổi so sánh các keyframe - + Delete Layer Windows title of Delete current layer pop-up. - + Please keep at least one camera layer in project - + Are you sure you want to delete layer: Bạn có chắc là muốn xóa Layer: @@ -3596,12 +3801,12 @@ Bạn có muốn lưu ngay không? TimeLineCells - + Layer Properties - + Layer name: @@ -3678,6 +3883,16 @@ Bạn có muốn lưu ngay không? <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + + Playback + + + + + Show onion skin while playing + + Frame size diff --git a/translations/pencil_zh_CN.qm b/translations/pencil_zh_CN.qm new file mode 100644 index 0000000000000000000000000000000000000000..8fcf417d50eec1981218aaf057858e10a69f8b72 GIT binary patch literal 60141 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 XJwf9j%chZA%%^9$f0ev8sL1|5oYJ;( literal 0 HcmV?d00001 diff --git a/translations/pencil_zh_CN.ts b/translations/pencil_zh_CN.ts new file mode 100644 index 000000000..1741c1a18 --- /dev/null +++ b/translations/pencil_zh_CN.ts @@ -0,0 +1,4222 @@ + + + AboutDialog + + + About + About Dialog Window Title + 关于 + + + + Official site: <a href="https://www.pencil2d.org">pencil2d.org</a><br>Developed by: <b>Pascal Naidon, Patrick Corrieri, Matt Chang</b><br>Thanks to Qt Framework <a href="https://www.qt.io/download">https://www.qt.io/</a><br>miniz: <a href="https://github.com/richgel999/miniz">https://github.com/richgel999/miniz</a><br>Distributed under the <a href="http://www.gnu.org/licenses/gpl-2.0.html">GNU General Public License, version 2</a> + 官方站点: <a href="https://www.pencil2d.org">pencil2d.org</a><br>开发者: <b>Pascal Naidon, Patrick Corrieri, Matt Chang</b><br>致谢 Qt Framework <a href="https://www.qt.io/download">https://www.qt.io/</a><br>miniz: <a href="https://github.com/richgel999/miniz">https://github.com/richgel999/miniz</a><br>分发许可: <a href="http://www.gnu.org/licenses/gpl-2.0.html">GNU General Public License, version 2</a> + + + + Version: %1 + Version Number in About Dialog + 版本: %1 + + + + Copy to clipboard + Copy system info from About Dialog + 复制到剪贴板 + + + + ActionCommands + + + No sound layer exists as a destination for your import. Create a new sound layer? + 没有声音层当作导入目的地。要新建声音层吗? + + + + Create sound layer + 创建声音层 + + + + Don't create layer + 不创建层 + + + + Layer Properties + Dialog title on creating a sound layer + 层属性 + + + + Sound Layer + Default name on creating a sound layer + 声音层 + + + + Exporting movie + 导出电影 + + + + Finished. Open movie now? + When movie export done. + 完成。现在打开电影吗? + + + + + + + Layer Properties + 层属性 + + + + + + + + Layer name: + 层名: + + + + A sound clip already exists on this frame! Please select another frame or layer. + 该帧已经存在音频剪辑!请选择其它的帧或层。 + + + + Finished. Open file location? + 完成。打开文件位置? + + + + Exporting image sequence... + 导出图像序列... + + + + Abort + 关于 + + + + Warning + 警告 + + + + Unable to export image. + 不能导出图像。 + + + + Bitmap Layer + 位图层 + + + + Vector Layer + 矢量层 + + + + Camera Layer + 相机层 + + + + Sound Layer + 声音层 + + + + Delete Layer + Windows title of Delete current layer pop-up. + 删除层 + + + + Are you sure you want to delete layer: + 确定要删除层吗: + + + + Please keep at least one camera layer in project + text when failed to delete camera layer + 请至少保留一个相机层在项目里 + + + + BaseTool + + + Pencil + 铅笔 + + + + Eraser + 橡皮擦 + + + + Select + 选择 + + + + Move + 移动 + + + + Hand + 抓手 + + + + Smudge + 涂抹 + + + + Pen + 钢笔 + + + + Polyline + 折线 + + + + Bucket + 颜料桶 + + + + Eyedropper + 吸管 + + + + Brush + 笔刷 + + + + CameraPropertiesDialog + + + Camera Properties + 相机属性 + + + + Camera name: + 相机名: + + + + Camera size: + 相机尺寸: + + + + ColorBox + + + Color Box + Color Box window title + 颜色盒 + + + + ColorInspector + + + HSV + HSV + + + + RGB + RGB + + + + R + R + + + + A + A + + + + G + G + + + + B + B + + + + Color Inspector + Window title of color inspector + 颜色检视器 + + + + ColorPalette + + + Color Palette + Window title of color palette. + 调色板 + + + + Add Color + 增加颜色 + + + + Remove Color + 删除颜色 + + + + Native color dialog window + 操作系统原生颜色对话窗口 + + + + List Mode + 列表模式 + + + + Show palette as a list + 列表显示调色板 + + + + Grid Mode + 栅格模式 + + + + Show palette as icons + 图标显示调色板 + + + + Small swatch + 小色块 + + + + Sets swatch size to: 16x16px + 设置色块尺寸为: 16x16px + + + + Medium Swatch + 中色块 + + + + Sets swatch size to: 26x26px + 设置色块尺寸为: 26x26px + + + + Large Swatch + 打色块 + + + + Sets swatch size to: 36x36px + 设置色块尺寸为: 36x36px + + + + ColorPaletteWidget + + + Add + 添加 + + + + Replace + 置换 + + + + Remove + 删除 + + + + + Colour name + 颜色名 + + + + The color(s) you are about to delete are currently being used by one or multiple strokes. + 你要删除的颜色用在了一个或多个笔划中。 + + + + Cancel + 取消 + + + + Delete + 删除 + + + + Palette Restriction + 调色板限制集 + + + + The palette requires at least one swatch to remain functional + 调色板至少需要保留一个色块 + + + + ColorWheel + + + Color Wheel + Color Wheel's window title + 色轮 + + + + DisplayOption + + + Horizontal flip + 水平反转 + + + + + + + + + + ... + ... + + + + Display + Window title of display options like . + 显示 + + + + + Onion skin previous frame + 洋葱皮前一帧 + + + + Show invisible lines + 显示不可见的线 + + + + + Onion skin color: blue + 洋葱皮颜色: 蓝 + + + + + Onion skin next frame + 洋葱皮后一帧 + + + + + Onion skin color: red + 洋葱皮颜色: 红 + + + + Show outlines only + 仅显示轮廓 + + + + Vertical flip + 垂直反转 + + + + DoubleProgressDialog + + + Loading... + 加载中... + + + + Cancel + 取消 + + + + Editor + + + + Paste + 粘贴 + + + + Remove frame + 删除帧 + + + + + Import Image + 导入图像 + + + + ErrorDialog + + + Dialog + 对话框 + + + + <h3>Title</h3> + <h3>标题</h3> + + + + Description + 描述 + + + + ExportImageDialog + + + Export image sequence + 导出图像序列 + + + + Export image + 导出图像 + + + + ExportImageOptions + + + Camera + 相机 + + + + Resolution + 分辨率 + + + + Format + 格式 + + + + PNG + PNG + + + + JPG + JPG + + + + BMP + BMP + + + + Transparency + 透明 + + + + Range + 范围 + + + + The last frame you want to include in the exported movie + 要包含在导出电影里的最后一帧 + + + + End Frame + 结束帧 + + + + The first frame you want to include in the exported movie + 要包含在导出电影里的第一帧 + + + + Start Frame + 起始帧 + + + + <html><head/><body><p>End frame is set to last paintable keyframe (Useful when you only want to export to the last animated frame)</p></body></html> + <html><head/><body><p>结束帧设置成最后一个可以绘制的关键帧(用于想导出最后一个动画帧时)</p></body></html> + + + + To the end of sound clips + 到声音剪辑的结尾处 + + + + ExportMovieDialog + + + Export Animated GIF + 导出动画 GIF + + + + Export Movie + 导出电影 + + + + ExportMovieOptions + + + Camera + 相机 + + + + Resolution + 分辨率 + + + + Width + 宽度 + + + + Height + 高度 + + + + Range + 范围 + + + + The last frame you want to include in the exported movie + 要导出在电影中的最后一帧 + + + + End Frame + 结束帧 + + + + The first frame you want to include in the exported movie + 要 包含在导出电影里的第一帧 + + + + Start Frame + 起始帧 + + + + <html><head/><body><p>End frame is set to last paintable keyframe (Useful when you only want to export to the last animated frame)</p></body></html> + <html><head/><body><p>结束帧设置成最后一个可以绘制的关键帧(用于想导出最后一个动画帧时)</p></body></html> + + + + To the end of sound clips + 到声音剪辑的结尾处 + + + + GIF and APNG only + 仅 GIF 和 APNG + + + + Loop + 循环 + + + + FileDialog + + + Open animation + 打开动画 + + + + Import image + 导入图像 + + + + Import image sequence + 导入图像序列 + + + + Import Animated GIF + 导入动画 GIF + + + + Import movie + 导入电影 + + + + Import sound + 导入声音 + + + + Import palette + 导入调色板 + + + + Save animation + 保存动画 + + + + Export image + 导出图像 + + + + Export image sequence + 导出图像序列 + + + + Export Animated GIF + 导出动画 GIF + + + + Export movie + 导出电影 + + + + Export sound + 导出声音 + + + + Export palette + 导出调色板 + + + + + Animated GIF (*.gif) + 动画 GIF (*.gif) + + + + Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) + 声音 (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) + + + + + Pencil2D Palette (*.xml);; Gimp Palette (*.gpl) + Pencil2D 调色板 (*.xml);; Gimp 调色板 (*.gpl) + + + + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng) + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng) + + + + MyAnimation.pclx + 我的动画.pclx + + + + FileManager + + + + Could not open file + 不能打开文件 + + + + The file does not exist, so we are unable to open it. Please check to make sure the path is correct and that the file is accessible and try again. + 该文件不存在,我们没法打开。请检查并保证路径正确而且文件可以访问之后再试一次。 + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + 程序没有权限读取你选的文件。请检查并确认有读取权限后再试一次。 + + + + + + Invalid Save Path + 无效的保存路径 + + + + The path ("%1") points to a directory. + 路径 ("%1") 指向一个目录。 + + + + The directory ("%1") does not exist. + 目录 ("%1") 不存在。 + + + + The path ("%1") is not writable. + 路径 ("%1") 是不可写入的。 + + + + + Cannot Create Data Directory + 不能创建数据目录 + + + + Failed to create directory "%1". Please make sure you have sufficient permissions. + 创建目录 "%1" 失败。请确保拥有足够的权限。 + + + + "%1" is a file. Please delete the file and try again. + "%1" 是一个文件。请删除文件再尝试一次。 + + + + Miniz Error + Miniz 错误 + + + + Internal Error + 内部错误 + + + + + An internal error occurred. Your file may not be saved successfully. + 发生了一个内部错误。你的文件可能没有保存成功。 + + + + FilesPage + + + Autosave documents + Preference + 自动保存文档 + + + + Enable autosave + Preference + 启用自动保存 + + + + Number of modifications before autosaving: + Preference + 自动保存前的修改数: + + + + GeneralPage + + + Language + GroupBox title in Preference + 语言 + + + + Window opacity + GroupBox title in Preference + 窗口不透明度 + + + + Background + GroupBox title in Preference + 背景 + + + + Appearance + GroupBox title in Preference + 外观 + + + + + [System-Language] + First item of the language list + [系统语言] + + + + Canvas + GroupBox title in Preference + 画布 + + + + Editing + GroupBox title in Preference + 编辑 + + + + Grid + groupBox title in Preference + 栅格 + + + + Czech + 捷克语 + + + + Danish + 丹麦语 + + + + English + 英语 + + + + German + 德语 + + + + Estonian + 爱莎尼亚语 + + + + Spanish + 西班牙语 + + + + French + 法语 + + + + Hebrew + 希伯莱语 + + + + Hungarian + 匈牙利语 + + + + Indonesian + 印度尼西亚语 + + + + Italian + 意大利语 + + + + Japanese + 日语 + + + + Polish + 波兰语 + + + + Portuguese - Portugal + 葡萄牙语 - 葡萄牙 + + + + Portuguese - Brazil + 葡萄牙语 - 巴西 + + + + Russian + 俄语 + + + + Slovenian + 斯洛文尼亚语 + + + + Vietnamese + 越南语 + + + + Chinese - Taiwan + 中文 - 台湾 + + + + Opacity + 不透明度 + + + + Shadows + 阴影 + + + + Tool Cursors + 工具光标 + + + + Antialiasing + 抗锯齿 + + + + Dotted Cursor + 带点光标 + + + + Enable Grid + 启用栅格 + + + + Vector curve smoothing + 矢量曲线平滑 + + + + Tablet high-resolution position + 绘图板高分辨率位置 + + + + Restart Required + 需要重启 + + + + The language change will take effect after a restart of Pencil2D + 语言的更改在重启 Pencil2D 后起作用 + + + + ImportExportDialog + + + File + 文件 + + + + Browse... + 浏览... + + + + Options + 选项 + + + + ImportImageSeqDialog + + + Import Animated GIF + 导入动画 GIF + + + + Import image sequence + 导入图像序列 + + + + ImportImageSeqOptions + + + Import an image every # frame + 每 # 帧导入一幅图像 + + + + Layer + + + Undefined Layer + 未定义的层 + + + + LayerBitmap + + + Bitmap Layer + 位图层 + + + + LayerCamera + + + Camera Layer + 相机层 + + + + LayerSound + + + Sound Layer + 声音层 + + + + LayerVector + + + Vector Layer + 矢量层 + + + + MainWindow2 + + + MainWindow + 主窗口 + + + + File + 文件 + + + + Import + 导入 + + + + Export + 导出 + + + + Edit + 编辑 + + + + Selection + 选择 + + + + View + 查看 + + + + Onion Skin + 洋葱皮 + + + + Animation + 动画 + + + + + Tools + 工具 + + + + Layer + + + + + + Help + 帮助 + + + + Windows + 窗口 + + + + New + 新建 + + + + Open + 打开 + + + + Save + 保存 + + + + Save As .. + 另存为... + + + + Exit + 退出 + + + + + Image Sequence... + 图像序列... + + + + + Image... + 图像... + + + + + Movie... + 电影... + + + + + Palette... + 调色板... + + + + Sound... + 声音... + + + + Undo + 撤销 + + + + Redo + 重做 + + + + Cut + 剪切 + + + + Copy + 复制 + + + + Paste + 粘贴 + + + + Crop + 裁剪 + + + + Crop To Selection + 裁剪到选择 + + + + Select All + 选择全部 + + + + Deselect All + 取消选择全部 + + + + + Clear Frame + 清除帧 + + + + Preferences + 首选项 + + + + Reset Windows + 重置窗口 + + + + Zoom In + 放大 + + + + Zoom Out + 缩小 + + + + Rotate Clockwise + 顺时针旋转 + + + + Rotate AntiClosewise + 逆时针旋转 + + + + Reset Zoom/Rotate + 重置缩放/旋转 + + + + Horizontal Flip + 水平反转 + + + + Vertical Flip + 垂直反转 + + + + Preview + 预览 + + + + Grid + 栅格 + + + + Previous + 前一帧 + + + + Show previous onion skin + 显示前一帧洋葱皮 + + + + Next + 后一帧 + + + + Show next onion skin + 显示后一帧洋葱皮 + + + + + Play + 播放 + + + + Loop + 循环 + + + + Next Frame + 后一帧 + + + + Previous Frame + 前一帧 + + + + Extend Frame + 扩展帧 + + + + Add Frame + 添加帧 + + + + Duplicate Frame + 复制帧 + + + + Remove Frame + 删除帧 + + + + Move + 移动 + + + + Select + 选择 + + + + Brush + 画笔 + + + + Polyline + 折线 + + + + Smudge + 涂抹 + + + + Pen + 钢笔 + + + + Hand + 抓手 + + + + Pencil + 铅笔 + + + + Bucket + 颜料桶 + + + + Eyedropper + 吸管 + + + + Eraser + 橡皮擦 + + + + New Bitmap Layer + 新建位图层 + + + + New Vector Layer + 新建矢量层 + + + + New Sound Layer + 新建声音层 + + + + New Camera Layer + 新建相机层 + + + + Delete Current Layer + 删除当前层 + + + + About + 关于 + + + + + Reset to default + 重置为默认 + + + + MultiLayer Onion Skin + 多层洋葱皮 + + + + Range + 范围 + + + + Pencil2D Website + Pencil2D 网站 + + + + Report a Bug + 报告问题 + + + + Quick Reference Guide + 快速参考指南 + + + + F1 + F1 + + + + + Animated GIF... + 动画 GIF... + + + + + Next KeyFrame + 后一关键帧 + + + + + Previous KeyFrame + 前一关键帧 + + + + Timeline + 时间轴 + + + + Options + 选项 + + + + Color Wheel + 色轮 + + + + Color Palette + 调色板 + + + + Display Options + 显示选项 + + + + Flip X + 反转 X + + + + Flip Y + 反转 Y + + + + Move Frame Forward + 向前移动帧 + + + + Move Frame Backward + 先后移动帧 + + + + color palette:<br>use <b>(C)</b><br>toggle at cursor + 调色板<br>使用 <b>(C)</b><br>光标位置切换 + + + + Color inspector + 颜色检视器 + + + + Lock Windows + 锁定窗口 + + + + Open Recent + 打开最近使用 + + + + + + You have successfully cleared the list + + + 你已经成功清除列表 + + + + + + + Could not open file + 不能打开文件 + + + + The file you have selected is a directory, so we are unable to open it. If you are are trying to open a project that uses the old structure, please open the file ending with .pcl, not the data folder. + 你选的文件是个目录,我们不能打开它。如果你在试图打开用了旧结构的项目,请直接打开 pcl 文件,而非数据文件夹。 + + + + The file you have selected does not exist, so we are unable to open it. Please check to make sure that you've entered the correct path and that the file is accessible and try again. + 你选的文件不存在,我们没法打开。请检查并保证路径正确而且文件可以访问之后再试一次。 + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + 程序没有权限读取你选的文件。请检查并确认有读取权限后再试一次。 + + + + + + + + Warning + 警告 + + + + This program does not currently have permission to write to the file you have selected. Please make sure you have write permission for this file before attempting to save it. Alternatively, you can use the Save As... menu option to save to a writable location. + 程序没有权限写入你选的文件。请在保存文件之前确认有该文件的写入权限。另外,你可以用 另存为.. 菜单项保存到一个可以写的地方。 + + + + Opening document... + 打开文档中... + + + + + + + Abort + 关于 + + + + An unknown error occurred while trying to load the file and we are not able to load your file. + 加载文件时发生了未知错误,我们没法加载你的文件。 + + + + Saving document... + 保存文档中... + + + + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: + <br><br>发生错误,你的文件没有保存成功。如果你确信问题来自 Pencile2D,请在 <br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>开个新问题。另外请包含如下的细节在其中: + + + + This animation has been modified. + Do you want to save your changes? + 该动画被修改过了。 +你要保存所做的变动吗? + + + + The animation is not saved yet. + Do you want to save now? + 该动画还没被保存。 +你要现在保存吗? + + + + Never ask again + AutoSave reminder button + 不要再问 + + + + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. + 不能导入图像<br><b>贴士:</b> 使用位图层导入位图。 + + + + Importing image sequence... + 导入图像序列... + + + + + was unable to import + 不能导入 + + + + Importing Animated GIF... + 导入动画 GIF... + + + + + Undo + Menu item text + 撤销 + + + + Redo + Menu item text + 重做 + + + + Stop + 停止 + + + + MoveTool + + + Layer switch + Windows title of layer switch pop-up. + 层切换 + + + + You are about to switch layer, do you want to apply the transformation? + 你就要切换层,是否要应用所设的变换? + + + + Object + + + Black + 黑色 + + + + Red + 红色 + + + + Dark Red + 深红色 + + + + Orange + 橙色 + + + + Dark Orange + 深橙色 + + + + Yellow + 黄色 + + + + Dark Yellow + 深黄色 + + + + Green + 绿色 + + + + Dark Green + 深绿色 + + + + Cyan + 青色 + + + + Dark Cyan + 深青色 + + + + Blue + 蓝色 + + + + Dark Blue + 深蓝色 + + + + White + 白色 + + + + Very Light Grey + 超浅灰色 + + + + Light Grey + 浅灰色 + + + + Grey + 灰色 + + + + Dark Grey + 深灰色 + + + + Light Skin + 浅肤色 + + + + Light Skin - shade + 浅肤色 - 阴影 + + + + Skin + 肤色 + + + + Skin - shade + 肤色 - 阴影 + + + + Dark Skin + 深肤色 + + + + Dark Skin - shade + 深肤色 - 阴影 + + + + PencilApplication + + + Pencil2D is an animation/drawing software for Mac OS X, Windows, and Linux. It lets you create traditional hand-drawn animation (cartoon) using both bitmap and vector graphics. + Pencil2D 是动画/绘画软件,运行与 macOS,Windows 和 Linux。通过它可以用位图和矢量图像手段创作传统手绘动画(卡通)。 + + + + Path to the input pencil file. + 输入 Pencil 文件的路径。 + + + + + Render the file to <output_path> + 渲染文件的路径<output_path> + + + + + output_path + 输出路径 + + + + Name of the camera layer to use + 要用的相机层的名字 + + + + layer_name + 层名 + + + + Width of the output frames + 输出帧的宽度 + + + + + integer + 整数 + + + + Height of the output frames + 输出帧的高度 + + + + The first frame you want to include in the exported movie + 要包含在导出电影里的第一帧 + + + + + frame + + + + + The last frame you want to include in the exported movie. Can also be last or last-sound to automatically use the last frame containing animation or sound, respectively + 要包含在导出电影里的最后一帧。也可以自动选动画或声音的最后一帧 + + + + Render transparency when possible + 尽可能渲染透明度 + + + + Warning: width value %1 is not an integer, ignoring. + 警告:宽度值 %1 不是整数,已忽略。 + + + + Warning: height value %1 is not an integer, ignoring. + 警告:高度值 %1 不是整数,已忽略。 + + + + Warning: start value %1 is not an integer, ignoring. + 警告:起始值 %1 不是整数,已忽略。 + + + + Warning: start value must be at least 1, ignoring. + 警告:起始值最小必须是1,已忽略。 + + + + Warning: end value %1 is not an integer, last or last-sound, ignoring. + 警告:结束值 %1 不是整数,也不是最后的动画帧或声音,已忽略。 + + + + Warning: end value %1 is smaller than start value %2, ignoring. + 警告:结束值 %1 小于 %2,已忽略。 + + + + Error: No input file specified. + 错误:没有定义输入文件。 + + + + Error: the input file at '%1' does not exist + Command line error + 错误:在 ‘%1’ 的输入文件不存在 + + + + Error: the input path '%1' is not a file + Command line error + 错误:输入路径 '%1' 不是一个文件 + + + + Warning: the specified camera layer %1 was not found, ignoring. + 警告:指定的相机层 %1 没有找到,已忽略。 + + + + Warning: Output format is not specified or unsupported. Using PNG. + Command line warning + 警告:输出格式不支持。将用 PNG。 + + + + Warning: Transparency is not currently supported in movie files + Command line warning + 警告:电影文件还不支持透明 + + + + Exporting movie... + Command line task progress + 导出电影... + + + + + Done. + Command line task done + 完成。 + + + + Exporting image sequence... + Command line task progress + 导出图像序列... + + + + PreferencesDialog + + + Preferences + 首选项 + + + + General + 通用 + + + + Files + 文件 + + + + Timeline + 时间轴 + + + + Tools + 工具 + + + + Shortcuts + 快捷键 + + + + QApplication + + + Checking environment... + 检查环境中... + + + + Done + 完成 + + + + QObject + + + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) + + + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp) + 图像 (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp) + + + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp); + 图像 (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp); + + + + Everything ok. + 一切良好。 + + + + Ooops, Something went wrong. + 哦,有点问题。 + + + + File doesn't exist. + 文件不存在。 + + + + Cannot open file. + 不能打开文件。 + + + + The file is not a valid xml document. + 该文件不是有效的 XML 文档。 + + + + The file is not valid pencil document. + 该文件不是有效的 Pencil 文档。 + + + + All Pencil Files PCLX & PCL(*.pclx *.pcl);;Pencil Animation File PCLX(*.pclx);;Old Pencil Animation File PCL(*.pcl);;Any files (*) + 所以 Pencil 文件 PCLX & PCL(*.pclx *.pcl);;Pencil 动画文件 PCLX(*.pclx);;旧版 Pencil 动画文件 PCL(*.pcl);;任意文件 (*) + + + + Pencil Animation File PCLX(*.pclx);;Old Pencil Animation File PCL(*.pcl) + Pencil 动画文件 PCLX(*.pclx);;旧版 Pencil 动画文件 PCL(*.pcl) + + + + Vivid Pink + 鲜粉红色 + + + + Strong Pink + 浓粉红色 + + + + Deep Pink + 深粉红色 + + + + Light Pink + 淡粉红色 + + + + Moderate Pink + 中粉红色 + + + + Dark Pink + 暗粉红色 + + + + Pale Pink + 浅粉红色 + + + + Grayish Pink + 浅灰粉红色 + + + + Pinkish White + 粉红白色 + + + + Pinkish Gray + 粉红灰色 + + + + Vivid Red + 鲜红色 + + + + Strong Red + 大红色 + + + + Deep Red + 深红色 + + + + Very Deep Red + 超深红色 + + + + Moderate Red + 中红色 + + + + Dark Red + 暗红色 + + + + Very Dark Red + 超暗红色 + + + + Light Grayish Red + 浅灰红色 + + + + Grayish Red + 灰红色 + + + + Dark Grayish Red + 暗灰红色 + + + + Blackish Red + 殷红色 + + + + Reddish Gray + 红灰色 + + + + Dark Reddish Gray + 暗红灰色 + + + + Reddish Black + 红黑色 + + + + Vivid Yellowish Pink + 鲜黄粉红色 + + + + Strong Yellowish Pink + 大黄粉红色 + + + + Deep Yellowish Pink + 深黄粉红色 + + + + Light Yellowish Pink + 浅黄粉红色 + + + + Moderate Yellowish Pink + 中黄粉红色 + + + + Dark Yellowish Pink + 暗黄粉红色 + + + + Pale Yellowish Pink + 淡黄粉红色 + + + + Grayish Yellowish Pink + 灰黄粉红色 + + + + Brownish Pink + 褐粉红色 + + + + Vivid Reddish Orange + 鲜红橙色 + + + + Strong Reddish Orange + 大红橙色 + + + + Deep Reddish Orange + 深红橙色 + + + + Moderate Reddish Orange + 中红橙色 + + + + Dark Reddish Orange + 暗红橙色 + + + + Grayish Reddish Orange + 灰红橙色 + + + + Strong Reddish Brown + 大红褐色 + + + + Deep Reddish Brown + 深红褐色 + + + + Light Reddish Brown + 浅红褐色 + + + + Moderate Reddish Brown + 中红褐色 + + + + Dark Reddish Brown + 暗红褐色 + + + + Light Grayish Reddish Brown + 浅灰红褐色 + + + + Grayish Reddish Brown + 灰红褐色 + + + + Dark Grayish Reddish Brown + 暗灰红褐色 + + + + Vivid Orange + 鲜橙色 + + + + Brilliant Orange + 亮橙色 + + + + Strong Orange + 浓橙色 + + + + Deep Orange + 深橙色 + + + + Light Orange + 浅橙色 + + + + Moderate Orange + 中橙色 + + + + Brownish Orange + 褐橙色 + + + + Strong Brown + 大褐色 + + + + Deep Brown + 深褐色 + + + + Light Brown + 浅褐色 + + + + Moderate Brown + 中褐色 + + + + Dark Brown + 暗褐色 + + + + Light Grayish Brown + 浅灰褐色 + + + + Grayish Brown + 灰褐色 + + + + Dark Grayish Brown + 暗灰褐色 + + + + Light Brownish Gray + 浅褐灰色 + + + + Brownish Gray + 褐灰色 + + + + Brownish Black + 褐黑色 + + + + Vivid Orange Yellow + 鲜橙黄色 + + + + Brilliant Orange Yellow + 亮橙黄色 + + + + Strong Orange Yellow + 大橙黄色 + + + + Deep Orange Yellow + 深橙黄色 + + + + Light Orange Yellow + 浅橙黄色 + + + + Moderate Orange Yellow + 中橙黄色 + + + + Dark Orange Yellow + 暗橙黄色 + + + + Pale Orange Yellow + 淡橙黄色 + + + + Strong Yellowish Brown + 大黄褐色 + + + + Deep Yellowish Brown + 深黄褐色 + + + + Light Yellowish Brown + 浅黄褐色 + + + + Moderate Yellowish Brown + 中黄褐色 + + + + Dark Yellowish Brown + 暗黄褐色 + + + + Light Grayish Yellowish Brown + 浅灰黄褐色 + + + + Grayish Yellowish Brown + 灰黄褐色 + + + + Dark Grayish Yellowish Brown + 暗灰黄褐色 + + + + Vivid Yellow + 鲜黄色 + + + + Brilliant Yellow + 亮黄色 + + + + Strong Yellow + 大黄色 + + + + Deep Yellow + 深黄色 + + + + Light Yellow + 浅黄色恶 + + + + Moderate Yellow + 中黄色 + + + + Dark Yellow + 暗黄色 + + + + Pale Yellow + 淡黄色 + + + + Grayish Yellow + 灰黄色 + + + + Dark Grayish Yellow + 暗灰黄色 + + + + Yellowish White + 黄白色 + + + + Yellowish Gray + 黄灰色 + + + + Light Olive Brown + 浅橄榄褐色 + + + + Moderate Olive Brown + 中橄榄棕色 + + + + Dark Olive Brown + 暗橄榄褐色 + + + + Vivid Greenish Yellow + 鲜绿黄色 + + + + Brilliant Greenish Yellow + 亮绿黄色 + + + + Strong Greenish Yellow + 大绿黄色 + + + + Deep Greenish Yellow + 深绿黄色 + + + + Light Greenish Yellow + 浅绿黄色 + + + + Moderate Greenish Yellow + 中绿黄色 + + + + Dark Greenish Yellow + 暗绿黄色 + + + + Pale Greenish Yellow + 淡绿黄色 + + + + Grayish Greenish Yellow + 灰绿黄色 + + + + Light Olive + 浅橄榄色 + + + + Moderate Olive + 中橄榄色 + + + + Dark Olive + 暗橄榄色 + + + + Light Grayish Olive + 浅灰橄榄色 + + + + Grayish Olive + 灰橄榄色 + + + + Dark Grayish Olive + 暗灰橄榄色 + + + + Light Olive Gray + 浅橄榄色 + + + + Olive Gray + 橄榄灰色 + + + + Olive Black + 橄榄黑色 + + + + Vivid Yellow Green + 鲜黄绿色 + + + + Brilliant Yellow Green + 亮黄绿色 + + + + Strong Yellow Green + 大黄绿色 + + + + Deep Yellow Green + 深黄绿色 + + + + Light Yellow Green + 浅黄绿色 + + + + Moderate Yellow Green + 中黄绿色 + + + + Pale Yellow Green + 淡黄绿色 + + + + Grayish Yellow Green + 灰黄绿色 + + + + Strong Olive Green + 大橄榄绿色 + + + + Deep Olive Green + 深橄榄绿色 + + + + Moderate Olive Green + 中橄榄绿色 + + + + Dark Olive Green + 暗橄榄绿色 + + + + Grayish Olive Green + 灰橄榄绿色 + + + + Dark Grayish Olive Green + 暗灰橄榄绿色 + + + + Vivid Yellowish Green + 鲜黄绿色 + + + + Brilliant Yellowish Green + 亮黄绿色 + + + + Strong Yellowish Green + 大黄绿色 + + + + Deep Yellowish Green + 深黄绿色 + + + + Very Deep Yellowish Green + 超深黄绿色 + + + + Very Light Yellowish Green + 超浅黄绿色 + + + + Light Yellowish Green + 浅黄绿色 + + + + Moderate Yellowish Green + 中黄绿色 + + + + Dark Yellowish Green + 暗黄绿色 + + + + Very Dark Yellowish Green + 超暗黄绿色 + + + + Vivid Green + 鲜绿色 + + + + Brilliant Green + 亮绿色 + + + + Strong Green + 大绿色 + + + + Deep Green + 深绿色 + + + + Very Light Green + 超浅绿色 + + + + Light Green + 浅绿色 + + + + Moderate Green + 中绿色 + + + + Dark Green + 暗绿色 + + + + Very Dark Green + 超暗绿色 + + + + Very Pale Green + 超淡绿色 + + + + Pale Green + 淡绿色 + + + + Grayish Green + 灰绿色 + + + + Dark Grayish Green + 暗灰绿色 + + + + Blackish Green + 黑绿色 + + + + Greenish White + 绿白色 + + + + Light Greenish Gray + 浅绿色灰色 + + + + Greenish Gray + 绿灰色 + + + + Dark Greenish Gray + 暗绿灰色 + + + + Greenish Black + 绿黑色 + + + + Vivid Bluish Green + 鲜蓝绿色 + + + + Brilliant Bluish Green + 亮蓝绿色 + + + + Strong Bluish Green + 大蓝绿色 + + + + Deep Bluish Green + 深蓝绿色 + + + + Very Light Bluish Green + 超浅蓝绿色 + + + + Light Bluish Green + 浅蓝绿色 + + + + Moderate Bluish Green + 中蓝绿色 + + + + Dark Bluish Green + 暗蓝绿色 + + + + Very Dark Bluish Green + 超暗蓝绿色 + + + + Vivid Greenish Blue + 鲜绿蓝色 + + + + Brilliant Greenish Blue + 亮绿蓝色 + + + + Strong Greenish Blue + 大绿蓝色 + + + + Deep Greenish Blue + 深绿蓝色 + + + + Very Light Greenish Blue + 超浅绿绿色 + + + + Light Greenish Blue + 浅绿蓝色 + + + + Moderate Greenish Blue + 中绿蓝色 + + + + Dark Greenish Blue + 暗绿蓝色 + + + + Very Dark Greenish Blue + 超暗绿绿色 + + + + Vivid Blue + 鲜蓝色 + + + + Brilliant Blue + 亮蓝色 + + + + Strong Blue + 大蓝色 + + + + Deep Blue + 深绿色 + + + + Very Light Blue + 超浅蓝色 + + + + Light Blue + 浅蓝色 + + + + Moderate Blue + 中蓝色 + + + + Dark Blue + 暗蓝色 + + + + Very Pale Blue + 超淡蓝色 + + + + Pale Blue + 淡蓝色 + + + + Grayish Blue + 灰蓝色 + + + + Dark Grayish Blue + 暗灰蓝色 + + + + Blackish Blue + 黑蓝色 + + + + Bluish White + 蓝白色 + + + + Light Bluish Gray + 浅蓝灰色 + + + + Bluish Gray + 蓝灰色 + + + + Dark Bluish Gray + 暗蓝灰色 + + + + Bluish Black + 蓝黑色 + + + + Vivid Purplish Blue + 鲜紫蓝色 + + + + Brilliant Purplish Blue + 亮紫蓝色 + + + + Strong Purplish Blue + 大紫蓝色 + + + + Deep Purplish Blue + 深紫蓝色 + + + + Very Light Purplish Blue + 超浅紫蓝色 + + + + Light Purplish Blue + 浅紫蓝色 + + + + Moderate Purplish Blue + 中紫蓝色 + + + + Dark Purplish Blue + 暗紫蓝色 + + + + Very Pale Purplish Blue + 超淡紫蓝色 + + + + Pale Purplish Blue + 淡紫蓝色 + + + + Grayish Purplish Blue + 灰紫蓝色 + + + + Vivid Violet + 鲜紫罗兰色 + + + + Brilliant Violet + 亮紫罗兰色 + + + + Strong Violet + 大紫罗兰色 + + + + Deep Violet + 深紫罗兰色 + + + + Very Light Violet + 超浅紫罗兰色 + + + + Light Violet + 浅紫罗兰色 + + + + Moderate Violet + 中紫罗兰色 + + + + Dark Violet + 暗紫罗兰色 + + + + Very Pale Violet + 超淡紫罗兰色 + + + + Pale Violet + 淡紫罗兰色 + + + + Grayish Violet + 灰紫罗兰色 + + + + Vivid Purple + 鲜紫色 + + + + Brilliant Purple + 亮紫色 + + + + Strong Purple + 大紫色 + + + + Deep Purple + 深紫色 + + + + Very Deep Purple + 超深紫色 + + + + Very Light Purple + 超浅紫色 + + + + Light Purple + 浅紫色 + + + + Moderate Purple + 中紫色 + + + + Dark Purple + 暗紫色 + + + + Very Dark Purple + 超暗紫色 + + + + Very Pale Purple + 超淡紫色 + + + + Pale Purple + 淡紫色 + + + + Grayish Purple + 灰紫色 + + + + Dark Grayish Purple + 暗灰紫色 + + + + Blackish Purple + 黑紫色 + + + + Purplish White + 紫白色 + + + + Light Purplish Gray + 浅紫灰色 + + + + Purplish Gray + 紫灰色 + + + + Dark Purplish Gray + 暗紫灰色 + + + + Purplish Black + 紫黑色 + + + + Vivid Reddish Purple + 鲜红紫色 + + + + Strong Reddish Purple + 大红紫色 + + + + Deep Reddish Purple + 深红紫色 + + + + Very Deep Reddish Purple + 超深红紫色 + + + + Light Reddish Purple + 浅红紫色 + + + + Moderate Reddish Purple + 中红紫色 + + + + Dark Reddish Purple + 暗红紫色 + + + + Very Dark Reddish Purple + 超暗红紫色 + + + + Pale Reddish Purple + 淡红紫色 + + + + Grayish Reddish Purple + 灰红紫色 + + + + Brilliant Purplish Pink + 亮紫粉红色 + + + + Strong Purplish Pink + 大紫粉红色 + + + + Deep Purplish Pink + 深紫粉红色 + + + + Light Purplish Pink + 浅紫粉红色 + + + + Moderate Purplish Pink + 中紫粉红色 + + + + Dark Purplish Pink + 暗紫粉红色 + + + + Pale Purplish Pink + 淡紫粉红色 + + + + Grayish Purplish Pink + 灰紫粉红色 + + + + Vivid Purplish Red + 鲜紫红色 + + + + Strong Purplish Red + 大紫红色 + + + + Deep Purplish Red + 深紫红色 + + + + Very Deep Purplish Red + 超深紫红色 + + + + Moderate Purplish Red + 中紫红色 + + + + Dark Purplish Red + 暗紫红色 + + + + Very Dark Purplish Red + 超暗紫红色 + + + + Light Grayish Purplish Red + 浅灰紫红色 + + + + Grayish Purplish Red + 灰紫红色 + + + + White + 白色 + + + + Light Gray + 浅灰色 + + + + Medium Gray + 中灰色 + + + + Dark Gray + 暗灰色 + + + + Black + 黑色 + + + + Could not open file + 不能打开文件 + + + + There was an error processing your file. This usually means that your project has been at least partially corrupted. You can try again with a newer version of Pencil2D, or you can try to use a backup file if you have one. If you contact us through one of our offical channels we may be able to help you. For reporting issues, the best places to reach us are: + 处理文件时发生了错误。这通常是因为你的项目有部分被损坏了。你可以用更新版本的 Pencil2D 来试一下,有备份文件的话也可以试一试。如果你通过官方途径联系我们,我们也许可以帮忙看看。要报告问题,联系我们的最好方式是: + + + + RecentFileMenu + + + Open Recent + 打开最近使用 + + + + Clear + 清除 + + + + ScribbleArea + + + Warning + 警告 + + + + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). + 你正在一个隐藏的层上绘图!请选择其它层 (或者打开该图层)。 + + + + Delete Selection + Undo Step: clear the selection area. + 删除选择区域 + + + + + Clear Image + Undo step text + 清理图像 + + + + There is a gap in your drawing (or maybe you have zoomed too much). + 有间隙在你的图画中 (也可能是你放大太厉害)。 + + + + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). + 对不起!这个有时不行。请再试一次 (稍微缩放一点,点点其他地方...),<br>如果还不行,放大检查路径是不是连接上了)。 + + + + Out of bound. + 超出了边界。 + + + + Could not find a closed path. + 不能找到闭合路径。 + + + + Could not find the root index. + 不能找到根索引。 + + + + %1<br><br>Error: %2 + %1<br><br>错误: %2 + + + + Flood fill error + 填充错误 + + + + ShortcutsPage + + + Form + 表单 + + + + Action: + 动作: + + + + None + + + + + Shortcuts: + 快捷键: + + + + clear + 清理 + + + + Restore Default Shortcuts + 重置默认快捷键 + + + + Shortcut Conflict! + 快捷键冲突! + + + + %1 is already used, overwrite? + %1 已经在用了,覆盖吗? + + + + TimeControls + + + Range + 范围 + + + + Frames per second + 每秒帧数 + + + + Start of playback loop + 回放循环起始点 + + + + End of playback loop + 回放循环结束点 + + + + Playback range + 回放范围 + + + + Play + 播放 + + + + Loop + 循环 + + + + Sound on/off + 声音开/关 + + + + End + 结束 + + + + + Start + 开始 + + + + Stop + 停止 + + + + TimeLine + + + Timeline + 时间轴 + + + + Layers: + 层: + + + + Add Layer + 添加层 + + + + Remove Layer + 删除层 + + + + New Bitmap Layer + 新位图层 + + + + New Vector Layer + 新矢量层 + + + + New Sound Layer + 新声音层 + + + + New Camera Layer + 新相机层 + + + + &Layer + Timeline add-layer menu + 层(&L) + + + + Keys: + 关键帧: + + + + Add Frame + 添加帧 + + + + Remove Frame + 删除帧 + + + + Duplicate Frame + 复制帧 + + + + Onion skin: + 洋葱皮 + + + + Toggle match keyframes + 开关适配关键帧 + + + + Delete Layer + Windows title of Delete current layer pop-up. + 删除层 + + + + Please keep at least one camera layer in project + 请至少保留一个相机层在项目里 + + + + Are you sure you want to delete layer: + 确定要删除层吗: + + + + TimeLineCells + + + Layer Properties + 层属性 + + + + Layer name: + 层名: + + + + Timeline2 + + + Timeline + 时间轴 + + + + Layers + + + + + + ... + ... + + + + TimelinePage + + + Timeline + 时间轴 + + + + Timeline length: + Preferences + 时间轴长度: + + + + Drawing + 绘画 + + + + When drawing on an empty frame: + 在空帧上绘画时: + + + + Create a new (blank) key-frame and start drawing on it. + 创建新(空白)关键帧并在其上绘制。 + + + + Create a new (blank) key-frame + 创建新(空白)关键帧 + + + + Duplicate the previous key-frame and start drawing on the duplicate. + 复制前一关键帧并在该复制品上开始绘制。 + + + + Duplicate the previous key-frame + 复制前一关键帧 + + + + Keep drawing on the previous key-frame + 进行在前一关键帧上绘制 + + + + <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + <html><head/><body><p>(应用到铅笔、橡皮擦、钢笔、折线、颜料桶和笔刷工具上)</p></body></html> + + + + Playback + 回放 + + + + Show onion skin while playing + 播放时显示洋葱皮 + + + + Frame size + 帧的尺寸 + + + + Short scrub + 短指示器 + + + + ToolBoxWidget + + + Tools + Window title of tool box + 工具 + + + + Pencil Tool (%1): Sketch with pencil + 铅笔工具 (%1): 用铅笔打稿 + + + + Select Tool (%1): Select an object + 选择工具 (%1): 选择物件 + + + + Move Tool (%1): Move an object + 移动工具 (%1): 移动物件 + + + + Hand Tool (%1): Move the canvas + 抓手工具 (%1): 移动画布 + + + + Pen Tool (%1): Sketch with pen + 钢笔工具 (%1): 用钢笔起稿 + + + + Eraser Tool (%1): Erase + 橡皮擦工具 (%1): 擦除 + + + + Polyline Tool (%1): Create line/curves + 折线工具 (%1): 创建线段/曲线 + + + + Paint Bucket Tool (%1): Fill selected area with a color + 颜料桶工具 (%1):填充颜色到选择区 + + + + Brush Tool (%1): Paint smooth stroke with a brush + 笔刷工具 (%1): 用笔刷刷出平滑笔划 + + + + Eyedropper Tool (%1): Set color from the stage<br>[ALT] for instant access + 吸管工具 (%1): 从绘图区<br>[ALT]拾取颜色 + + + + Clear Frame (%1): Erases content of selected frame + 清除帧 (%1): 擦除所选帧的内容 + + + + Smudge Tool (%1):<br>Edit polyline/curves<br>Liquify bitmap pixels<br> (%1)+[Alt]: Smooth + 涂抹工具 (%1):<br>编辑折线/曲线<br>液化位图像素<br> (%1)+[Alt]: 平滑 + + + + Pencil Tool (%1) + 铅笔工具 (%1) + + + + Select Tool (%1) + 选择 (%1) + + + + Move Tool (%1) + 移动 (%1) + + + + Hand Tool (%1) + 抓手工具 (%1) + + + + Pen Tool (%1) + 钢笔工具 (%1) + + + + Eraser Tool (%1) + 橡皮擦工具 (%1) + + + + Polyline Tool (%1) + 折线工具 (%1) + + + + Paint Bucket Tool (%1) + 颜料桶工具 (%1) + + + + Brush Tool (%1) + 笔刷工具 (%1) + + + + Eyedropper Tool (%1) + 吸管工具 (%1) + + + + Clear Tool (%1) + 清除工具 (%1) + + + + Smudge Tool (%1) + 涂抹工具 (%1) + + + + ToolOptionWidget + + + Brush + 笔刷 + + + + Feather + 羽化 + + + + Color Tolerance + 允许色差 + + + + Options + Window title of tool option panel like pen width, feather etc.. + 选项 + + + + Stroke Thickness + 描边粗细 + + + + Width + 宽度 + + + + ToolOptions + + + Form + 表单 + + + + Set Pen Width <br><b>[SHIFT]+drag</b><br>for quick adjustment + 设置钢笔宽度 <br><b>[SHIFT]+拖动</b><br>以快调整 + + + + Set Pen Feather <br><b>[CTRL]+drag</b><br>for quick adjustment + 设置钢笔羽化 <br><b>[CTRL]+拖动</b><br>以快调整 + + + + Enable or disable feathering + 启用或者停用羽化 + + + + Use Feather + 使用羽化 + + + + Contour will be filled + 轮廓将被填充 + + + + Fill Contour + 填充轮廓 + + + + The extend to which the color variation will be treated as being equal + 颜色变化的扩展将被视为相等 + + + + Bezier + 贝塞尔 + + + + Pressure + Brush + 压力 + + + + Anti-Aliasing + Brush AA + 抗锯齿 + + + + Merge + Vector line merge + 矢量线合并 + + + + None + Stabilizer option + + + + + Simple + Stabilizer option + 简单 + + + + Strong + Stabilizer option + 强烈 + + + + Make invisible + 使不看见 + + + + Invisible + 不看见 + + + + Preserve Alpha + 保留透明度 + + + + Alpha + 透明度 + + + + Merge vector lines when they are close together + 合并彼此靠近的矢量线 + + + + Stabilizer + 稳定器 + + + + ToolsPage + + + Onion skin + 洋葱皮 + + + + Maximum onion opacity % + 最大不透明度 % + + + + Minimum onion opacity % + 最小不透明度 % + + + + Number of previous onion frames shown + 显示前面帧数 + + + + Number of next onion frames shown + 显示后面帧数 + + + + Brush Tools + 笔刷工具 + + + + Use Quick Sizing + 使用快速尺寸 + + + \ No newline at end of file diff --git a/translations/pencil_zh_TW.qm b/translations/pencil_zh_TW.qm index 67ce9e0a7e24bcbee01dbcb7ab2c94a5077a0d45..f936d31277a49c9cb60142144bed02d3da0fc7f6 100644 GIT binary patch delta 3167 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 L;q_1B621NpJTqBi delta 3977 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 diff --git a/translations/pencil_zh_TW.ts b/translations/pencil_zh_TW.ts index 2edfbc725..c47d99325 100644 --- a/translations/pencil_zh_TW.ts +++ b/translations/pencil_zh_TW.ts @@ -13,13 +13,13 @@ - + Version: %1 Version Number in About Dialog 版本 %1 - + Copy to clipboard Copy system info from About Dialog 複製到剪貼簿 @@ -55,30 +55,30 @@ 音效層 - + Exporting movie 正在輸出影片 - + Finished. Open movie now? When movie export done. 輸出完成。要打開影片嗎? - - - - + + + + Layer Properties 圖層屬性 - - - - + + + + Layer name: 圖層名稱: @@ -88,58 +88,63 @@ 目前畫格已經有一個音效了! 請選擇另一個畫格或圖層 - + + Finished. Open file location? + + + + Exporting image sequence... 輸出連續圖片中... - + Abort 關於 - + Warning 警告 - + Unable to export image. 無法匯出圖片 - + Bitmap Layer 點陣圖層 - + Vector Layer 向量圖層 - + Camera Layer 相機層 - + Sound Layer 音效層 - + Delete Layer Windows title of Delete current layer pop-up. 刪除圖層 - + Are you sure you want to delete layer: 確定要刪除圖層嗎 - + Please keep at least one camera layer in project text when failed to delete camera layer 請至少保留一個相機層 @@ -148,57 +153,57 @@ BaseTool - + Pencil 鉛筆 - + Eraser 橡皮擦 - + Select 全選 - + Move 移動 - + Hand - + Smudge 塗抹 - + Pen 鋼筆 - + Polyline 多邊形工具 - + Bucket 油漆桶 - + Eyedropper 吸管 - + Brush 刷子 @@ -224,69 +229,55 @@ ColorBox - - Color Wheel - Color Wheel's window title - 色輪 + + Color Box + Color Box window title + ColorInspector - + HSV HSV - + RGB RGB - - - Red - - - - - - Green - - - - - - Blue - + + R + - - - - Alpha - Alpha + + A + - - Hue - 色相 + + G + - - Saturation - 飽和度 + + B + - - Value - 明度 + + Color Inspector + Window title of color inspector + ColorPalette - + Color Palette Window title of color palette. 調色盤 @@ -302,57 +293,57 @@ 刪除顏色 - - ... - ... + + Native color dialog window + - + List Mode 列表模式 - + Show palette as a list 列表方式顯示調色盤 - + Grid Mode 色塊模式 - + Show palette as icons 方格方式顯示調色盤 - + Small swatch 小色塊 - + Sets swatch size to: 16x16px 設定色塊尺寸: 16x16 - + Medium Swatch 中色塊 - + Sets swatch size to: 26x26px 設定色塊尺寸: 26x26 - + Large Swatch 大色塊 - + Sets swatch size to: 36x36px 設定色塊尺寸: 36x36 @@ -360,11 +351,60 @@ ColorPaletteWidget - - + + Add + + + + + Replace + + + + + Remove + + + + + Colour name 顏色名稱 + + + The color(s) you are about to delete are currently being used by one or multiple strokes. + + + + + Cancel + + + + + Delete + + + + + Palette Restriction + + + + + The palette requires at least one swatch to remain functional + + + + + ColorWheel + + + Color Wheel + Color Wheel's window title + + DisplayOption @@ -446,19 +486,19 @@ Editor - - + + Paste 貼上 - + Remove frame 刪除關鍵格 - - + + Import Image 匯入圖像 @@ -484,12 +524,12 @@ ExportImageDialog - + Export image sequence 匯出連續圖像 - + Export image 匯出圖片 @@ -531,11 +571,51 @@ Transparency 透明背景 + + + Range + + + + + The last frame you want to include in the exported movie + + + + + End Frame + + + + + The first frame you want to include in the exported movie + + + + + Start Frame + + + + + <html><head/><body><p>End frame is set to last paintable keyframe (Useful when you only want to export to the last animated frame)</p></body></html> + + + + + To the end of sound clips + + ExportMovieDialog - + + Export Animated GIF + + + + Export Movie 匯出影片 @@ -627,67 +707,83 @@ + Import Animated GIF + + + + Import movie 匯入影片 - + Import sound 匯入音效 - + Import palette 匯入調色盤 - + Save animation 儲存動畫 - + Export image 匯出圖像 - + Export image sequence 匯出連續圖片 - + + Export Animated GIF + + + + Export movie 匯出影片 - + Export sound 匯出音效 - + Export palette 匯出調色盤 - + + + Animated GIF (*.gif) + + + + Sounds (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) 音效 (*.wav *.mp3);;WAV (*.wav);;MP3 (*.mp3) - - - Palette (*.xml) - 調色盤 (*.xml) + + + Pencil2D Palette (*.xml);; Gimp Palette (*.gpl) + - - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) - MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; GIF (*.gif);; APNG (*.apng) + + MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng) + - + MyAnimation.pclx 我的動畫.pclx @@ -695,52 +791,72 @@ FileManager - - - + + + Could not open file + + + + + The file does not exist, so we are unable to open it. Please check to make sure the path is correct and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + Invalid Save Path 無效的路徑 - + The path ("%1") points to a directory. 該路徑是一個目錄 ("%1") - + The directory ("%1") does not exist. 目錄不存在 ("%1") - + The path ("%1") is not writable. 沒有寫入權限 ("%1") - - + + Cannot Create Data Directory 無法建立資料目錄 - + Failed to create directory "%1". Please make sure you have sufficient permissions. 無法創建目錄 "%1",請確定您有足夠權限。 - + "%1" is a file. Please delete the file and try again. - - + + Miniz Error + + + + Internal Error 內部錯誤 - - + + An internal error occurred. Your file may not be saved successfully. 發生內部錯誤,您的檔案可能沒有儲存成功。 @@ -818,87 +934,97 @@ 格線 - + Czech 捷克語 - + Danish 丹麥語 - + English 英語 - + German 德語 - + + Estonian + + + + Spanish 西班牙語 - + French 法語 - + Hebrew 希伯來語 - + Hungarian 匈牙利語 - + Indonesian 印尼語 - + Italian 義大利語 - + Japanese 日語 - + + Polish + + + + Portuguese - Portugal - + Portuguese - Brazil 葡萄牙語 - 巴西 - + Russian 俄語 - + Slovenian - + Vietnamese - + Chinese - Taiwan 中文 - 台灣 @@ -943,12 +1069,12 @@ 高解析度繪圖板 - + Restart Required 需要重新啟動 - + The language change will take effect after a restart of Pencil2D 會在下次打開 Pencil2D 時改變顯示語言 @@ -974,7 +1100,12 @@ ImportImageSeqDialog - + + Import Animated GIF + + + + Import image sequence 匯入連續圖像 @@ -998,7 +1129,7 @@ LayerBitmap - + Bitmap Layer 點陣圖層 @@ -1014,7 +1145,7 @@ LayerSound - + Sound Layer 音效層 @@ -1045,686 +1176,745 @@ 匯入 - + Export 匯出 - + Edit 編輯 - + Selection 選擇 - + View 檢視 - + Onion Skin 描圖紙 - + Animation 動畫 - - + + Tools 工具 - + Layer 圖層 - - + + Help 幫助 - + Windows 視窗 - + New 新增 - + Open 開啟 - + Save 儲存 - + Save As .. 另存為.. - + Exit 離開 - - + + Image Sequence... 連續圖像... - - + + Image... 圖像... - - + + Movie... 影片... - - + + Palette... 調色盤... - + Sound... 音效... - + Undo 復原 - + Redo 重做 - + Cut 剪下 - + Copy 複製 - + Paste 貼上 - + Crop 裁剪 - + Crop To Selection 裁剪至選擇區域 - + Select All 全選 - + Deselect All 取消全選 - - + + Clear Frame 清除畫格 - + Preferences 偏好設定 - + Reset Windows 重設視窗 - + Zoom In 放大 - + Zoom Out 縮小 - + Rotate Clockwise 順時針旋轉 - + Rotate AntiClosewise 逆時針旋轉 - + Reset Zoom/Rotate 重設縮放/旋轉 - + Horizontal Flip 水平翻轉 - + Vertical Flip 垂直翻轉 - + Preview 預覽 - + Grid 格線 - + Previous 前一個 - + Show previous onion skin 顯示先前描圖紙 - + Next 下一個 - + Show next onion skin 顯示後續描圖紙 - - + + Play 播放 - + Loop 循環 - + Next Frame 下一個畫格 - + Previous Frame 前一個畫格 - + Extend Frame 延伸畫格 - + Add Frame 加入畫格 - + Duplicate Frame 重製畫格 - + Remove Frame 移除畫格 - + Move 移動 - + Select 選擇 - + Brush 筆刷 - + Polyline 折線 - + Smudge 塗抹 - + Pen 鋼筆 - + Hand - + Pencil 鉛筆 - + Bucket 顏料桶 - + Eyedropper 取色器 - + Eraser 橡皮擦 - + New Bitmap Layer 新增點陣圖層 - + New Vector Layer 新增向量圖層 - + New Sound Layer 新增音效層 - + New Camera Layer 新增攝影機層 - + Delete Current Layer 刪除目前圖層 - + About 關於 - - + + Reset to default 重設為預設值 - + MultiLayer Onion Skin 多重圖層描圖紙 - + Range 範圍 - + Pencil2D Website Pencil2D 網站 - + Report a Bug 回報 BUG - + Quick Reference Guide - + F1 - - + + + Animated GIF... + + + + + Next KeyFrame 下一個關鍵影格 - - + + Previous KeyFrame 前一個關鍵影格 - + Timeline 時間軸 - + Options 選項 - + Color Wheel 色輪 - + Color Palette 顏色調色盤 - + Display Options 顯示選項 - + Flip X X翻轉 - + Flip Y Y翻轉 - + Move Frame Forward 影格前移 - + Move Frame Backward 影格後移 - + color palette:<br>use <b>(C)</b><br>toggle at cursor - + + Color inspector + + + + Lock Windows 鎖定視窗 - + Open Recent 最近開啟的 - + You have successfully cleared the list 成功清除清單 - - - - - + + + + + Could not open file + + + + + The file you have selected is a directory, so we are unable to open it. If you are are trying to open a project that uses the old structure, please open the file ending with .pcl, not the data folder. + + + + + The file you have selected does not exist, so we are unable to open it. Please check to make sure that you've entered the correct path and that the file is accessible and try again. + + + + + This program does not have permission to read the file you have selected. Please check that you have read permissions for this file and try again. + + + + + + + + Warning 警告 - - - Pencil cannot read this file. If you want to import images, use the command import. - Pencil 無法讀取這個檔案。如果您想要匯入影像,請使用指令匯入。 + + This program does not currently have permission to write to the file you have selected. Please make sure you have write permission for this file before attempting to save it. Alternatively, you can use the Save As... menu option to save to a writable location. + - + Opening document... 開啟文件... - - - + + + + Abort 中止 - + + An unknown error occurred while trying to load the file and we are not able to load your file. + + + + Saving document... 儲存文件... - + <br><br>An error has occurred and your file may not have saved successfully.If you believe that this error is an issue with Pencil2D, please create a new issue at:<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>Please be sure to include the following details in your issue: <br><br>發現錯誤,你的檔案可能並未成功保存。如果你看見這個訊息,請到<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a>協助回報錯誤<br>並附上以下錯誤細節訊息: - + This animation has been modified. Do you want to save your changes? 動畫已經修改。你想要儲存檔案嗎? - + The animation is not saved yet. Do you want to save now? 您的動畫還沒儲存。要現在儲存嗎? - + Never ask again AutoSave reminder button 不要再問我 - + Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps. 無法匯入圖片。<br><b>提示</b> 使用點陣圖層來匯入點陣圖 - + Importing image sequence... - + + was unable to import - - + + Importing Animated GIF... + + + + + Undo Menu item text - + Redo Menu item text - + Stop 停止 + + MoveTool + + + Layer switch + Windows title of layer switch pop-up. + + + + + You are about to switch layer, do you want to apply the transformation? + + + Object - + Black 黑色 - + Red 紅色 - + Dark Red 深紅色 - + Orange 橙色 - + Dark Orange 深橙色 - + Yellow 黃色 - + Dark Yellow 深黃色 - + Green 綠色 - + Dark Green 深綠色 - + Cyan 青色 - + Dark Cyan 深青色 - + Blue 藍色 - + Dark Blue 深藍色 - + White 白色 - + Very Light Grey 很淺灰色 - + Light Grey 淺灰色 - + Grey 灰色 - + Dark Grey 深灰色 - + Light Skin 淺膚色 - + Light Skin - shade - + Skin 膚色 - + Skin - shade - + Dark Skin 深膚色 - + Dark Skin - shade @@ -1732,153 +1922,153 @@ PencilApplication - + Pencil2D is an animation/drawing software for Mac OS X, Windows, and Linux. It lets you create traditional hand-drawn animation (cartoon) using both bitmap and vector graphics. Pencil2D 是一款2D動畫軟體,可用點陣圖與向量圖兩種格式來製作傳統手繪動畫。Pencil2D 能在Windows, Mac OS 與 Linux下運行。 - + Path to the input pencil file. 輸入的 Pencil2D 檔案路徑 - - + + Render the file to <output_path> - - + + output_path - + Name of the camera layer to use 使用的相機層名稱 - + layer_name - + Width of the output frames - - + + integer - + Height of the output frames - + The first frame you want to include in the exported movie - - + + frame - + The last frame you want to include in the exported movie. Can also be last or last-sound to automatically use the last frame containing animation or sound, respectively - + Render transparency when possible - + Warning: width value %1 is not an integer, ignoring. - + Warning: height value %1 is not an integer, ignoring. - + Warning: start value %1 is not an integer, ignoring. - + Warning: start value must be at least 1, ignoring. - + Warning: end value %1 is not an integer, last or last-sound, ignoring. - + Warning: end value %1 is smaller than start value %2, ignoring. - + Error: No input file specified. - + Error: the input file at '%1' does not exist Command line error - + Error: the input path '%1' is not a file Command line error - + Warning: the specified camera layer %1 was not found, ignoring. - + Warning: Output format is not specified or unsupported. Using PNG. Command line warning - + Warning: Transparency is not currently supported in movie files Command line warning - + Exporting movie... Command line task progress - - + + Done. Command line task done - + Exporting image sequence... Command line task progress @@ -1920,12 +2110,12 @@ QApplication - + Checking environment... - + Done @@ -1933,42 +2123,47 @@ QObject - + AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) AVI (*.avi);;MPEG(*.mpg);;MOV(*.mov);;MP4(*.mp4);;SWF(*.swf);;FLV(*.flv);;WMV(*.wmv) - - Images (*.png *.jpg *.jpeg *.bmp *.gif);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp);;GIF(*.gif) + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp) - + + Images (*.png *.jpg *.jpeg *.bmp);;PNG (*.png);;JPG(*.jpg *.jpeg);;BMP(*.bmp); + + + + Everything ok. 正常 - + Ooops, Something went wrong. 歐,好像出錯了! - + File doesn't exist. 檔案不存在 - + Cannot open file. 無法開啟檔案 - + The file is not a valid xml document. 無效的 XML 檔案 - + The file is not valid pencil document. 無效的 Pencil 檔案格式 @@ -3317,6 +3512,16 @@ Black + + + Could not open file + + + + + There was an error processing your file. This usually means that your project has been at least partially corrupted. You can try again with a newer version of Pencil2D, or you can try to use a backup file if you have one. If you contact us through one of our offical channels we may be able to help you. For reporting issues, the best places to reach us are: + + RecentFileMenu @@ -3334,60 +3539,60 @@ ScribbleArea - + Warning 警告 - + You are drawing on a hidden layer! Please select another layer (or make the current layer visible). 您在隱藏的圖層上繪製!請選擇其他圖層(或使目前圖層可看見)。 - + Delete Selection Undo Step: clear the selection area. 刪除選擇 - - + + Clear Image Undo step text 清除 - + There is a gap in your drawing (or maybe you have zoomed too much). - + Sorry! This doesn't always work.Please try again (zoom a bit, click at another location... )<br>if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.). - + Out of bound. 超出界線 - + Could not find a closed path. - + Could not find the root index. - + %1<br><br>Error: %2 - + Flood fill error 填滿功能錯誤 @@ -3484,12 +3689,12 @@ - + Start 開始 - + Stop 停止 @@ -3573,18 +3778,18 @@ 切換描圖紙畫格模式 - + Delete Layer Windows title of Delete current layer pop-up. 刪除圖層 - + Please keep at least one camera layer in project 請至少保留一個相機層 - + Are you sure you want to delete layer: 你確定要刪除圖層嗎: @@ -3592,12 +3797,12 @@ TimeLineCells - + Layer Properties 圖層屬性 - + Layer name: 圖層名稱: @@ -3674,6 +3879,16 @@ <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + + Playback + + + + + Show onion skin while playing + + Frame size diff --git a/translations/translations.qrc b/translations/translations.qrc index df02732a7..5572bbe54 100644 --- a/translations/translations.qrc +++ b/translations/translations.qrc @@ -17,6 +17,7 @@ pencil_ru.qm pencil_sl.qm pencil_vi.qm + pencil_zh_CN.qm pencil_zh_TW.qm From fa3ca0c10ad0af01679a91d9541586bff0cecce5 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Fri, 27 Jul 2018 00:47:10 -0600 Subject: [PATCH 142/184] Improve color palette selection behavior This includes: - Showing the proper icon color when selected (Fixes #1024) - Adding a border around the selected color, this is particularly useful for grid mode which has no other way to display the selection - Refactored the resizing code so that going to grid mode from list mode does not result in unexpected icon spacing --- app/src/colorpalettewidget.cpp | 91 +++++++++++++++++++++++----------- 1 file changed, 61 insertions(+), 30 deletions(-) diff --git a/app/src/colorpalettewidget.cpp b/app/src/colorpalettewidget.cpp index 90705b12e..267d4be22 100644 --- a/app/src/colorpalettewidget.cpp +++ b/app/src/colorpalettewidget.cpp @@ -185,6 +185,13 @@ void ColorPaletteWidget::refreshColorList() swatchPainter.drawTiledPixmap(0, 0, mIconSize.width(), mIconSize.height(), QPixmap(":/background/checkerboard.png")); swatchPainter.end(); QPixmap colourSwatch; + QPen borderShadow(QColor(0, 0, 0, 200), 1, Qt::DotLine, Qt::FlatCap, Qt::MiterJoin); + QVector dashPattern; + dashPattern << 4 << 4; + borderShadow.setDashPattern(dashPattern); + QPen borderHighlight(borderShadow); + borderHighlight.setColor(QColor(255, 255, 255, 200)); + borderHighlight.setDashOffset(4); int colourCount = editor()->object()->getColourCount(); @@ -204,12 +211,24 @@ void ColorPaletteWidget::refreshColorList() colourSwatch = originalColourSwatch; swatchPainter.begin(&colourSwatch); swatchPainter.fillRect(0, 0, mIconSize.width(), mIconSize.height(), colourRef.colour); + + QIcon swatchIcon; + swatchIcon.addPixmap(colourSwatch, QIcon::Normal); + + // Draw selection border + swatchPainter.setPen(borderHighlight); + swatchPainter.drawRect(0, 0, mIconSize.width() - 1, mIconSize.height() - 1); + swatchPainter.setPen(borderShadow); + swatchPainter.drawRect(0, 0, mIconSize.width() - 1, mIconSize.height() - 1); + swatchIcon.addPixmap(colourSwatch, QIcon::Selected); + + colourItem->setIcon(swatchIcon); swatchPainter.end(); - colourItem->setIcon(colourSwatch); colourItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); ui->colorListWidget->addItem(colourItem); } + updateGridUI(); update(); } @@ -316,7 +335,8 @@ void ColorPaletteWidget::setGridMode() ui->colorListWidget->setViewMode(QListView::IconMode); ui->colorListWidget->setMovement(QListView::Static); // TODO: update swatch index on move ui->colorListWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); - ui->colorListWidget->setGridSize(mIconSize); + ui->colorListWidget->setGridSize(QSize(mIconSize.width() + 1, mIconSize.height() + 1)); + updateUI(); QSettings settings(PENCIL2D, PENCIL2D); @@ -325,28 +345,7 @@ void ColorPaletteWidget::setGridMode() void ColorPaletteWidget::resizeEvent(QResizeEvent* event) { - if (ui->colorListWidget->viewMode() == QListView::IconMode) - { - // Find the value to divide with - for (int i = 1; i < 75; i++) - { - int size = (ui->colorListWidget->width() - 18) / i; // subtract scrollbar width - if (size >= mIconSize.width() && size <= mIconSize.width() + 8) - { - stepper = size; - } - } - QSize tempSize = QSize(stepper, mIconSize.height()); - - ui->colorListWidget->setIconSize(QSize(tempSize.width(), mIconSize.height())); - ui->colorListWidget->setGridSize(QSize(tempSize.width(), mIconSize.height())); - mIconSize.setWidth(mIconSize.width()); - } - else - { - ui->colorListWidget->setIconSize(mIconSize); - ui->colorListWidget->setGridSize(QSize(-1, -1)); - } + updateUI(); QWidget::resizeEvent(event); } @@ -388,12 +387,26 @@ void ColorPaletteWidget::setSwatchSizeLarge() void ColorPaletteWidget::updateGridUI() { - if (ui->colorListWidget->viewMode() == QListView::IconMode) - ui->colorListWidget->setGridSize(mIconSize); - else - ui->colorListWidget->setGridSize(QSize(-1, -1)); + if (ui->colorListWidget->viewMode() == QListView::IconMode) { + // Find the value to divide with + for (int i = 1; i < 75; i++) + { + int size = (ui->colorListWidget->width() - 18) / i; // subtract scrollbar width + if (size >= mIconSize.width() && size <= mIconSize.width() + 8) + { + stepper = size; + } + } + QSize tempSize = QSize(stepper, mIconSize.height()); - ui->colorListWidget->setIconSize(mIconSize); + ui->colorListWidget->setIconSize(QSize(tempSize.width(), mIconSize.height())); + ui->colorListWidget->setGridSize(QSize(tempSize.width(), mIconSize.height() + 2)); + mIconSize.setWidth(mIconSize.width()); + } + else { + ui->colorListWidget->setIconSize(mIconSize); + ui->colorListWidget->setGridSize(QSize(-1, -1)); + } } QString ColorPaletteWidget::getDefaultColorName(QColor c) @@ -558,7 +571,25 @@ void ColorPaletteWidget::updateItemColor(int itemIndex, QColor newColor) swatchPainter.drawTiledPixmap(0, 0, mIconSize.width(), mIconSize.height(), QPixmap(":/background/checkerboard.png")); swatchPainter.fillRect(0, 0, mIconSize.width(), mIconSize.height(), newColor); - ui->colorListWidget->item(itemIndex)->setIcon(colourSwatch); + QPen borderShadow(QColor(0, 0, 0, 200), 1, Qt::DotLine, Qt::FlatCap, Qt::MiterJoin); + QVector dashPattern; + dashPattern << 4 << 4; + borderShadow.setDashPattern(dashPattern); + QPen borderHighlight(borderShadow); + borderHighlight.setColor(QColor(255, 255, 255, 200)); + borderHighlight.setDashOffset(4); + + QIcon swatchIcon; + swatchIcon.addPixmap(colourSwatch, QIcon::Normal); + + // Draw selection border + swatchPainter.setPen(borderHighlight); + swatchPainter.drawRect(0, 0, mIconSize.width() - 1, mIconSize.height() - 1); + swatchPainter.setPen(borderShadow); + swatchPainter.drawRect(0, 0, mIconSize.width() - 1, mIconSize.height() - 1); + swatchIcon.addPixmap(colourSwatch, QIcon::Selected); + + ui->colorListWidget->item(itemIndex)->setIcon(swatchIcon); // Make sure to update grid in grid mode if (ui->colorListWidget->viewMode() == QListView::IconMode) From 4a6cc4b44e16e017ca4b959cd5dde703d4ac29e9 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Sat, 28 Jul 2018 23:57:00 -0600 Subject: [PATCH 143/184] Remove selection border for list mode palette --- app/src/colorpalettewidget.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/app/src/colorpalettewidget.cpp b/app/src/colorpalettewidget.cpp index 267d4be22..60dd271eb 100644 --- a/app/src/colorpalettewidget.cpp +++ b/app/src/colorpalettewidget.cpp @@ -216,10 +216,12 @@ void ColorPaletteWidget::refreshColorList() swatchIcon.addPixmap(colourSwatch, QIcon::Normal); // Draw selection border - swatchPainter.setPen(borderHighlight); - swatchPainter.drawRect(0, 0, mIconSize.width() - 1, mIconSize.height() - 1); - swatchPainter.setPen(borderShadow); - swatchPainter.drawRect(0, 0, mIconSize.width() - 1, mIconSize.height() - 1); + if(ui->colorListWidget->viewMode() == QListView::IconMode) { + swatchPainter.setPen(borderHighlight); + swatchPainter.drawRect(0, 0, mIconSize.width() - 1, mIconSize.height() - 1); + swatchPainter.setPen(borderShadow); + swatchPainter.drawRect(0, 0, mIconSize.width() - 1, mIconSize.height() - 1); + } swatchIcon.addPixmap(colourSwatch, QIcon::Selected); colourItem->setIcon(swatchIcon); @@ -582,11 +584,13 @@ void ColorPaletteWidget::updateItemColor(int itemIndex, QColor newColor) QIcon swatchIcon; swatchIcon.addPixmap(colourSwatch, QIcon::Normal); - // Draw selection border - swatchPainter.setPen(borderHighlight); - swatchPainter.drawRect(0, 0, mIconSize.width() - 1, mIconSize.height() - 1); - swatchPainter.setPen(borderShadow); - swatchPainter.drawRect(0, 0, mIconSize.width() - 1, mIconSize.height() - 1); + if(ui->colorListWidget->viewMode() == QListView::IconMode) { + // Draw selection border + swatchPainter.setPen(borderHighlight); + swatchPainter.drawRect(0, 0, mIconSize.width() - 1, mIconSize.height() - 1); + swatchPainter.setPen(borderShadow); + swatchPainter.drawRect(0, 0, mIconSize.width() - 1, mIconSize.height() - 1); + } swatchIcon.addPixmap(colourSwatch, QIcon::Selected); ui->colorListWidget->item(itemIndex)->setIcon(swatchIcon); From 7aabf458af8045c9ca43e1ffd4f47848c29b075f Mon Sep 17 00:00:00 2001 From: eszlari Date: Fri, 3 Aug 2018 21:44:31 +0200 Subject: [PATCH 144/184] pencil2d.desktop: fix MimeType --- app/data/pencil2d.desktop | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/data/pencil2d.desktop b/app/data/pencil2d.desktop index 1a6d6f3e9..87d41cd34 100644 --- a/app/data/pencil2d.desktop +++ b/app/data/pencil2d.desktop @@ -6,7 +6,7 @@ GenericName=Animation Software Comment=Create traditional hand-drawn animation using both bitmap and vector graphics Icon=pencil2d Exec=pencil2d %f -MimeType=application/x-pencil-pcl;application/x-pencil-pclx; +MimeType=application/x-pencil2d-pcl;application/x-pencil2d-pclx;application/x-pencil2d-palette; Categories=Graphics;2DGraphics;VectorGraphics;RasterGraphics;Qt;AudioVideo;Video; Keywords=picture;drawing;vector;bitmap;cartoon; From ae2d40272492b75d564f6a7e5b8a73a030320af2 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Sat, 4 Aug 2018 23:14:00 +1000 Subject: [PATCH 145/184] Fix: timeline didn't extend to the correct length when opening a long project - in the previous implementation, timeline length always grows 1.5 times longer based on the current length. But sometimes the timeline length must grow more. - A example, current length 240 frames. Load a project 1000 frames. Timeline extends to 240 * 1.5 = 360 frames, which is far from 1000 frames. --- core_lib/src/interface/timeline.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/core_lib/src/interface/timeline.cpp b/core_lib/src/interface/timeline.cpp index 6954e9c0d..33f7f26fd 100644 --- a/core_lib/src/interface/timeline.cpp +++ b/core_lib/src/interface/timeline.cpp @@ -241,18 +241,15 @@ void TimeLine::setLength(int frame) } /** Extends the tineline frame length if necessary - * - * If the new animation length is more than 75% of the timeline - * frame length, then double the timeline frame length, otherwise - * do nothing. * * @param[in] frame The new animation length */ void TimeLine::extendLength(int frame) { - int frameLength = mTracks->getFrameLength(); - if(frame > frameLength * 0.75) { - mTracks->setFrameLength(frameLength * 1.5); + int currentLength = mTracks->getFrameLength(); + if(frame > currentLength - 50) + { + mTracks->setFrameLength(frame + 100); updateLength(); } } From 8e003ffea7490d3d9d946ae47835d48d86989e11 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Sun, 5 Aug 2018 09:40:09 +1000 Subject: [PATCH 146/184] Bring the exponential growing rule back --- core_lib/src/interface/timeline.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core_lib/src/interface/timeline.cpp b/core_lib/src/interface/timeline.cpp index 33f7f26fd..7ac3e785d 100644 --- a/core_lib/src/interface/timeline.cpp +++ b/core_lib/src/interface/timeline.cpp @@ -240,16 +240,17 @@ void TimeLine::setLength(int frame) updateLength(); } -/** Extends the tineline frame length if necessary +/** Extends the timeline frame length if necessary * * @param[in] frame The new animation length */ void TimeLine::extendLength(int frame) { int currentLength = mTracks->getFrameLength(); - if(frame > currentLength - 50) + if(frame > (currentLength * 0.75)) { - mTracks->setFrameLength(frame + 100); + int newLength = std::max(frame, currentLength) * 1.5; + mTracks->setFrameLength(newLength); updateLength(); } } From 5d5ce956b11a907c15a43bf63135b55cc53559c3 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Sat, 4 Aug 2018 22:28:27 +1000 Subject: [PATCH 147/184] Fix the high memory usage when exporting a movie --- core_lib/src/interface/editor.cpp | 22 +--------------------- core_lib/src/interface/editor.h | 4 ---- core_lib/src/movieexporter.cpp | 2 -- core_lib/src/structure/object.cpp | 22 ++++++++++++++++++++++ core_lib/src/structure/object.h | 3 +++ 5 files changed, 26 insertions(+), 27 deletions(-) diff --git a/core_lib/src/interface/editor.cpp b/core_lib/src/interface/editor.cpp index 9e6fb785a..6d7b2c2df 100644 --- a/core_lib/src/interface/editor.cpp +++ b/core_lib/src/interface/editor.cpp @@ -65,15 +65,12 @@ Editor::Editor(QObject* parent) : QObject(parent) clipboardBitmapOk = false; clipboardVectorOk = false; clipboardSoundClipOk = false; - - mActiveFramePool.reset(new ActiveFramePool(200)); } Editor::~Editor() { // a lot more probably needs to be cleaned here... clearUndoStack(); - mActiveFramePool->clear(); } bool Editor::init() @@ -484,21 +481,6 @@ void Editor::updateAutoSaveCounter() } } -void Editor::updateActiveFrames(int frame) -{ - int beginFrame = std::max(frame - 3, 1); - int endFrame = frame + 4; - for (int i = 0; i < mObject->getLayerCount(); ++i) - { - Layer* layer = mObject->getLayer(i); - for (int k = beginFrame; k < endFrame; ++k) - { - KeyFrame* key = layer->getKeyFrameAt(k); - mActiveFramePool->put(key); - } - } -} - void Editor::cut() { copy(); @@ -632,13 +614,11 @@ Status Editor::setObject(Object* newObject) mObject.reset(newObject); - for (BaseManager* m : mAllManagers) { m->load(mObject.get()); } - mActiveFramePool->clear(); g_clipboardVectorImage.setObject(newObject); updateObject(); @@ -896,7 +876,7 @@ void Editor::scrubTo(int frame) emit updateTimeLine(); // needs to update the timeline to update onion skin positions } - updateActiveFrames(frame); + mObject->updateActiveFrames(frame); } void Editor::scrubForward() diff --git a/core_lib/src/interface/editor.h b/core_lib/src/interface/editor.h index 6c3f634fb..7269e5794 100644 --- a/core_lib/src/interface/editor.h +++ b/core_lib/src/interface/editor.h @@ -205,10 +205,6 @@ class Editor : public QObject bool clipboardBitmapOk = true; bool clipboardVectorOk = true; bool clipboardSoundClipOk = true; - - // Memory management - void updateActiveFrames(int frame); - std::unique_ptr mActiveFramePool; }; #endif diff --git a/core_lib/src/movieexporter.cpp b/core_lib/src/movieexporter.cpp index a2bcc4977..d6def65d1 100644 --- a/core_lib/src/movieexporter.cpp +++ b/core_lib/src/movieexporter.cpp @@ -173,8 +173,6 @@ Status MovieExporter::run(const Object* obj, { #ifdef _WIN32 qCritical() << "Please place ffmpeg.exe in " << ffmpegPath << " directory"; -#elif __APPLE__ - qCritical() << "Please place ffmpeg in " << ffmpegPath << " directory"; #else qCritical() << "Please place ffmpeg in " << ffmpegPath << " directory"; #endif diff --git a/core_lib/src/structure/object.cpp b/core_lib/src/structure/object.cpp index c54d2e629..d28eb30e7 100644 --- a/core_lib/src/structure/object.cpp +++ b/core_lib/src/structure/object.cpp @@ -32,14 +32,19 @@ GNU General Public License for more details. #include "bitmapimage.h" #include "vectorimage.h" #include "fileformat.h" +#include "activeframepool.h" + Object::Object(QObject* parent) : QObject(parent) { setData(new ObjectData()); + mActiveFramePool.reset(new ActiveFramePool(200)); } Object::~Object() { + mActiveFramePool->clear(); + while (!mLayers.empty()) { delete mLayers.takeLast(); @@ -568,6 +573,8 @@ void Object::paintImage(QPainter& painter,int frameNumber, bool background, bool antialiasing) const { + updateActiveFrames(frameNumber); + painter.setRenderHint(QPainter::Antialiasing, true); painter.setRenderHint(QPainter::SmoothPixmapTransform, true); painter.setCompositionMode(QPainter::CompositionMode_SourceOver); @@ -800,3 +807,18 @@ int Object::totalKeyFrameCount() } return sum; } + +void Object::updateActiveFrames(int frame) const +{ + int beginFrame = std::max(frame - 3, 1); + int endFrame = frame + 4; + for (int i = 0; i < getLayerCount(); ++i) + { + Layer* layer = getLayer(i); + for (int k = beginFrame; k < endFrame; ++k) + { + KeyFrame* key = layer->getKeyFrameAt(k); + mActiveFramePool->put(key); + } + } +} diff --git a/core_lib/src/structure/object.h b/core_lib/src/structure/object.h index a69bb0871..2bc2e43fc 100644 --- a/core_lib/src/structure/object.h +++ b/core_lib/src/structure/object.h @@ -33,6 +33,7 @@ class LayerVector; class LayerCamera; class LayerSound; class ObjectData; +class ActiveFramePool; struct ExportMovieParameters @@ -145,6 +146,7 @@ class Object : public QObject void setData( ObjectData* ); int totalKeyFrameCount(); + void updateActiveFrames(int frame) const; signals: void layerViewChanged(); @@ -163,6 +165,7 @@ class Object : public QObject QList mPalette; std::unique_ptr mData; + mutable std::unique_ptr mActiveFramePool; }; From fa788bfd05b7ad2c979ecdfed9bb3df236beeb24 Mon Sep 17 00:00:00 2001 From: Jakob Gahde Date: Sat, 4 Aug 2018 14:30:20 +0200 Subject: [PATCH 148/184] Add completion for bash and zsh --- app/app.pro | 8 +++++++- app/data/_pencil2d | 13 +++++++++++++ app/data/pencil2d | 27 +++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 app/data/_pencil2d create mode 100644 app/data/pencil2d diff --git a/app/app.pro b/app/app.pro index c726f20eb..dcfa13afa 100644 --- a/app/app.pro +++ b/app/app.pro @@ -139,6 +139,12 @@ win32 { linux { target.path = $${PREFIX}/bin + bashcompletion.files = data/pencil2d + bashcompletion.path = $${PREFIX}/share/bash-completion/completions + + zshcompletion.files = data/_pencil2d + zshcompletion.path = $${PREFIX}/share/zsh/site-functions + mimepackage.files = data/pencil2d.xml mimepackage.path = $${PREFIX}/share/mime/packages @@ -148,7 +154,7 @@ linux { icon.files = data/pencil2d.png icon.path = $${PREFIX}/share/icons/hicolor/256x256/apps - INSTALLS += target mimepackage desktopentry icon + INSTALLS += bashcompletion zshcompletion target mimepackage desktopentry icon } diff --git a/app/data/_pencil2d b/app/data/_pencil2d new file mode 100644 index 000000000..8bf4b29db --- /dev/null +++ b/app/data/_pencil2d @@ -0,0 +1,13 @@ +#compdef pencil2d + +_arguments \ + {-h,--help}'[Display help]' \ + {-v,--version}'[Display version information]' \ + {-o+,--export=}'[Render the file to the given path]:output file:_files' \ + '--camera=[Name of the camera layer to use]:name of the camera layer to use:' \ + '--width=[Width of the output frames]:width of the output frames:' \ + '--height=[Height of the output frames]:height of the output frames:' \ + '--start=[The first frame to export]:number of first frame to include:' \ + '--end=[The last frame to include]:number of last frame to include:((last\:"Last frame containing animation" last-sound\:"Last frame containing animation or sound"))' \ + '--transparency[Render transparency when possible]' \ + '::input file:_files -g "*.pcl|*.pclx"' diff --git a/app/data/pencil2d b/app/data/pencil2d new file mode 100644 index 000000000..061e40137 --- /dev/null +++ b/app/data/pencil2d @@ -0,0 +1,27 @@ +_pencil2d() +{ + local cur prev words cword opts + _init_completion || return + opts="-h --help -v --version -o --export --camera --width --height --start --end --transparency" + + case "${prev}" in + --camera|--width|--height|--start) + return 0 + ;; + --end) + COMPREPLY=( $(compgen -W "last last-sound" -- ${cur}) ) + return 0 + ;; + -o|--export) + _filedir + return 0 + ;; + esac + + if [[ ${cur} == -* ]]; then + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + else + _filedir "pcl?(x)" + fi +} && +complete -F _pencil2d pencil2d From 4c998dbea875d3cb1a91490e1a1d5118a19a73e5 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Mon, 6 Aug 2018 09:43:14 +1000 Subject: [PATCH 149/184] Give a maximum timeline length 9999 frames, the length will not grow over that number --- core_lib/src/interface/timeline.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core_lib/src/interface/timeline.cpp b/core_lib/src/interface/timeline.cpp index 7ac3e785d..9d7dc32ec 100644 --- a/core_lib/src/interface/timeline.cpp +++ b/core_lib/src/interface/timeline.cpp @@ -250,6 +250,10 @@ void TimeLine::extendLength(int frame) if(frame > (currentLength * 0.75)) { int newLength = std::max(frame, currentLength) * 1.5; + + if (newLength > 9999) + newLength = 9999; + mTracks->setFrameLength(newLength); updateLength(); } From f9e24fcc5b060351ae2d96e33dcd541d0650b2e4 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Mon, 6 Aug 2018 09:56:16 +1000 Subject: [PATCH 150/184] Fix #1025 HSV/RGB buttons of Colour inspector are too small on Mac --- app/ui/colorinspector.ui | 164 ++++++++++++++++----------------------- 1 file changed, 66 insertions(+), 98 deletions(-) diff --git a/app/ui/colorinspector.ui b/app/ui/colorinspector.ui index 1ca70e96a..952a845a1 100644 --- a/app/ui/colorinspector.ui +++ b/app/ui/colorinspector.ui @@ -7,8 +7,8 @@ 0 0 - 301 - 162 + 271 + 175 @@ -34,7 +34,7 @@ 2 - + 2 @@ -57,8 +57,8 @@ - 40 - 20 + 80 + 30 @@ -75,26 +75,10 @@ - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 5 - 20 - - - - - + 0 0 @@ -102,13 +86,13 @@ 40 - 0 + 25 - 40 - 20 + 80 + 30 @@ -145,43 +129,7 @@ 0 - - - - - 0 - 0 - - - - R - - - 2 - - - - - - - A - - - 2 - - - - - - - G - - - 2 - - - - + @@ -194,8 +142,8 @@ - - + + 60 @@ -207,29 +155,16 @@ - - + + - B + A 2 - - - - - 60 - 16777215 - - - - 255 - - - @@ -257,8 +192,8 @@ - - + + 60 @@ -270,6 +205,16 @@ + + + + G + + + 2 + + + @@ -297,6 +242,32 @@ + + + + + 0 + 0 + + + + R + + + 2 + + + + + + + B + + + 2 + + + @@ -324,6 +295,19 @@ + + + + + 60 + 16777215 + + + + 255 + + + @@ -360,22 +344,6 @@ - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 5 - 20 - - - - From aec2652614759cf20915338adeabb7e81923e75c Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 7 Aug 2018 12:59:21 +1000 Subject: [PATCH 151/184] Extract pclx to the data folder with random generated folder name to avoid folder name conflicts. If a user opens the same project twice in a row, Penci2D will: 1. Create data folder for file to load 2. Load everything into the data folder 3. Stop if there is an error 4. Switch to using the new data folder 5. Delete the old data folder However, if the old data folder and new data folder are the same, then step 5 ends up deleting all the data from our project! (by scribblemaniac) --- core_lib/src/structure/filemanager.cpp | 1 + core_lib/src/structure/object.cpp | 7 ++----- core_lib/src/util/fileformat.cpp | 16 ++++++++++++++++ core_lib/src/util/fileformat.h | 5 +++-- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/core_lib/src/structure/filemanager.cpp b/core_lib/src/structure/filemanager.cpp index a1ec37bb2..9c89ed452 100644 --- a/core_lib/src/structure/filemanager.cpp +++ b/core_lib/src/structure/filemanager.cpp @@ -41,6 +41,7 @@ FileManager::FileManager(QObject *parent) : QObject(parent), mLog("FileManager") { ENABLE_DEBUG_LOG(mLog, false); + srand(time(nullptr)); } Object* FileManager::load(QString sFileName) diff --git a/core_lib/src/structure/object.cpp b/core_lib/src/structure/object.cpp index d28eb30e7..574846a80 100644 --- a/core_lib/src/structure/object.cpp +++ b/core_lib/src/structure/object.cpp @@ -164,11 +164,8 @@ void Object::createWorkingDir() QFileInfo fileInfo(mFilePath); strFolderName = fileInfo.completeBaseName(); } - const QString strWorkingDir = QDir::tempPath() - + "/Pencil2D/" - + strFolderName - + PFF_TMP_DECOMPRESS_EXT - + "/"; + const QString strWorkingDir = + QString("%1/Pencil2D/%2_%3_%4/").arg(QDir::tempPath()).arg(strFolderName).arg(PFF_TMP_DECOMPRESS_EXT).arg(uniqueString(8)); QDir dir(QDir::tempPath()); dir.mkpath(strWorkingDir); diff --git a/core_lib/src/util/fileformat.cpp b/core_lib/src/util/fileformat.cpp index 41774dafc..4b3627610 100644 --- a/core_lib/src/util/fileformat.cpp +++ b/core_lib/src/util/fileformat.cpp @@ -37,3 +37,19 @@ bool removePFFTmpDirectory (const QString& dirName) return result; } + +QString uniqueString(int len) +{ + static const char alphanum[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + const int alphanum_len = sizeof(alphanum); + + if (len > 128) len = 128; + + char s[128 + 1]; + for (int i = 0; i < len; ++i) + { + s[i] = alphanum[rand() % (alphanum_len - 1)]; + } + s[len] = 0; + return QString::fromUtf8(s); +} diff --git a/core_lib/src/util/fileformat.h b/core_lib/src/util/fileformat.h index 4c523219a..359249b2a 100644 --- a/core_lib/src/util/fileformat.h +++ b/core_lib/src/util/fileformat.h @@ -33,12 +33,13 @@ GNU General Public License for more details. #define PFF_OLD_DATA_DIR "data" #define PFF_DATA_DIR "data" #define PFF_XML_FILE_NAME "main.xml" -#define PFF_TMP_COMPRESS_EXT ".Y2xC" -#define PFF_TMP_DECOMPRESS_EXT ".Y2xD" +#define PFF_TMP_COMPRESS_EXT "Y2xC" +#define PFF_TMP_DECOMPRESS_EXT "Y2xD" #define PFF_PALETTE_FILE "palette.xml" bool removePFFTmpDirectory (const QString& dirName); +QString uniqueString(int len); #endif From 54355210824afad6d89d83206b50ffa4e9fa207d Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 7 Aug 2018 13:14:15 +1000 Subject: [PATCH 152/184] a missing header --- core_lib/src/structure/filemanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/core_lib/src/structure/filemanager.cpp b/core_lib/src/structure/filemanager.cpp index 9c89ed452..6e7f46b43 100644 --- a/core_lib/src/structure/filemanager.cpp +++ b/core_lib/src/structure/filemanager.cpp @@ -17,6 +17,7 @@ GNU General Public License for more details. #include "filemanager.h" +#include #include #include "pencildef.h" #include "qminiz.h" From abf3ae2ea368ac971cbe05cca0fd15419c9a5dfa Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Thu, 9 Aug 2018 09:52:43 +1000 Subject: [PATCH 153/184] Make sure the work directory is a fresh new folder --- core_lib/src/structure/object.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/core_lib/src/structure/object.cpp b/core_lib/src/structure/object.cpp index 574846a80..c6c35164d 100644 --- a/core_lib/src/structure/object.cpp +++ b/core_lib/src/structure/object.cpp @@ -164,12 +164,20 @@ void Object::createWorkingDir() QFileInfo fileInfo(mFilePath); strFolderName = fileInfo.completeBaseName(); } - const QString strWorkingDir = - QString("%1/Pencil2D/%2_%3_%4/").arg(QDir::tempPath()).arg(strFolderName).arg(PFF_TMP_DECOMPRESS_EXT).arg(uniqueString(8)); - QDir dir(QDir::tempPath()); - dir.mkpath(strWorkingDir); + QString strWorkingDir; + do + { + strWorkingDir = QString("%1/Pencil2D/%2_%3_%4/") + .arg(QDir::tempPath()) + .arg(strFolderName) + .arg(PFF_TMP_DECOMPRESS_EXT) + .arg(uniqueString(8)); + } + while(dir.exists(strWorkingDir)); + + dir.mkpath(strWorkingDir); mWorkingDirPath = strWorkingDir; QDir dataDir(strWorkingDir + PFF_DATA_DIR); From 2e5db2adf615a26e9447ee5993224fcf10b793fc Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Thu, 9 Aug 2018 09:54:02 +1000 Subject: [PATCH 154/184] Delete an unused define Y2xC --- core_lib/src/util/fileformat.h | 1 - 1 file changed, 1 deletion(-) diff --git a/core_lib/src/util/fileformat.h b/core_lib/src/util/fileformat.h index 359249b2a..8381faf3d 100644 --- a/core_lib/src/util/fileformat.h +++ b/core_lib/src/util/fileformat.h @@ -33,7 +33,6 @@ GNU General Public License for more details. #define PFF_OLD_DATA_DIR "data" #define PFF_DATA_DIR "data" #define PFF_XML_FILE_NAME "main.xml" -#define PFF_TMP_COMPRESS_EXT "Y2xC" #define PFF_TMP_DECOMPRESS_EXT "Y2xD" #define PFF_PALETTE_FILE "palette.xml" From 7e7b40145ba6bd4f4f2f2450f60fb9ada9de09dc Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Thu, 9 Aug 2018 10:04:18 +1000 Subject: [PATCH 155/184] Delete the working directory anyway when deleting an Object --- core_lib/src/structure/object.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/core_lib/src/structure/object.cpp b/core_lib/src/structure/object.cpp index c6c35164d..30d79db8f 100644 --- a/core_lib/src/structure/object.cpp +++ b/core_lib/src/structure/object.cpp @@ -45,16 +45,11 @@ Object::~Object() { mActiveFramePool->clear(); - while (!mLayers.empty()) - { - delete mLayers.takeLast(); - } + for (Layer* layer : mLayers) + delete layer; + mLayers.clear(); - // Delete the working directory if this is not a "New" project. - if (!filePath().isEmpty()) - { - deleteWorkingDir(); - } + deleteWorkingDir(); } void Object::init() From 1506fd4a5e660cf525664b597598df7852782db1 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Thu, 9 Aug 2018 10:04:18 +1000 Subject: [PATCH 156/184] Don't delete a thing if the working dir path is empty - most of them are unit tests --- core_lib/src/structure/object.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core_lib/src/structure/object.cpp b/core_lib/src/structure/object.cpp index 30d79db8f..cfc7a00d5 100644 --- a/core_lib/src/structure/object.cpp +++ b/core_lib/src/structure/object.cpp @@ -183,8 +183,11 @@ void Object::createWorkingDir() void Object::deleteWorkingDir() const { - QDir dir(mWorkingDirPath); - dir.removeRecursively(); + if (!mWorkingDirPath.isEmpty()) + { + QDir dir(mWorkingDirPath); + dir.removeRecursively(); + } } void Object::createDefaultLayers() From da425f09b4079bd024c10da9bc4c2c60e8b1ac48 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Mon, 20 Aug 2018 10:32:59 +1000 Subject: [PATCH 157/184] build nightly builds in release mode --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c4c25149b..a3940869c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -90,7 +90,7 @@ script: - 'if [ "$TRAVIS_BRANCH" == "release" ]; then qmake ../ PREFIX=/usr CONFIG+=release DEFINES+=QT_NO_DEBUG_OUTPUT DEFINES+=PENCIL2D_RELEASE; else - qmake ../ PREFIX=/usr CONFIG+=GIT CONFIG+=NIGHTLY; + qmake ../ PREFIX=/usr CONFIG+=release CONFIG+=GIT CONFIG+=NIGHTLY; fi' - make; - "$TRAVIS_BUILD_DIR/build/tests/tests" From b9edaecb050707c4145cecfd0e76e1c83eb493a6 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Mon, 20 Aug 2018 11:19:51 +1000 Subject: [PATCH 158/184] Fix #1048: Crash on file loading operation after drawing vectors [Why] ActiveFramePool is a member of Object and will get destroyed automatically when the Object is destroyed. So keyframes in undo stack are not be able to access ActiveFramePool after unloading a project. [Fix] Clear the undo stack before deleting the Object --- core_lib/src/interface/editor.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core_lib/src/interface/editor.cpp b/core_lib/src/interface/editor.cpp index 6d7b2c2df..504c4b38c 100644 --- a/core_lib/src/interface/editor.cpp +++ b/core_lib/src/interface/editor.cpp @@ -612,6 +612,7 @@ Status Editor::setObject(Object* newObject) return Status::SAFE; } + clearUndoStack(); mObject.reset(newObject); for (BaseManager* m : mAllManagers) @@ -638,8 +639,6 @@ void Editor::updateObject() scrubTo(mObject->data()->getCurrentFrame()); setCurrentLayerIndex(mObject->data()->getCurrentLayer()); - clearUndoStack(); - mAutosaveCounter = 0; mAutosaveNerverAskAgain = false; From 79c730f62523db9ad175df89e697c426d37970f3 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Fri, 17 Aug 2018 12:13:04 +1000 Subject: [PATCH 159/184] Delete unused functions --- core_lib/src/activeframepool.h | 2 +- core_lib/src/structure/filemanager.cpp | 61 ++------------------------ core_lib/src/structure/filemanager.h | 3 -- 3 files changed, 4 insertions(+), 62 deletions(-) diff --git a/core_lib/src/activeframepool.h b/core_lib/src/activeframepool.h index 785437618..2cd7af0bc 100644 --- a/core_lib/src/activeframepool.h +++ b/core_lib/src/activeframepool.h @@ -42,7 +42,7 @@ class ActiveFramePool : public KeyFrameEventListener private: void unloadFrame(KeyFrame* key); - typedef std::list::iterator list_iterator_t; + using list_iterator_t = std::list::iterator; std::list mCacheFramesList; std::unordered_map mCacheFramesMap; diff --git a/core_lib/src/structure/filemanager.cpp b/core_lib/src/structure/filemanager.cpp index 6e7f46b43..93dd3edf5 100644 --- a/core_lib/src/structure/filemanager.cpp +++ b/core_lib/src/structure/filemanager.cpp @@ -225,8 +225,7 @@ Status FileManager::save(Object* object, QString sFileName) if (fileInfo.isDir()) { dd << "FileName points to a directory"; - return Status(Status::INVALID_ARGUMENT, - dd, + return Status(Status::INVALID_ARGUMENT, dd, tr("Invalid Save Path"), tr("The path (\"%1\") points to a directory.").arg(fileInfo.absoluteFilePath())); } @@ -234,16 +233,14 @@ Status FileManager::save(Object* object, QString sFileName) if (!parentDirInfo.exists()) { dd << "The parent directory of sFileName does not exist"; - return Status(Status::INVALID_ARGUMENT, - dd, + return Status(Status::INVALID_ARGUMENT, dd, tr("Invalid Save Path"), tr("The directory (\"%1\") does not exist.").arg(parentDirInfo.absoluteFilePath())); } if ((fileInfo.exists() && !fileInfo.isWritable()) || !parentDirInfo.isWritable()) { dd << "Filename points to a location that is not writable"; - return Status(Status::INVALID_ARGUMENT, - dd, + return Status(Status::INVALID_ARGUMENT, dd, tr("Invalid Save Path"), tr("The path (\"%1\") is not writable.").arg(fileInfo.absoluteFilePath())); } @@ -280,7 +277,6 @@ Status FileManager::save(Object* object, QString sFileName) if (!dir.mkpath(sDataFolder)) { dd << QString("dir.absolutePath() = %1").arg(dir.absolutePath()); - return Status(Status::FAIL, dd, tr("Cannot Create Data Directory"), tr("Failed to create directory \"%1\". Please make sure you have sufficient permissions.").arg(sDataFolder)); @@ -624,54 +620,3 @@ Status FileManager::verifyObject(Object* obj) return Status::OK; } -QStringList FileManager::getImageSrcNamesFromXML(QString mainXmlFile, QString dataFolderPath) -{ - QStringList listOfWorkFolderFiles = QDir(dataFolderPath).entryList(QDir::Files); - - QFile xmlFile(mainXmlFile); - QDomDocument xmlDoc; - xmlDoc.setContent(&xmlFile); - QDomElement objectElem = xmlDoc.firstChildElement("document"); - - QStringList srcNames; - - QDomNode objectNode = objectElem.namedItem("object"); - QDomElement element = objectNode.toElement(); - - for (QDomNode child = element.firstChild(); !child.isNull(); child = child.nextSibling()) - { - QDomElement element = child.toElement(); - if (element.tagName() == "layer") - { - for (QDomNode child2 = element.firstChild(); !child2.isNull(); child2 = child2.nextSibling()) - { - QDomElement element = child2.toElement(); - - srcNames << element.attribute("src"); - } - } - } - return srcNames; -} - -void FileManager::removeFilesWithNoXMLReference(QString xmlFilePath, QString dataFolderPath) -{ - QStringList srcNames = getImageSrcNamesFromXML(xmlFilePath, dataFolderPath); - QStringList listOfWorkFolderFiles = QDir(dataFolderPath).entryList(QDir::Files); - for (QString fileName: listOfWorkFolderFiles) - { - bool fileExists = false; - for (QString srcName: srcNames) - { - if (fileName == srcName) - { - fileExists = true; - } - } - - if (!fileExists && !fileName.endsWith(".xml", Qt::CaseInsensitive)) - { - QDir(dataFolderPath).remove(fileName); - } - } -} diff --git a/core_lib/src/structure/filemanager.h b/core_lib/src/structure/filemanager.h index f31812f50..9ace6e863 100644 --- a/core_lib/src/structure/filemanager.h +++ b/core_lib/src/structure/filemanager.h @@ -67,9 +67,6 @@ class FileManager : public QObject void deleteBackupFile(const QString& fileName); void progressForward(); - void removeFilesWithNoXMLReference(QString xmlFilePath, QString dataFolderPath); - - QStringList getImageSrcNamesFromXML(QString mainXmlFile, QString dataFolderPath); private: Status mError = Status::OK; From 3dae435f81089e5f00dbde3e06359f470ef54e47 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Fri, 17 Aug 2018 13:18:46 +1000 Subject: [PATCH 160/184] Fix: app crashes when leaving a not paintable layer with move tool - and a bit refactoring --- core_lib/src/tool/movetool.cpp | 74 ++++++++++++++++++---------------- core_lib/src/tool/movetool.h | 20 +++++---- 2 files changed, 48 insertions(+), 46 deletions(-) diff --git a/core_lib/src/tool/movetool.cpp b/core_lib/src/tool/movetool.cpp index 661cbba9d..dbc034942 100644 --- a/core_lib/src/tool/movetool.cpp +++ b/core_lib/src/tool/movetool.cpp @@ -56,13 +56,10 @@ QCursor MoveTool::cursor() void MoveTool::mousePressEvent(QMouseEvent* event) { - mCurrentLayer = mEditor->layers()->currentLayer(); - if (mCurrentLayer == NULL) { return; } - if (!mCurrentLayer->isPaintable()) { return; } + mCurrentLayer = currentPaintableLayer(); if (event->button() != Qt::LeftButton) { return; } - beginInteraction(event); - + beginInteraction(event, mCurrentLayer); } void MoveTool::mouseReleaseEvent(QMouseEvent*) @@ -79,22 +76,21 @@ void MoveTool::mouseReleaseEvent(QMouseEvent*) void MoveTool::mouseMoveEvent(QMouseEvent* event) { - mCurrentLayer = mEditor->layers()->currentLayer(); - if (mCurrentLayer == NULL) { return; } - if (!mCurrentLayer->isPaintable()) { return; } + mCurrentLayer = currentPaintableLayer(); if (event->buttons() & Qt::LeftButton) // the user is also pressing the mouse (dragging) { - transformSelection(event); + transformSelection(event, mCurrentLayer); } - else // the user is moving the mouse without pressing it + else { + // the user is moving the mouse without pressing it // update cursor to reflect selection corner interaction mScribbleArea->updateToolCursor(); if (mCurrentLayer->type() == Layer::VECTOR) { - storeClosestVectorCurve(); + storeClosestVectorCurve(mCurrentLayer); } } mScribbleArea->updateCurrentFrame(); @@ -110,17 +106,19 @@ void MoveTool::updateTransformation() // paint the transformation paintTransformedSelection(); - } -void MoveTool::transformSelection(QMouseEvent* event) +void MoveTool::transformSelection(QMouseEvent* event, Layer* layer) { if (mScribbleArea->isSomethingSelected()) { QPointF offset; - if (mCurrentLayer->type() == Layer::VECTOR) { + if (layer->type() == Layer::VECTOR) + { offset = mScribbleArea->getTransformOffset(); - } else { + } + else + { offset = QPointF(mScribbleArea->getTransformOffset().x(), mScribbleArea->getTransformOffset().y()).toPoint(); } @@ -132,7 +130,6 @@ void MoveTool::transformSelection(QMouseEvent* event) } mScribbleArea->adjustSelection(offset.x(),offset.y(), mRotatedAngle); - mScribbleArea->calculateSelectionTransformation(); paintTransformedSelection(); @@ -143,7 +140,7 @@ void MoveTool::transformSelection(QMouseEvent* event) } } -void MoveTool::beginInteraction(QMouseEvent* event) +void MoveTool::beginInteraction(QMouseEvent* event, Layer* layer) { if (event->buttons() & Qt::LeftButton) { @@ -168,19 +165,17 @@ void MoveTool::beginInteraction(QMouseEvent* event) } } - if (mScribbleArea->getMoveMode() == MoveMode::MIDDLE) { if (event->modifiers() == Qt::ControlModifier) // --- rotation { mScribbleArea->setMoveMode(MoveMode::ROTATION); } - } - if (mCurrentLayer->type() == Layer::VECTOR) + if (layer->type() == Layer::VECTOR) { - createVectorSelection(event); + createVectorSelection(event, layer); } } @@ -195,10 +190,11 @@ bool MoveTool::shouldDeselect() * In vector the selection rectangle is based on the bounding box of the curves * We can therefore create a selection just by clicking near/on a curve */ -void MoveTool::createVectorSelection(QMouseEvent* event) +void MoveTool::createVectorSelection(QMouseEvent* event, Layer* layer) { - VectorImage* vectorImage = static_cast(mCurrentLayer)-> - getLastVectorImageAtFrame(mEditor->currentFrame(), 0); + assert(layer->type() == Layer::VECTOR); + LayerVector* vecLayer = static_cast(layer); + VectorImage* vectorImage = vecLayer->getLastVectorImageAtFrame(mEditor->currentFrame(), 0); if (mScribbleArea->mClosestCurves.size() > 0) // the user clicks near a curve { @@ -236,7 +232,6 @@ void MoveTool::setAreaSelected(VectorImage* vectorImage, QMouseEvent* event) vectorImage->setAreaSelected(areaNumber, true); mScribbleArea->setSelection(vectorImage->getSelectionRect()); } - } QPointF MoveTool::maintainAspectRatio(qreal offsetX, qreal offsetY) @@ -269,9 +264,9 @@ QPointF MoveTool::maintainAspectRatio(qreal offsetX, qreal offsetY) * @brief MoveTool::storeClosestVectorCurve * stores the curves closest to the mouse position in mClosestCurves */ -void MoveTool::storeClosestVectorCurve() +void MoveTool::storeClosestVectorCurve(Layer* layer) { - auto layerVector = static_cast(mCurrentLayer); + auto layerVector = static_cast(layer); VectorImage* pVecImg = layerVector->getLastVectorImageAtFrame(mEditor->currentFrame(), 0); mScribbleArea->mClosestCurves = pVecImg->getCurvesCloseTo(getCurrentPoint(), mScribbleArea->selectionTolerance / mEditor->view()->scaling()); @@ -314,15 +309,15 @@ void MoveTool::paintTransformedSelection() bool MoveTool::leavingThisTool() { - if (mCurrentLayer->type() == Layer::BITMAP) + if (mCurrentLayer) { - applySelectionChanges(); - } - else if (mCurrentLayer->type() == Layer::VECTOR) - { - applyTransformation(); + switch (mCurrentLayer->type()) + { + case Layer::BITMAP: applySelectionChanges(); break; + case Layer::VECTOR: applyTransformation(); break; + default: break; + } } - return true; } @@ -343,7 +338,6 @@ bool MoveTool::switchingLayer() if (returnValue == QMessageBox::Yes) { - if (mCurrentLayer->type() == Layer::BITMAP) { applySelectionChanges(); @@ -380,3 +374,13 @@ void MoveTool::resetSelectionProperties() { mScribbleArea->resetSelectionProperties(); } + +Layer* MoveTool::currentPaintableLayer() +{ + Layer* layer = mEditor->layers()->currentLayer(); + if (layer == nullptr) + return nullptr; + if (!layer->isPaintable()) + return nullptr; + return layer; +} diff --git a/core_lib/src/tool/movetool.h b/core_lib/src/tool/movetool.h index 11a84f796..8e6ea7a71 100644 --- a/core_lib/src/tool/movetool.h +++ b/core_lib/src/tool/movetool.h @@ -29,14 +29,14 @@ class MoveTool : public BaseTool { Q_OBJECT public: - explicit MoveTool( QObject* parent = 0 ); + explicit MoveTool(QObject* parent); ToolType type() override; void loadSettings() override; QCursor cursor() override; - void mousePressEvent(QMouseEvent *) override; - void mouseReleaseEvent(QMouseEvent *) override; - void mouseMoveEvent(QMouseEvent *) override; + void mousePressEvent(QMouseEvent*) override; + void mouseReleaseEvent(QMouseEvent*) override; + void mouseMoveEvent(QMouseEvent*) override; bool leavingThisTool() override; bool switchingLayer() override; @@ -53,9 +53,10 @@ class MoveTool : public BaseTool int showTransformWarning(); - void beginInteraction(QMouseEvent* event); - void createVectorSelection(QMouseEvent* event); - void transformSelection(QMouseEvent* event); + void beginInteraction(QMouseEvent* event, Layer* layer); + void createVectorSelection(QMouseEvent* event, Layer* layer); + void transformSelection(QMouseEvent* event, Layer* layer); + void storeClosestVectorCurve(Layer* layer); void setCurveSelected(VectorImage* vectorImage, QMouseEvent* event); void setAreaSelected(VectorImage* vectorImage, QMouseEvent* event); @@ -63,15 +64,12 @@ class MoveTool : public BaseTool bool transformHasBeenModified(); bool shouldDeselect(); - void storeClosestVectorCurve(); QPointF maintainAspectRatio(qreal offsetX, qreal offsetY); + Layer* currentPaintableLayer(); QPointF anchorOriginPoint; - Layer* mCurrentLayer = nullptr; - qreal mRotatedAngle = 0.0; - }; #endif From 0a2c87b523fc81c655daf391a26af967134ba733 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Mon, 20 Aug 2018 11:39:21 +1000 Subject: [PATCH 161/184] A missing header --- core_lib/src/tool/movetool.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/core_lib/src/tool/movetool.cpp b/core_lib/src/tool/movetool.cpp index dbc034942..55a3e3624 100644 --- a/core_lib/src/tool/movetool.cpp +++ b/core_lib/src/tool/movetool.cpp @@ -17,6 +17,7 @@ GNU General Public License for more details. #include "movetool.h" +#include #include #include From 3e119678dc8123132ab6780fce8a1f04fae91cdc Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Wed, 22 Aug 2018 22:31:08 -0600 Subject: [PATCH 162/184] Fix: pre 0.6 project exporting issues [Why] Deleting the camera layer was allowed in earlier versions, so when they are loaded with this version. The missing now-mandatory camera layer causes issues when rendering. See https://discuss.pencil2d.org/t/cant-create-videos-with-projects-created-with-v0-5-4/2840 [Fix] Add a new camera layer when loading a file if it does not already contain one. --- core_lib/src/structure/object.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/core_lib/src/structure/object.cpp b/core_lib/src/structure/object.cpp index cfc7a00d5..20d38c8a4 100644 --- a/core_lib/src/structure/object.cpp +++ b/core_lib/src/structure/object.cpp @@ -84,6 +84,7 @@ bool Object::loadXML(QDomElement docElem, ProgressCallback progressForward) int layerNumber = -1; const QString dataDirPath = mDataDirPath; + bool hasCameraLayer = false; for (QDomNode node = docElem.firstChild(); !node.isNull(); node = node.nextSibling()) { @@ -95,13 +96,19 @@ bool Object::loadXML(QDomElement docElem, ProgressCallback progressForward) case Layer::BITMAP: addNewBitmapLayer(); break; case Layer::VECTOR: addNewVectorLayer(); break; case Layer::SOUND: addNewSoundLayer(); break; - case Layer::CAMERA: addNewCameraLayer(); break; + case Layer::CAMERA: addNewCameraLayer(); hasCameraLayer = true; break; default: Q_ASSERT(false); break; } layerNumber++; getLayer(layerNumber)->loadDomElement(element, dataDirPath, progressForward); } } + + // Must have at least 1 camera layer + if(!hasCameraLayer) { + addNewCameraLayer(); + } + return true; } From cf9a710aea810a1da8c8942ffaec4d887f7d3885 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Sat, 25 Aug 2018 14:32:47 -0600 Subject: [PATCH 163/184] Simple autocrop --- core_lib/src/graphics/bitmap/bitmapimage.cpp | 191 ++++++++++++++++++- core_lib/src/graphics/bitmap/bitmapimage.h | 4 +- 2 files changed, 188 insertions(+), 7 deletions(-) diff --git a/core_lib/src/graphics/bitmap/bitmapimage.cpp b/core_lib/src/graphics/bitmap/bitmapimage.cpp index 8fb000e9d..f37a15e0c 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.cpp +++ b/core_lib/src/graphics/bitmap/bitmapimage.cpp @@ -133,14 +133,16 @@ BitmapImage BitmapImage::copy(QRect rectangle) return result; } -void BitmapImage::paste(BitmapImage* bitmapImage) -{ - paste(bitmapImage, QPainter::CompositionMode_SourceOver); -} - void BitmapImage::paste(BitmapImage* bitmapImage, QPainter::CompositionMode cm) { QRect newBoundaries; + + bitmapImage->autoCrop(); + if(bitmapImage->width() <= 0 || bitmapImage->height() <= 0) + { + return; + } + if (image()->width() == 0 || image()->height() == 0) { newBoundaries = bitmapImage->mBounds; @@ -158,6 +160,8 @@ void BitmapImage::paste(BitmapImage* bitmapImage, QPainter::CompositionMode cm) painter.drawImage(bitmapImage->mBounds.topLeft() - mBounds.topLeft(), *image2); painter.end(); + autoCrop(); + modification(); } @@ -332,6 +336,183 @@ void BitmapImage::extend(QRect rectangle) } } +/** Removes any transparent borders by reducing the boundaries. + * + * This function reduces the bounds of an image until the top and + * bottom rows, and the left and right columns of pixels each + * contain at least one pixel with a non-zero alpha value + * (i.e. non-transparent pixel). Both mBounds and + * the size of #mImage are updated. + * + * @pre mBounds.size() == mImage->size() + * @post Either the first and last rows and columns all contain a + * pixel with alpha > 0 or mBounds.isEmpty() == true + */ +void BitmapImage::autoCrop() +{ + // Get image properties + const int width = mImage->width(); + + // Relative top and bottom row indices (inclusive) + int relTop = 0; + int relBottom = mBounds.height()-1; + + // Check top row + bool isEmpty = true; // Used to track if a non-transparent pixel has been found + while (isEmpty && relTop <= relBottom) // Loop through rows + { + // Point cursor to the first pixel in the current top row + const QRgb* cursor = reinterpret_cast(mImage->constScanLine(relTop)); + for (int col = 0; col < width; col++) // Loop through pixels in row + { + // If the pixel is not transparent + // (i.e. alpha channel > 0) + if (qAlpha(*cursor) != 0) + { + // We've found a non-transparent pixel in row relTop, + // so we can stop looking for one + isEmpty = false; + break; + } + // Move cursor to point to the next pixel in the row + cursor++; + } + if (isEmpty) + { + // If the row we just checked was empty, increase relTop + // to remove the empty row from the top of the bounding box + ++relTop; + } + } + + // Check bottom row + isEmpty = true; // Reset isEmpty + while (isEmpty && relBottom >= relTop) // Loop through rows + { + // Point cursor to the first pixel in the current bottom row + const QRgb* cursor = reinterpret_cast(mImage->constScanLine(relBottom)); + for (int col = 0; col < width; col++) // Loop through pixels in row + { + // If the pixel is not transparent + // (i.e. alpha channel > 0) + if(qAlpha(*cursor) != 0) + { + // We've found a non-transparent pixel in row relBottom, + // so we can stop looking for one + isEmpty = false; + break; + } + // Move cursor to point to the next pixel in the row + ++cursor; + } + if (isEmpty) + { + // If the row we just checked was empty, decrease relBottom + // to remove the empty row from the bottom of the bounding box + --relBottom; + } + } + + // Relative left and right column indices (inclusive) + int relLeft = 0; + int relRight = mBounds.width()-1; + + // Check left row + isEmpty = true; // Reset isEmpty + while (isEmpty && relLeft <= relRight) // Loop through columns + { + // Point cursor to the pixel at row relTop and column relLeft + const QRgb* cursor = reinterpret_cast(mImage->constScanLine(relTop)) + relLeft; + // Loop through pixels in column + // Note: we only need to loop from relTop to relBottom (inclusive) + // not the full image height, because rows 0 to relTop-1 and + // relBottom+1 to mBounds.height() have already been + // confirmed to contain only transparent pixels + for (int row = relTop; row <= relBottom; row++) + { + // If the pixel is not transparent + // (i.e. alpha channel > 0) + if(qAlpha(*cursor) != 0) + { + // We've found a non-transparent pixel in column relLeft, + // so we can stop looking for one + isEmpty = false; + break; + } + // Move cursor to point to next pixel in the column + // Increment by width because the data is in row-major order + cursor += width; + } + if (isEmpty) + { + // If the column we just checked was empty, increase relLeft + // to remove the empty column from the left of the bounding box + ++relLeft; + } + } + + // Check right row + isEmpty = true; // Reset isEmpty + while (isEmpty && relRight >= relLeft) // Loop through columns + { + // Point cursor to the pixel at row relTop and column relRight + const QRgb* cursor = reinterpret_cast(mImage->constScanLine(relTop)) + relRight; + // Loop through pixels in column + // Note: we only need to loop from relTop to relBottom (inclusive) + // not the full image height, because rows 0 to relTop-1 and + // relBottom+1 to mBounds.height()-1 have already been + // confirmed to contain only transparent pixels + for (int row = relTop; row <= relBottom; row++) + { + // If the pixel is not transparent + // (i.e. alpha channel > 0) + if(qAlpha(*cursor) != 0) + { + // We've found a non-transparent pixel in column relRight, + // so we can stop looking for one + isEmpty = false; + break; + } + // Move cursor to point to next pixel in the column + // Increment by width because the data is in row-major order + cursor += width; + } + if (isEmpty) + { + // If the column we just checked was empty, increase relRight + // to remove the empty column from the left of the bounding box + --relRight; + } + } + + // If any of the rel* variables have changed, then update mBounds and mImage + if (relTop != 0 || + relLeft != 0 || + relRight != mBounds.width()-1 || + relBottom != mBounds.height()-1) + { + // Create new QRect for bounds by normalizing mBounds and then applying the rel offsets + QRect newBoundaries = mBounds.normalized().adjusted(relLeft, relTop, relRight - mBounds.width() + 1, relBottom - mBounds.height() + 1); + // Create a new image with this same size + QImage* newImage = new QImage( newBoundaries.size(), QImage::Format_ARGB32_Premultiplied); + // Make the image transparent + newImage->fill(Qt::transparent); + // If the image initialized properly + // (probably true unless the newBoundaries width or height <= 0) + if (!newImage->isNull()) + { + // Copy mImage to the new image with the updated size + QPainter painter(newImage); + painter.drawImage(mBounds.topLeft() - newBoundaries.topLeft(), *mImage); + painter.end(); + } + // Apply the resized image to mImage + mImage.reset( newImage ); + // Apply the boundaries to mBounds + mBounds = newBoundaries; + } +} + QRgb BitmapImage::pixel(int x, int y) { return pixel(QPoint(x, y)); diff --git a/core_lib/src/graphics/bitmap/bitmapimage.h b/core_lib/src/graphics/bitmap/bitmapimage.h index c214b3faf..2a74baf0b 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.h +++ b/core_lib/src/graphics/bitmap/bitmapimage.h @@ -46,8 +46,7 @@ class BitmapImage : public KeyFrame BitmapImage copy(); BitmapImage copy(QRect rectangle); - void paste(BitmapImage*); - void paste(BitmapImage*, QPainter::CompositionMode cm); + void paste(BitmapImage*, QPainter::CompositionMode cm = QPainter::CompositionMode_SourceOver); void add(BitmapImage*); void compareAlpha(BitmapImage*); @@ -63,6 +62,7 @@ class BitmapImage : public KeyFrame bool contains(QPointF P) { return contains(P.toPoint()); } void extend(QPoint P); void extend(QRect rectangle); + void autoCrop(); QRgb pixel(int x, int y); QRgb pixel(QPoint P); From d5dd9a4140e1ada5a86e8361ce0c22ce6cade7b8 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Sat, 25 Aug 2018 15:24:48 -0600 Subject: [PATCH 164/184] Revert b084401 and apply different fix Forcing the bounds to be > 0 does not work well with autocropping. Instead we should delete images that are empty when saving. Related to #939 --- core_lib/src/graphics/bitmap/bitmapimage.cpp | 24 +++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/core_lib/src/graphics/bitmap/bitmapimage.cpp b/core_lib/src/graphics/bitmap/bitmapimage.cpp index f37a15e0c..a5be82367 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.cpp +++ b/core_lib/src/graphics/bitmap/bitmapimage.cpp @@ -19,13 +19,13 @@ GNU General Public License for more details. #include #include #include +#include #include "util.h" BitmapImage::BitmapImage() { - mImage = std::make_shared(1, 1, QImage::Format_ARGB32_Premultiplied); // don't create null image - mImage->fill(QColor(0,0,0,0)); - mBounds = QRect(0, 0, 1, 1); + mImage = std::make_shared(); // create null image + mBounds = QRect(0, 0, 0, 0); } BitmapImage::BitmapImage(const BitmapImage& a) : KeyFrame(a) @@ -659,14 +659,26 @@ Status BitmapImage::writeFile(const QString& filename) bool b = mImage->save(filename); return (b) ? Status::OK : Status::FAIL; } + else + { + QFile f(filename); + if(f.exists()) + { + bool b = f.remove(); + return (b) ? Status::OK : Status::FAIL; + } + else + { + return Status::OK; + } + } return Status::SAFE; } void BitmapImage::clear() { - mImage = std::make_shared(1, 1, QImage::Format_ARGB32_Premultiplied); // null image - mBounds = QRect(0, 0, 1, 1); - mImage->fill(QColor(0,0,0,0)); + mImage = std::make_shared(); // null image + mBounds = QRect(0, 0, 0, 0); modification(); } From 7f83b814fe6bc53f7d03ecf46a226e6d106a71d4 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Sat, 25 Aug 2018 18:23:28 -0600 Subject: [PATCH 165/184] Basic autocropping --- core_lib/src/graphics/bitmap/bitmapimage.cpp | 353 ++++++++++--------- core_lib/src/graphics/bitmap/bitmapimage.h | 61 ++-- core_lib/src/interface/editor.cpp | 5 +- core_lib/src/structure/layerbitmap.cpp | 2 +- tests/src/test_bitmapimage.cpp | 15 - 5 files changed, 225 insertions(+), 211 deletions(-) diff --git a/core_lib/src/graphics/bitmap/bitmapimage.cpp b/core_lib/src/graphics/bitmap/bitmapimage.cpp index a5be82367..150c3d76f 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.cpp +++ b/core_lib/src/graphics/bitmap/bitmapimage.cpp @@ -26,11 +26,13 @@ BitmapImage::BitmapImage() { mImage = std::make_shared(); // create null image mBounds = QRect(0, 0, 0, 0); + mMinBound = true; } BitmapImage::BitmapImage(const BitmapImage& a) : KeyFrame(a) { mBounds = a.mBounds; + mMinBound = a.mMinBound; mImage = std::make_shared(*a.mImage); } @@ -39,25 +41,23 @@ BitmapImage::BitmapImage(const QRect& rectangle, const QColor& colour) mBounds = rectangle; mImage = std::make_shared(mBounds.size(), QImage::Format_ARGB32_Premultiplied); mImage->fill(colour.rgba()); + mMinBound = true; } -BitmapImage::BitmapImage(const QRect& rectangle, const QImage& image) +BitmapImage::BitmapImage(const QPoint& topLeft, const QImage& image) { - mBounds = rectangle.normalized(); - mExtendable = true; + mBounds = QRect(topLeft, image.size()); + mMinBound = false; mImage = std::make_shared(image); - if (mImage->width() != rectangle.width() || mImage->height() != rectangle.height()) - { - qDebug() << "Error instancing bitmapImage."; - } } -BitmapImage::BitmapImage(const QString& path, const QPoint& topLeft) +BitmapImage::BitmapImage(const QPoint& topLeft, const QString& path) { setFileName(path); mImage.reset(); - mBounds = QRect(topLeft, QSize(1,1)); + mBounds = QRect(topLeft, QSize(0,0)); + mMinBound = true; setModified(false); } @@ -69,6 +69,7 @@ void BitmapImage::setImage(QImage* img) { Q_CHECK_PTR(img); mImage.reset(img); + mMinBound = false; modification(); } @@ -76,6 +77,7 @@ void BitmapImage::setImage(QImage* img) BitmapImage& BitmapImage::operator=(const BitmapImage& a) { mBounds = a.mBounds; + mMinBound = a.mMinBound; mImage = std::make_shared(*a.mImage); modification(); return *this; @@ -92,6 +94,7 @@ void BitmapImage::loadFile() { mImage = std::make_shared(fileName()); mBounds.setSize(mImage->size()); + mMinBound = false; } } @@ -105,12 +108,12 @@ void BitmapImage::unloadFile() void BitmapImage::paintImage(QPainter& painter) { - painter.drawImage(topLeft(), *image()); + painter.drawImage(mBounds.topLeft(), *image()); } void BitmapImage::paintImage(QPainter& painter, QImage& image, QRect sourceRect, QRect destRect) { - painter.drawImage(QRect(QPoint(topLeft()), destRect.size()), + painter.drawImage(QRect(mBounds.topLeft(), destRect.size()), image, sourceRect); } @@ -123,35 +126,24 @@ QImage* BitmapImage::image() BitmapImage BitmapImage::copy() { - return BitmapImage(mBounds, *image()); + return BitmapImage(mBounds.topLeft(), *image()); } BitmapImage BitmapImage::copy(QRect rectangle) { - QRect intersection2 = rectangle.translated(-topLeft()); - BitmapImage result = BitmapImage(rectangle, image()->copy(intersection2)); + QRect intersection2 = rectangle.translated(-mBounds.topLeft()); + BitmapImage result = BitmapImage(rectangle.topLeft(), image()->copy(intersection2)); return result; } void BitmapImage::paste(BitmapImage* bitmapImage, QPainter::CompositionMode cm) { - QRect newBoundaries; - - bitmapImage->autoCrop(); if(bitmapImage->width() <= 0 || bitmapImage->height() <= 0) { return; } - if (image()->width() == 0 || image()->height() == 0) - { - newBoundaries = bitmapImage->mBounds; - } - else - { - newBoundaries = mBounds.united(bitmapImage->mBounds); - } - extend(newBoundaries); + setCompositionModeBounds(bitmapImage, cm); QImage* image2 = bitmapImage->image(); @@ -160,95 +152,13 @@ void BitmapImage::paste(BitmapImage* bitmapImage, QPainter::CompositionMode cm) painter.drawImage(bitmapImage->mBounds.topLeft() - mBounds.topLeft(), *image2); painter.end(); - autoCrop(); - modification(); } -void BitmapImage::add(BitmapImage* bitmapImage) -{ - QImage* image2 = bitmapImage->image(); - - QRect newBoundaries; - if (image()->width() == 0 || image()->height() == 0) - { - newBoundaries = bitmapImage->mBounds; - } - else - { - newBoundaries = mBounds.united(bitmapImage->mBounds); - } - extend(newBoundaries); - QPoint offset = bitmapImage->mBounds.topLeft() - mBounds.topLeft(); - for (int y = 0; y < image2->height(); y++) - { - for (int x = 0; x < image2->width(); x++) - { - QRgb p1 = image()->pixel(offset.x() + x, offset.y() + y); - QRgb p2 = image2->pixel(x, y); - - int a1 = qAlpha(p1); - int a2 = qAlpha(p2); - int r1 = qRed(p1); - int r2 = qRed(p2); // remember that the bitmap format is RGB32 Premultiplied - int g1 = qGreen(p1); - int g2 = qGreen(p2); - int b1 = qBlue(p1); - int b2 = qBlue(p2); - - // unite - int a = qMax(a1, a2); - int r = qMax(r1, r2); - int g = qMax(g1, g2); - int b = qMax(b1, b2); - - QRgb mix = qRgba(r, g, b, a); - if (a2 != 0) - { - mImage->setPixel(offset.x() + x, offset.y() + y, mix); - } - } - } - modification(); -} - -void BitmapImage::compareAlpha(BitmapImage* bitmapImage) // this function picks the greater alpha value -{ - QImage* image2 = bitmapImage->image(); - - QRect newBoundaries; - if (image()->width() == 0 || image()->height() == 0) - { - newBoundaries = bitmapImage->mBounds; - } - else - { - newBoundaries = mBounds.united(bitmapImage->mBounds); - } - extend(newBoundaries); - QPoint offset = bitmapImage->mBounds.topLeft() - mBounds.topLeft(); - for (int y = 0; y < image2->height(); y++) - { - for (int x = 0; x < image2->width(); x++) - { - QRgb p1 = image()->pixel(offset.x() + x, offset.y() + y); - QRgb p2 = image2->pixel(x, y); - - int a1 = qAlpha(p1); - int a2 = qAlpha(p2); - - if (a1 <= a2) - { - QRgb mix = qRgba(qRed(p2), qGreen(p2), qBlue(p2), a2); - image()->setPixel(offset.x() + x, offset.y() + y, mix); - } - } - } -} - void BitmapImage::moveTopLeft(QPoint point) { mBounds.moveTopLeft(point); + // Size is unchanged so there is no need to update mBounds modification(); } @@ -286,7 +196,7 @@ BitmapImage BitmapImage::transformed(QRect selection, QTransform transform, bool { transformedImage = selectedPart.image()->transformed(transform); } - return BitmapImage(transform.mapRect(selection), transformedImage); + return BitmapImage(transform.mapRect(selection).normalized().topLeft(), transformedImage); } BitmapImage BitmapImage::transformed(QRect newBoundaries, bool smoothTransform) @@ -300,23 +210,46 @@ BitmapImage BitmapImage::transformed(QRect newBoundaries, bool smoothTransform) return transformedImage; } +/** Update image bounds. + * + * @param[in] newBoundaries the new bounds + * + * Sets this image's bounds to rectangle. + * Modifies mBounds and crops mImage. + */ +void BitmapImage::updateBounds(QRect newBoundaries) +{ + // Check to make sure changes actually need to be made + if (mBounds == newBoundaries) return; + + QImage* newImage = new QImage( newBoundaries.size(), QImage::Format_ARGB32_Premultiplied); + newImage->fill(Qt::transparent); + if (!newImage->isNull()) + { + QPainter painter(newImage); + painter.drawImage(mBounds.topLeft() - newBoundaries.topLeft(), *mImage); + painter.end(); + } + mImage.reset( newImage ); + mBounds = newBoundaries; + mMinBound = false; +} -void BitmapImage::extend(QPoint P) +void BitmapImage::extend(const QPoint &p) { - if (!mBounds.contains(P)) + if (!mBounds.contains(p)) { - extend(QRect(P, QSize(1, 1))); + extend(QRect(p, QSize(1, 1))); } } void BitmapImage::extend(QRect rectangle) { - if (!mExtendable) return; if (rectangle.width() <= 0) rectangle.setWidth(1); if (rectangle.height() <= 0) rectangle.setHeight(1); if (mBounds.contains(rectangle)) { - // nothing + // Do nothing } else { @@ -336,6 +269,92 @@ void BitmapImage::extend(QRect rectangle) } } +/** Updates the bounds after a drawImage operation with the composition mode cm. + * + * @param[in] source The source image used for the drawImage call. + * @param[in] cm The composition mode that will be used for the draw image + * + * @see BitmapImage::setCompositionModeBounds(BitmapImage, QPainter::CompositionMode) + */ +void BitmapImage::setCompositionModeBounds(BitmapImage *source, QPainter::CompositionMode cm) +{ + if (source) + { + setCompositionModeBounds(source->mBounds, source->mMinBound, cm); + } +} + +/** Updates the bounds after a draw operation with the composition mode cm. + * + * @param[in] sourceBounds The bounds of the source used for drawcall. + * @param[in] cm The composition mode that will be used for the draw image + * + * For a call to draw image of a QPainter (initialized with mImage) with an argument + * of source, this function intelligently calculates the bounds. It will attempt to + * preserve minimum bounds based on the composition mode. + * + * Some minimal bounds can be determined solely by the + * minimal bounds of this and source, depending on the value of cm. + * Here is a summary of such cases: + * Depends on destination only: Destination, SourceAtop + * Depnds on source only: Source, DestinationAtop + * Depends on both: SourceOver, DestinationOver + * + * @warning The draw operation described by the arguments of this + * function needs to be called after this function is run, + * or the bounds will be out of sync. If mBounds is null, + * no draw operation needs to be performed. + */ +void BitmapImage::setCompositionModeBounds(QRect sourceBounds, bool isSourceMinBounds, QPainter::CompositionMode cm) +{ + QRect newBoundaries; + /*if ((cm == QPainter::CompositionMode_Destination || cm == QPainter::CompositionMode_SourceAtop) && mMinBound) + { + // The bounds of the result of Destination and SourceAtop + // modes depend entirely on the destination bounds. + newBoundaries = mBounds; + // mMinBound is already true + } + else if ((cm == QPainter::CompositionMode_Source || cm == QPainter::CompositionMode_DestinationAtop) && isSourceMinBounds) + { + // The bounds of the result of Source and DestinationAtop + // modes depend entirely on the source bounds. + newBoundaries = sourceBounds; + mMinBound = true; + } + else + { + // If it's not one of the above cases, create a union of the two bounds. + // This contains the minimum bounds, but may be larger. + newBoundaries = mBounds.united(sourceBounds); + + if((cm == QPainter::CompositionMode_SourceOver || cm == QPainter::CompositionMode_DestinationOver) && mMinBound && isSourceMinBounds) + { + // If the mode is SourceOut or DestinationOut, then the minimal bound is + // the minimal bound of destination U the minimal bound of source + // which is what we just did above, therefore the current bounds are minimal + mMinBound = true; + } + else { + // There's not enough information to determine if the bounds are minimal + mMinBound = false; + } + }*/ + + // TEMPORARY + if ( mImage->width() == 0 || mImage->height() == 0 ) + { + newBoundaries = sourceBounds; + } + else + { + newBoundaries = mBounds.united(sourceBounds); + } + mMinBound = false; + + updateBounds(newBoundaries); +} + /** Removes any transparent borders by reducing the boundaries. * * This function reduces the bounds of an image until the top and @@ -347,9 +366,18 @@ void BitmapImage::extend(QRect rectangle) * @pre mBounds.size() == mImage->size() * @post Either the first and last rows and columns all contain a * pixel with alpha > 0 or mBounds.isEmpty() == true + * @post isMinimallyBounded() == true */ void BitmapImage::autoCrop() { + // Exit if current bounds are null + if (mBounds.isEmpty()) return; + + Q_ASSERT(mBounds.size() == mImage->size()); + + // Exit if already min bounded + if (mMinBound) return; + // Get image properties const int width = mImage->width(); @@ -485,32 +513,14 @@ void BitmapImage::autoCrop() } } - // If any of the rel* variables have changed, then update mBounds and mImage - if (relTop != 0 || - relLeft != 0 || - relRight != mBounds.width()-1 || - relBottom != mBounds.height()-1) - { - // Create new QRect for bounds by normalizing mBounds and then applying the rel offsets - QRect newBoundaries = mBounds.normalized().adjusted(relLeft, relTop, relRight - mBounds.width() + 1, relBottom - mBounds.height() + 1); - // Create a new image with this same size - QImage* newImage = new QImage( newBoundaries.size(), QImage::Format_ARGB32_Premultiplied); - // Make the image transparent - newImage->fill(Qt::transparent); - // If the image initialized properly - // (probably true unless the newBoundaries width or height <= 0) - if (!newImage->isNull()) - { - // Copy mImage to the new image with the updated size - QPainter painter(newImage); - painter.drawImage(mBounds.topLeft() - newBoundaries.topLeft(), *mImage); - painter.end(); - } - // Apply the resized image to mImage - mImage.reset( newImage ); - // Apply the boundaries to mBounds - mBounds = newBoundaries; - } + qDebug() << "Original" << mBounds; + qDebug() << "Autocrop" << relLeft << relTop << relRight - mBounds.width() + 1 << relBottom - mBounds.height() + 1; + // Update mBounds and mImage if necessary + updateBounds(mBounds.adjusted(relLeft, relTop, relRight - mBounds.width() + 1, relBottom - mBounds.height() + 1)); + + qDebug() << "New bounds" << mBounds; + + mMinBound = true; } QRgb BitmapImage::pixel(int x, int y) @@ -518,11 +528,11 @@ QRgb BitmapImage::pixel(int x, int y) return pixel(QPoint(x, y)); } -QRgb BitmapImage::pixel(QPoint P) +QRgb BitmapImage::pixel(QPoint p) { QRgb result = qRgba(0, 0, 0, 0); // black - if (mBounds.contains(P)) - result = image()->pixel(P - topLeft()); + if (mBounds.contains(p)) + result = image()->pixel(p - mBounds.topLeft()); return result; } @@ -531,12 +541,12 @@ void BitmapImage::setPixel(int x, int y, QRgb colour) setPixel(QPoint(x, y), colour); } -void BitmapImage::setPixel(QPoint P, QRgb colour) +void BitmapImage::setPixel(QPoint p, QRgb colour) { - extend(P); - if (mBounds.contains(P)) + setCompositionModeBounds(QRect(p, QSize(1,1)), true, QPainter::CompositionMode_SourceOver); + if (mBounds.contains(p)) { - image()->setPixel(P - topLeft(), colour); + image()->setPixel(p - mBounds.topLeft(), colour); } modification(); } @@ -545,14 +555,14 @@ void BitmapImage::setPixel(QPoint P, QRgb colour) void BitmapImage::drawLine(QPointF P1, QPointF P2, QPen pen, QPainter::CompositionMode cm, bool antialiasing) { int width = 2 + pen.width(); - extend(QRect(P1.toPoint(), P2.toPoint()).normalized().adjusted(-width, -width, width, width)); + setCompositionModeBounds(QRect(P1.toPoint(), P2.toPoint()).normalized().adjusted(-width, -width, width, width), true, cm); if (!image()->isNull()) { QPainter painter(image()); painter.setCompositionMode(cm); painter.setRenderHint(QPainter::Antialiasing, antialiasing); painter.setPen(pen); - painter.drawLine(P1 - topLeft(), P2 - topLeft()); + painter.drawLine(P1 - mBounds.topLeft(), P2 - mBounds.topLeft()); painter.end(); } modification(); @@ -561,12 +571,12 @@ void BitmapImage::drawLine(QPointF P1, QPointF P2, QPen pen, QPainter::Compositi void BitmapImage::drawRect(QRectF rectangle, QPen pen, QBrush brush, QPainter::CompositionMode cm, bool antialiasing) { int width = pen.width(); - extend(rectangle.adjusted(-width, -width, width, width).toRect()); + setCompositionModeBounds(rectangle.adjusted(-width, -width, width, width).toRect(), true, cm); if (brush.style() == Qt::RadialGradientPattern) { QRadialGradient* gradient = (QRadialGradient*)brush.gradient(); - gradient->setCenter(gradient->center() - topLeft()); - gradient->setFocalPoint(gradient->focalPoint() - topLeft()); + gradient->setCenter(gradient->center() - mBounds.topLeft()); + gradient->setFocalPoint(gradient->focalPoint() - mBounds.topLeft()); } if (!image()->isNull()) { @@ -575,7 +585,7 @@ void BitmapImage::drawRect(QRectF rectangle, QPen pen, QBrush brush, QPainter::C painter.setRenderHint(QPainter::Antialiasing, antialiasing); painter.setPen(pen); painter.setBrush(brush); - painter.drawRect(rectangle.translated(-topLeft())); + painter.drawRect(rectangle.translated(-mBounds.topLeft())); painter.end(); } modification(); @@ -584,12 +594,12 @@ void BitmapImage::drawRect(QRectF rectangle, QPen pen, QBrush brush, QPainter::C void BitmapImage::drawEllipse(QRectF rectangle, QPen pen, QBrush brush, QPainter::CompositionMode cm, bool antialiasing) { int width = pen.width(); - extend(rectangle.adjusted(-width, -width, width, width).toRect()); + setCompositionModeBounds(rectangle.adjusted(-width, -width, width, width).toRect(), true, cm); if (brush.style() == Qt::RadialGradientPattern) { QRadialGradient* gradient = (QRadialGradient*)brush.gradient(); - gradient->setCenter(gradient->center() - topLeft()); - gradient->setFocalPoint(gradient->focalPoint() - topLeft()); + gradient->setCenter(gradient->center() - mBounds.topLeft()); + gradient->setFocalPoint(gradient->focalPoint() - mBounds.topLeft()); } if (!image()->isNull()) { @@ -599,7 +609,7 @@ void BitmapImage::drawEllipse(QRectF rectangle, QPen pen, QBrush brush, QPainter painter.setPen(pen); painter.setBrush(brush); painter.setCompositionMode(cm); - painter.drawEllipse(rectangle.translated(-topLeft())); + painter.drawEllipse(rectangle.translated(-mBounds.topLeft())); painter.end(); } modification(); @@ -611,7 +621,7 @@ void BitmapImage::drawPath(QPainterPath path, QPen pen, QBrush brush, int width = pen.width(); // qreal inc = 1.0 + width / 20.0; - extend(path.controlPointRect().adjusted(-width, -width, width, width).toRect()); + setCompositionModeBounds(path.controlPointRect().adjusted(-width, -width, width, width).toRect(), true, cm); if (!image()->isNull()) { @@ -620,7 +630,7 @@ void BitmapImage::drawPath(QPainterPath path, QPen pen, QBrush brush, painter.setRenderHint(QPainter::Antialiasing, antialiasing); painter.setPen(pen); painter.setBrush(brush); - painter.setTransform(QTransform().translate(-topLeft().x(), -topLeft().y())); + painter.setTransform(QTransform().translate(-mBounds.left(), -mBounds.top())); painter.setMatrixEnabled(true); if (path.length() > 0) { @@ -679,6 +689,7 @@ void BitmapImage::clear() { mImage = std::make_shared(); // null image mBounds = QRect(0, 0, 0, 0); + mMinBound = true; modification(); } @@ -687,7 +698,7 @@ QRgb BitmapImage::constScanLine(int x, int y) QRgb result = qRgba(0, 0, 0, 0); if (mBounds.contains(QPoint(x, y))) { - result = *(reinterpret_cast(mImage->constScanLine(y - topLeft().y())) + x - topLeft().x()); + result = *(reinterpret_cast(mImage->constScanLine(y - mBounds.top())) + x - mBounds.left()); } return result; } @@ -698,7 +709,7 @@ void BitmapImage::scanLine(int x, int y, QRgb colour) if (mBounds.contains(QPoint(x, y))) { // Make sure color is premultiplied before calling - *(reinterpret_cast(image()->scanLine(y - topLeft().y())) + x - topLeft().x()) = + *(reinterpret_cast(image()->scanLine(y - mBounds.top())) + x - mBounds.left()) = qRgba( qRed(colour), qGreen(colour), @@ -710,7 +721,9 @@ void BitmapImage::scanLine(int x, int y, QRgb colour) void BitmapImage::clear(QRect rectangle) { QRect clearRectangle = mBounds.intersected(rectangle); - clearRectangle.moveTopLeft(clearRectangle.topLeft() - topLeft()); + clearRectangle.moveTopLeft(clearRectangle.topLeft() - mBounds.topLeft()); + + setCompositionModeBounds(clearRectangle, true, QPainter::CompositionMode_Clear); QPainter painter(image()); painter.setCompositionMode(QPainter::CompositionMode_Clear); @@ -811,12 +824,12 @@ void BitmapImage::floodFill(BitmapImage* targetImage, xTemp = point.x(); newPlacedColor = replaceImage->constScanLine(xTemp, point.y()); - while (xTemp >= targetImage->topLeft().x() && + while (xTemp >= targetImage->mBounds.left() && compareColor(targetImage->constScanLine(xTemp, point.y()), oldColor, tolerance, cache.data())) xTemp--; xTemp++; spanLeft = spanRight = false; - while (xTemp <= targetImage->right() && + while (xTemp <= targetImage->mBounds.right() && compareColor(targetImage->constScanLine(xTemp, point.y()), oldColor, tolerance, cache.data()) && newPlacedColor != newColor) { @@ -824,28 +837,28 @@ void BitmapImage::floodFill(BitmapImage* targetImage, // Set pixel color replaceImage->scanLine(xTemp, point.y(), newColor); - if (!spanLeft && (point.y() > targetImage->top()) && + if (!spanLeft && (point.y() > targetImage->mBounds.top()) && compareColor(targetImage->constScanLine(xTemp, point.y() - 1), oldColor, tolerance, cache.data())) { queue.append(QPoint(xTemp, point.y() - 1)); spanLeft = true; } - else if (spanLeft && (point.y() > targetImage->top()) && + else if (spanLeft && (point.y() > targetImage->mBounds.top()) && !compareColor(targetImage->constScanLine(xTemp, point.y() - 1), oldColor, tolerance, cache.data())) { spanLeft = false; } - if (!spanRight && point.y() < targetImage->bottom() && + if (!spanRight && point.y() < targetImage->mBounds.bottom() && compareColor(targetImage->constScanLine(xTemp, point.y() + 1), oldColor, tolerance, cache.data())) { queue.append(QPoint(xTemp, point.y() + 1)); spanRight = true; } - else if (spanRight && point.y() < targetImage->bottom() && + else if (spanRight && point.y() < targetImage->mBounds.bottom() && !compareColor(targetImage->constScanLine(xTemp, point.y() + 1), oldColor, tolerance, cache.data())) { spanRight = false; } - Q_ASSERT(queue.count() < (targetImage->width() * targetImage->height())); + Q_ASSERT(queue.count() < (targetImage->mBounds.width() * targetImage->mBounds.height())); xTemp++; } } diff --git a/core_lib/src/graphics/bitmap/bitmapimage.h b/core_lib/src/graphics/bitmap/bitmapimage.h index 2a74baf0b..cc6db59fe 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.h +++ b/core_lib/src/graphics/bitmap/bitmapimage.h @@ -27,9 +27,9 @@ class BitmapImage : public KeyFrame public: BitmapImage(); BitmapImage(const BitmapImage&); - BitmapImage(const QRect& boundaries, const QColor& colour); - BitmapImage(const QRect& boundaries, const QImage& image); - BitmapImage(const QString& path, const QPoint& topLeft); + BitmapImage(const QRect &rectangle, const QColor& colour); + BitmapImage(const QPoint& topLeft, const QImage& image); + BitmapImage(const QPoint& topLeft, const QString& path); ~BitmapImage(); BitmapImage& operator=(const BitmapImage& a); @@ -60,14 +60,12 @@ class BitmapImage : public KeyFrame bool contains(QPoint P) { return mBounds.contains(P); } bool contains(QPointF P) { return contains(P.toPoint()); } - void extend(QPoint P); - void extend(QRect rectangle); void autoCrop(); QRgb pixel(int x, int y); - QRgb pixel(QPoint P); + QRgb pixel(QPoint p); void setPixel(int x, int y, QRgb colour); - void setPixel(QPoint P, QRgb colour); + void setPixel(QPoint p, QRgb colour); QRgb constScanLine(int x, int y); void scanLine(int x, int y, QRgb colour); void clear(); @@ -82,26 +80,47 @@ class BitmapImage : public KeyFrame void drawEllipse(QRectF rectangle, QPen pen, QBrush brush, QPainter::CompositionMode cm, bool antialiasing); void drawPath(QPainterPath path, QPen pen, QBrush brush, QPainter::CompositionMode cm, bool antialiasing); - QPoint topLeft() { return mBounds.topLeft(); } - QPoint topRight() { return mBounds.topRight(); } - QPoint bottomLeft() { return mBounds.bottomLeft(); } - QPoint bottomRight() { return mBounds.bottomRight(); } - int left() { return mBounds.left(); } - int right() { return mBounds.right(); } - int top() { return mBounds.top(); } - int bottom() { return mBounds.bottom(); } - int width() { return mBounds.width(); } - int height() { return mBounds.height(); } - QSize size() { return mBounds.size(); } - - QRect& bounds() { return mBounds; } + QPoint topLeft() { autoCrop(); return mBounds.topLeft(); } + QPoint topRight() { autoCrop(); return mBounds.topRight(); } + QPoint bottomLeft() { autoCrop(); return mBounds.bottomLeft(); } + QPoint bottomRight() { autoCrop(); return mBounds.bottomRight(); } + int left() { autoCrop(); return mBounds.left(); } + int right() { autoCrop(); return mBounds.right(); } + int top() { autoCrop(); return mBounds.top(); } + int bottom() { autoCrop(); return mBounds.bottom(); } + int width() { autoCrop(); return mBounds.width(); } + int height() { autoCrop(); return mBounds.height(); } + QSize size() { autoCrop(); return mBounds.size(); } + + QRect& bounds() { autoCrop(); return mBounds; } + + /** Determines if the BitmapImage is minimally bounded. + * + * A BitmapImage is minimally bounded if all edges contain + * at least 1 non-transparent pixel (alpha > 0). In other words, + * the size of the image cannot be decreased without + * cropping visible data. + * + * @return True only if bounds() is the minimal bounding box + * for the contained image. + */ + bool isMinimallyBounded() const { return mMinBound; } Status writeFile(const QString& filename); +protected: + void updateBounds(QRect rectangle); + void extend(const QPoint& p); + void extend(QRect rectangle); + + void setCompositionModeBounds(BitmapImage *source, QPainter::CompositionMode cm); + void setCompositionModeBounds(QRect sourceBounds, bool isSourceMinBounds, QPainter::CompositionMode cm); + private: std::shared_ptr< QImage > mImage; QRect mBounds; - bool mExtendable = true; + /** @see isMinimallyBounded() */ + bool mMinBound; }; #endif diff --git a/core_lib/src/interface/editor.cpp b/core_lib/src/interface/editor.cpp index 504c4b38c..ba73c4787 100644 --- a/core_lib/src/interface/editor.cpp +++ b/core_lib/src/interface/editor.cpp @@ -754,10 +754,7 @@ bool Editor::importBitmapImage(QString filePath, int space) } BitmapImage* bitmapImage = layer->getBitmapImageAtFrame(currentFrame()); - QRect boundaries = img.rect(); - boundaries.moveTopLeft(mScribbleArea->getCentralPoint().toPoint() - QPoint(boundaries.width() / 2, boundaries.height() / 2)); - - BitmapImage importedBitmapImage{ boundaries, img }; + BitmapImage importedBitmapImage(mScribbleArea->getCentralPoint().toPoint() - QPoint(img.width() / 2, img.height() / 2), img); bitmapImage->paste(&importedBitmapImage); if (space > 1) { diff --git a/core_lib/src/structure/layerbitmap.cpp b/core_lib/src/structure/layerbitmap.cpp index 4f38c62da..d0585f807 100644 --- a/core_lib/src/structure/layerbitmap.cpp +++ b/core_lib/src/structure/layerbitmap.cpp @@ -47,7 +47,7 @@ BitmapImage* LayerBitmap::getLastBitmapImageAtFrame(int frameNumber, int increme void LayerBitmap::loadImageAtFrame(QString path, QPoint topLeft, int frameNumber) { - BitmapImage* pKeyFrame = new BitmapImage(path, topLeft); + BitmapImage* pKeyFrame = new BitmapImage(topLeft, path); pKeyFrame->setPos(frameNumber); loadKey(pKeyFrame); } diff --git a/tests/src/test_bitmapimage.cpp b/tests/src/test_bitmapimage.cpp index cc14de586..b1c561286 100644 --- a/tests/src/test_bitmapimage.cpp +++ b/tests/src/test_bitmapimage.cpp @@ -91,19 +91,4 @@ TEST_CASE("BitmapImage functions") REQUIRE(b->width() == 50); REQUIRE(b->height() == 50); } - - SECTION("extend()") - { - auto b = std::make_shared(QRect(0, 0, 50, 50), Qt::red); - - // before - REQUIRE(b->topLeft() == QPoint(0, 0)); - REQUIRE(b->size() == QSize(50, 50)); - - b->extend(QPoint(-10, -10)); - - // after - REQUIRE(b->topLeft() == QPoint(-10, -10)); - REQUIRE(b->size() == QSize(60, 60)); - } } From 5bed48a3dc309189d05ccca9543cc647a08b9309 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Sat, 25 Aug 2018 23:38:00 -0600 Subject: [PATCH 166/184] Improve autocropping --- core_lib/src/graphics/bitmap/bitmapimage.cpp | 76 ++++++++------------ core_lib/src/interface/scribblearea.cpp | 6 +- 2 files changed, 31 insertions(+), 51 deletions(-) diff --git a/core_lib/src/graphics/bitmap/bitmapimage.cpp b/core_lib/src/graphics/bitmap/bitmapimage.cpp index 150c3d76f..e5be301df 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.cpp +++ b/core_lib/src/graphics/bitmap/bitmapimage.cpp @@ -233,6 +233,8 @@ void BitmapImage::updateBounds(QRect newBoundaries) mImage.reset( newImage ); mBounds = newBoundaries; mMinBound = false; + + modification(); } void BitmapImage::extend(const QPoint &p) @@ -287,18 +289,16 @@ void BitmapImage::setCompositionModeBounds(BitmapImage *source, QPainter::Compos /** Updates the bounds after a draw operation with the composition mode cm. * * @param[in] sourceBounds The bounds of the source used for drawcall. + * @param[in] isSourceMinBounds Is sourceBounds the minimal bounds for the source image * @param[in] cm The composition mode that will be used for the draw image * * For a call to draw image of a QPainter (initialized with mImage) with an argument * of source, this function intelligently calculates the bounds. It will attempt to * preserve minimum bounds based on the composition mode. * - * Some minimal bounds can be determined solely by the - * minimal bounds of this and source, depending on the value of cm. - * Here is a summary of such cases: - * Depends on destination only: Destination, SourceAtop - * Depnds on source only: Source, DestinationAtop - * Depends on both: SourceOver, DestinationOver + * This works baed on the principle that some minimal bounds can be determined + * solely by the minimal bounds of this and source, depending on the value of cm. + * Some composition modes only expand, or have no affect on the bounds. * * @warning The draw operation described by the arguments of this * function needs to be called after this function is run, @@ -308,49 +308,31 @@ void BitmapImage::setCompositionModeBounds(BitmapImage *source, QPainter::Compos void BitmapImage::setCompositionModeBounds(QRect sourceBounds, bool isSourceMinBounds, QPainter::CompositionMode cm) { QRect newBoundaries; - /*if ((cm == QPainter::CompositionMode_Destination || cm == QPainter::CompositionMode_SourceAtop) && mMinBound) + switch(cm) { - // The bounds of the result of Destination and SourceAtop - // modes depend entirely on the destination bounds. + case QPainter::CompositionMode_Destination: + case QPainter::CompositionMode_SourceAtop: + // The Destination and SourceAtop modes + // do not change the bounds from destination. newBoundaries = mBounds; - // mMinBound is already true - } - else if ((cm == QPainter::CompositionMode_Source || cm == QPainter::CompositionMode_DestinationAtop) && isSourceMinBounds) - { - // The bounds of the result of Source and DestinationAtop - // modes depend entirely on the source bounds. - newBoundaries = sourceBounds; - mMinBound = true; - } - else - { + // mMinBound remains the same + break; + case QPainter::CompositionMode_SourceIn: + case QPainter::CompositionMode_DestinationIn: + case QPainter::CompositionMode_Clear: + case QPainter::CompositionMode_DestinationOut: + // The bounds of the result of SourceIn, DestinationIn, Clear, and DestinationOut + // modes are no larger than the destination bounds + newBoundaries = mBounds; + mMinBound = false; + break; + default: // If it's not one of the above cases, create a union of the two bounds. - // This contains the minimum bounds, but may be larger. - newBoundaries = mBounds.united(sourceBounds); - - if((cm == QPainter::CompositionMode_SourceOver || cm == QPainter::CompositionMode_DestinationOver) && mMinBound && isSourceMinBounds) - { - // If the mode is SourceOut or DestinationOut, then the minimal bound is - // the minimal bound of destination U the minimal bound of source - // which is what we just did above, therefore the current bounds are minimal - mMinBound = true; - } - else { - // There's not enough information to determine if the bounds are minimal - mMinBound = false; - } - }*/ - - // TEMPORARY - if ( mImage->width() == 0 || mImage->height() == 0 ) - { - newBoundaries = sourceBounds; - } - else - { + // This contains the minimum bounds, if both the destination and source + // use their respective minimum bounds. newBoundaries = mBounds.united(sourceBounds); + mMinBound = mMinBound && isSourceMinBounds; } - mMinBound = false; updateBounds(newBoundaries); } @@ -513,12 +495,12 @@ void BitmapImage::autoCrop() } } - qDebug() << "Original" << mBounds; - qDebug() << "Autocrop" << relLeft << relTop << relRight - mBounds.width() + 1 << relBottom - mBounds.height() + 1; + //qDebug() << "Original" << mBounds; + //qDebug() << "Autocrop" << relLeft << relTop << relRight - mBounds.width() + 1 << relBottom - mBounds.height() + 1; // Update mBounds and mImage if necessary updateBounds(mBounds.adjusted(relLeft, relTop, relRight - mBounds.width() + 1, relBottom - mBounds.height() + 1)); - qDebug() << "New bounds" << mBounds; + //qDebug() << "New bounds" << mBounds; mMinBound = true; } diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index 27f1364d9..1b096b433 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -688,7 +688,7 @@ void ScribbleArea::paintBitmapBuffer() case PENCIL: if (getTool(currentTool()->type())->properties.preserveAlpha) { - cm = QPainter::CompositionMode_SourceAtop; + cm = QPainter::CompositionMode_SourceOver; } break; default: //nothing @@ -1204,13 +1204,12 @@ void ScribbleArea::drawBrush(QPointF thePoint, qreal brushWidth, qreal mOffset, { QRectF rectangle(thePoint.x() - 0.5 * brushWidth, thePoint.y() - 0.5 * brushWidth, brushWidth, brushWidth); - BitmapImage gradientImg; if (usingFeather) { QRadialGradient radialGrad(thePoint, 0.5 * brushWidth); setGaussianGradient(radialGrad, fillColour, opacity, mOffset); - gradientImg.drawEllipse(rectangle, Qt::NoPen, radialGrad, + mBufferImg->drawEllipse(rectangle, Qt::NoPen, radialGrad, QPainter::CompositionMode_SourceOver, false); } else @@ -1218,7 +1217,6 @@ void ScribbleArea::drawBrush(QPointF thePoint, qreal brushWidth, qreal mOffset, mBufferImg->drawEllipse(rectangle, Qt::NoPen, QBrush(fillColour, Qt::SolidPattern), QPainter::CompositionMode_SourceOver, useAA); } - mBufferImg->paste(&gradientImg); } /** From e08bc9c6bc274be35c56ec010d51d858343a137d Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Mon, 27 Aug 2018 11:11:06 +1000 Subject: [PATCH 167/184] Let FileManager handles the absence of camera layers --- core_lib/src/structure/filemanager.cpp | 9 ++++++++- core_lib/src/structure/object.cpp | 9 +-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core_lib/src/structure/filemanager.cpp b/core_lib/src/structure/filemanager.cpp index 93dd3edf5..b7bc52d86 100644 --- a/core_lib/src/structure/filemanager.cpp +++ b/core_lib/src/structure/filemanager.cpp @@ -23,6 +23,7 @@ GNU General Public License for more details. #include "qminiz.h" #include "fileformat.h" #include "object.h" +#include "layercamera.h" QString openErrorTitle = QObject::tr("Could not open file"); @@ -617,6 +618,12 @@ Status FileManager::verifyObject(Object* obj) { obj->data()->setCurrentLayer(maxLayer - 1); } - + + // Must have at least 1 camera layer + std::vector camLayers = obj->getLayersByType(); + if (camLayers.empty()) + { + obj->addNewCameraLayer(); + } return Status::OK; } diff --git a/core_lib/src/structure/object.cpp b/core_lib/src/structure/object.cpp index 20d38c8a4..cfc7a00d5 100644 --- a/core_lib/src/structure/object.cpp +++ b/core_lib/src/structure/object.cpp @@ -84,7 +84,6 @@ bool Object::loadXML(QDomElement docElem, ProgressCallback progressForward) int layerNumber = -1; const QString dataDirPath = mDataDirPath; - bool hasCameraLayer = false; for (QDomNode node = docElem.firstChild(); !node.isNull(); node = node.nextSibling()) { @@ -96,19 +95,13 @@ bool Object::loadXML(QDomElement docElem, ProgressCallback progressForward) case Layer::BITMAP: addNewBitmapLayer(); break; case Layer::VECTOR: addNewVectorLayer(); break; case Layer::SOUND: addNewSoundLayer(); break; - case Layer::CAMERA: addNewCameraLayer(); hasCameraLayer = true; break; + case Layer::CAMERA: addNewCameraLayer(); break; default: Q_ASSERT(false); break; } layerNumber++; getLayer(layerNumber)->loadDomElement(element, dataDirPath, progressForward); } } - - // Must have at least 1 camera layer - if(!hasCameraLayer) { - addNewCameraLayer(); - } - return true; } From ee13b0c66817d011aab4d94514a0dab3d14c40ee Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Mon, 27 Aug 2018 11:12:32 +1000 Subject: [PATCH 168/184] Fix unit tests --- tests/src/test_filemanager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/src/test_filemanager.cpp b/tests/src/test_filemanager.cpp index 9db23867d..4905d36a9 100644 --- a/tests/src/test_filemanager.cpp +++ b/tests/src/test_filemanager.cpp @@ -108,7 +108,7 @@ TEST_CASE("FileManager Loading XML Tests") REQUIRE(o != nullptr); REQUIRE(fm.error().ok()); - REQUIRE(o->getLayerCount() == 0); + REQUIRE(o->getLayerCount() == 1); // have at least one cam layer delete o; } @@ -134,7 +134,7 @@ TEST_CASE("FileManager Loading XML Tests") FileManager fm; Object* obj = fm.load(theXML.fileName()); - REQUIRE(obj->getLayerCount() == 1); + REQUIRE(obj->getLayerCount() == 2); // one bitmap layer and one default cam layer REQUIRE(obj->getLayer(0)->name() == "MyLayer"); REQUIRE(obj->getLayer(0)->id() == 5); REQUIRE(obj->getLayer(0)->visible() == true); From abd57d15d29c399aab3c347c5aefcf62a615d116 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Fri, 17 Aug 2018 17:21:12 +1000 Subject: [PATCH 169/184] Introduce a pre-save step to handle the frame lost of moved bitmap frames --- core_lib/src/interface/editor.cpp | 1 - core_lib/src/structure/filemanager.cpp | 1 + core_lib/src/structure/keyframe.h | 3 -- core_lib/src/structure/layer.h | 2 + core_lib/src/structure/layerbitmap.cpp | 57 +++++++++++++++++--------- core_lib/src/structure/layerbitmap.h | 4 +- 6 files changed, 42 insertions(+), 26 deletions(-) diff --git a/core_lib/src/interface/editor.cpp b/core_lib/src/interface/editor.cpp index ba73c4787..0899cbf56 100644 --- a/core_lib/src/interface/editor.cpp +++ b/core_lib/src/interface/editor.cpp @@ -37,7 +37,6 @@ GNU General Public License for more details. #include "layervector.h" #include "layercamera.h" #include "backupelement.h" -#include "activeframepool.h" #include "colormanager.h" #include "toolmanager.h" diff --git a/core_lib/src/structure/filemanager.cpp b/core_lib/src/structure/filemanager.cpp index b7bc52d86..0b7344052 100644 --- a/core_lib/src/structure/filemanager.cpp +++ b/core_lib/src/structure/filemanager.cpp @@ -302,6 +302,7 @@ Status FileManager::save(Object* object, QString sFileName) for (int i = 0; i < numLayers; ++i) { Layer* layer = object->getLayer(i); + dd << QString("Layer[%1] = [id=%2, name=%3, type=%4]").arg(i).arg(layer->id()).arg(layer->name()).arg(layer->type()); Status st = layer->save(sDataFolder, zippedFiles, [this] { progressForward(); }); diff --git a/core_lib/src/structure/keyframe.h b/core_lib/src/structure/keyframe.h index 6c958b723..8922a7836 100644 --- a/core_lib/src/structure/keyframe.h +++ b/core_lib/src/structure/keyframe.h @@ -48,8 +48,6 @@ class KeyFrame QString fileName() const { return mAttachedFileName; } void setFileName(QString strFileName) { mAttachedFileName = strFileName; } - bool hasBeenRenamed() const { return mHasBeenRenamed; } - void setRenamed(bool b) { mHasBeenRenamed = b; } void addEventListener(KeyFrameEventListener*); void removeEventListner(KeyFrameEventListener*); @@ -63,7 +61,6 @@ class KeyFrame int mLength = 1; bool mIsModified = true; bool mIsSelected = false; - bool mHasBeenRenamed = false; QString mAttachedFileName; std::vector mEventListeners; diff --git a/core_lib/src/structure/layer.h b/core_lib/src/structure/layer.h index 6f53dc07a..2b076bd41 100644 --- a/core_lib/src/structure/layer.h +++ b/core_lib/src/structure/layer.h @@ -23,6 +23,7 @@ GNU General Public License for more details. #include #include #include +#include "pencilerror.h" class QMouseEvent; class KeyFrame; @@ -108,6 +109,7 @@ class Layer : public QObject bool moveSelectedFrames(int offset); Status save(const QString& sDataFolder, QStringList& attachedFiles, ProgressCallback progressStep); + virtual Status presave(const QString& sDataFolder) { Q_UNUSED(sDataFolder); return Status::SAFE; } // graphic representation -- could be put in another class void paintTrack(QPainter& painter, TimeLineCells* cells, int x, int y, int width, int height, bool selected, int frameSize); diff --git a/core_lib/src/structure/layerbitmap.cpp b/core_lib/src/structure/layerbitmap.cpp index d0585f807..549847457 100644 --- a/core_lib/src/structure/layerbitmap.cpp +++ b/core_lib/src/structure/layerbitmap.cpp @@ -65,18 +65,7 @@ Status LayerBitmap::saveKeyFrameFile(KeyFrame* keyframe, QString path) return Status::SAFE; } - if (bitmapImage->fileName().isEmpty()) - { - bitmapImage->setFileName(strFilePath); - } - else if(strFilePath != bitmapImage->fileName()) - { - bitmapImage->setFileName(bitmapImage->fileName()); - } - else { - bitmapImage->setFileName(strFilePath); - } - bitmapImage->setRenamed(true); + bitmapImage->setFileName(strFilePath); Status st = bitmapImage->writeFile(strFilePath); if (!st.ok()) @@ -103,6 +92,41 @@ KeyFrame* LayerBitmap::createKeyFrame(int position, Object*) return b; } +Status LayerBitmap::presave(const QString& sDataFolder) +{ + // handles those moved keys but note loaded yet + std::vector bitmapArray; + foreachKeyFrame([&bitmapArray](KeyFrame* key) + { + auto bitmap = static_cast(key); + // null image + modified => the keyframe has been moved, but users didn't draw on it. + if (bitmap->image()->isNull() && bitmap->isModified()) + { + bitmapArray.push_back(bitmap); + } + }); + + for (BitmapImage* b : bitmapArray) + { + if (b->fileName() != fileName(b)) + { + QString tmpName = QString::asprintf("t_%03d.%03d.png", id(), b->pos()); + QFile::rename(b->fileName(), tmpName); + b->setFileName(tmpName); + } + } + + for (BitmapImage* b : bitmapArray) + { + if (QFile::exists(fileName(b))) + QFile::remove(fileName(b)); + + QFile::rename(b->fileName(), fileName(b)); + } + + return Status::OK; +} + QString LayerBitmap::fileName(KeyFrame* key) const { return QString::asprintf("%03d.%03d.png", id(), key->pos()); @@ -138,14 +162,7 @@ QDomElement LayerBitmap::createDomElement(QDomDocument& doc) imageTag.setAttribute("topLeftY", pImg->topLeft().y()); layerTag.appendChild(imageTag); - if (!pImg->hasBeenRenamed()) - { - Q_ASSERT(QFileInfo(pKeyFrame->fileName()).fileName() == fileName(pKeyFrame)); - } - else - { - pImg->setRenamed(false); - } + Q_ASSERT(QFileInfo(pKeyFrame->fileName()).fileName() == fileName(pKeyFrame)); }); return layerTag; diff --git a/core_lib/src/structure/layerbitmap.h b/core_lib/src/structure/layerbitmap.h index 8376b4ede..57edf1e93 100644 --- a/core_lib/src/structure/layerbitmap.h +++ b/core_lib/src/structure/layerbitmap.h @@ -29,10 +29,9 @@ class LayerBitmap : public Layer LayerBitmap(Object* object); ~LayerBitmap(); - void loadImageAtFrame(QString strFilePath, QPoint topLeft, int frameNumber); - QDomElement createDomElement(QDomDocument& doc) override; void loadDomElement(QDomElement element, QString dataDirPath, ProgressCallback progressStep) override; + Status presave(const QString& sDataFolder) override; BitmapImage* getBitmapImageAtFrame(int frameNumber); BitmapImage* getLastBitmapImageAtFrame(int frameNumber, int increment = 0); @@ -42,6 +41,7 @@ class LayerBitmap : public Layer KeyFrame* createKeyFrame(int position, Object*) override; private: + void loadImageAtFrame(QString strFilePath, QPoint topLeft, int frameNumber); QString fileName(KeyFrame* key) const; bool needSaveFrame(KeyFrame* key, const QString& strSavePath); }; From acbbb8624506a775a5d9578deeeeb403be1fe755 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 4 Sep 2018 12:13:56 +1000 Subject: [PATCH 170/184] Use bounds().isEmpty() to identify an empty bitmap image. - mImage->isNull() is not accurate, since it could be simply unloaded, not really an empty frame. --- core_lib/src/graphics/bitmap/bitmapimage.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/core_lib/src/graphics/bitmap/bitmapimage.cpp b/core_lib/src/graphics/bitmap/bitmapimage.cpp index e5be301df..ddba8d43b 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.cpp +++ b/core_lib/src/graphics/bitmap/bitmapimage.cpp @@ -651,7 +651,8 @@ Status BitmapImage::writeFile(const QString& filename) bool b = mImage->save(filename); return (b) ? Status::OK : Status::FAIL; } - else + + if (bounds().isEmpty()) { QFile f(filename); if(f.exists()) @@ -659,10 +660,7 @@ Status BitmapImage::writeFile(const QString& filename) bool b = f.remove(); return (b) ? Status::OK : Status::FAIL; } - else - { - return Status::OK; - } + return Status::SAFE; } return Status::SAFE; } From cd11179842856452cf544e81d5d4b8764fc31096 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 4 Sep 2018 12:14:06 +1000 Subject: [PATCH 171/184] Fix a unit test --- tests/src/test_bitmapimage.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/src/test_bitmapimage.cpp b/tests/src/test_bitmapimage.cpp index b1c561286..7f202ebf2 100644 --- a/tests/src/test_bitmapimage.cpp +++ b/tests/src/test_bitmapimage.cpp @@ -22,10 +22,10 @@ TEST_CASE("BitmapImage constructors") SECTION("Init an Bitmap Image") { auto b = std::make_shared(); - REQUIRE(b->image()->isNull() == false); + REQUIRE(b->image()->isNull()); - REQUIRE(b->width() == 1); - REQUIRE(b->height() == 1); + REQUIRE(b->width() == 0); + REQUIRE(b->height() == 0); REQUIRE(b->top() == 0); REQUIRE(b->left() == 0); } From 9be26d85e9f2f7fb938312669bdab25b687ff23a Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 4 Sep 2018 12:47:43 +1000 Subject: [PATCH 172/184] Eliminate unnecessary auto-crop operations --- core_lib/src/canvaspainter.cpp | 3 ++- core_lib/src/graphics/bitmap/bitmapimage.cpp | 4 ++-- core_lib/src/graphics/bitmap/bitmapimage.h | 1 + core_lib/src/interface/scribblearea.cpp | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/core_lib/src/canvaspainter.cpp b/core_lib/src/canvaspainter.cpp index 73ffd1368..59bcaf7a2 100644 --- a/core_lib/src/canvaspainter.cpp +++ b/core_lib/src/canvaspainter.cpp @@ -211,6 +211,7 @@ void CanvasPainter::paintBitmapFrame(QPainter& painter, //qCDebug(mLog) << "Paint Image Size:" << paintedImage->image()->size(); BitmapImage paintToImage; + paintToImage.ignoreAutoCrop(); paintToImage.paste(paintedImage); if (colorize) @@ -243,7 +244,7 @@ void CanvasPainter::paintBitmapFrame(QPainter& painter, painter.setWorldMatrixEnabled(true); prescale(&paintToImage); - + paintToImage.ignoreAutoCrop(); paintToImage.paintImage(painter, mScaledBitmap, mScaledBitmap.rect(), paintToImage.bounds()); } diff --git a/core_lib/src/graphics/bitmap/bitmapimage.cpp b/core_lib/src/graphics/bitmap/bitmapimage.cpp index ddba8d43b..f111876c0 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.cpp +++ b/core_lib/src/graphics/bitmap/bitmapimage.cpp @@ -47,7 +47,7 @@ BitmapImage::BitmapImage(const QRect& rectangle, const QColor& colour) BitmapImage::BitmapImage(const QPoint& topLeft, const QImage& image) { mBounds = QRect(topLeft, image.size()); - mMinBound = false; + mMinBound = true; mImage = std::make_shared(image); } @@ -56,7 +56,7 @@ BitmapImage::BitmapImage(const QPoint& topLeft, const QString& path) setFileName(path); mImage.reset(); - mBounds = QRect(topLeft, QSize(0,0)); + mBounds = QRect(topLeft, QSize(0, 0)); mMinBound = true; setModified(false); } diff --git a/core_lib/src/graphics/bitmap/bitmapimage.h b/core_lib/src/graphics/bitmap/bitmapimage.h index cc6db59fe..a42bce619 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.h +++ b/core_lib/src/graphics/bitmap/bitmapimage.h @@ -105,6 +105,7 @@ class BitmapImage : public KeyFrame * for the contained image. */ bool isMinimallyBounded() const { return mMinBound; } + void ignoreAutoCrop() { mMinBound = true; } Status writeFile(const QString& filename); diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index 1b096b433..1bb61834d 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -694,6 +694,7 @@ void ScribbleArea::paintBitmapBuffer() default: //nothing break; } + mBufferImg->ignoreAutoCrop(); targetImage->paste(mBufferImg, cm); } From 684d66daeac30cd29a69878d66c62fd20abee4fd Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 4 Sep 2018 13:08:39 +1000 Subject: [PATCH 173/184] A unit test for #939 - https://github.com/pencil2d/pencil/issues/939 --- core_lib/src/structure/layer.cpp | 1 - tests/src/test_filemanager.cpp | 48 ++++++++++++++++++++++---------- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/core_lib/src/structure/layer.cpp b/core_lib/src/structure/layer.cpp index ab2d6195e..f7ab8e3d6 100644 --- a/core_lib/src/structure/layer.cpp +++ b/core_lib/src/structure/layer.cpp @@ -465,7 +465,6 @@ void Layer::setFrameSelected(int position, bool isSelected) if (isSelected && !mSelectedFrames_byLast.contains(startPosition)) { // Add the selected frame to the lists - // mSelectedFrames_byLast.insert(0, startPosition); mSelectedFrames_byPosition.append(startPosition); diff --git a/tests/src/test_filemanager.cpp b/tests/src/test_filemanager.cpp index 4905d36a9..7c0087e67 100644 --- a/tests/src/test_filemanager.cpp +++ b/tests/src/test_filemanager.cpp @@ -220,29 +220,47 @@ TEST_CASE("FileManager Load-a-zip Test") } } -TEST_CASE("FileManager Lazy loading test") +TEST_CASE("FileManager File-saving") { - SECTION("") + // https://github.com/pencil2d/pencil/issues/939 + SECTION("#939 Clear action not properly saved") { - Object* o = new Object; - o->init(); - o->createDefaultLayers(); + FileManager fm; - LayerBitmap* layer = static_cast(o->getLayer(2)); - //qDebug() << "LayerType:" << layer->type(); + // 1. create a animation with one red frame & save it + Object* o1 = new Object; + o1->init(); + o1->createDefaultLayers(); + LayerBitmap* layer = dynamic_cast(o1->getLayer(2)); REQUIRE(layer->addNewKeyFrameAt(2)); - BitmapImage* b2 = layer->getBitmapImageAtFrame(2); - //qDebug() << b2->bounds(); - b2->drawRect(QRectF(0, 0, 10, 10), QPen(QColor(255, 0, 0)), QBrush(Qt::red), QPainter::CompositionMode_SourceOver, false); - //b2->image()->save("C:/temp/test1.png"); + + BitmapImage* b1 = layer->getBitmapImageAtFrame(2); + b1->drawRect(QRectF(0, 0, 10, 10), QPen(QColor(255, 0, 0)), QBrush(Qt::red), QPainter::CompositionMode_SourceOver, false); QTemporaryDir testDir("PENCIL_TEST_XXXXXXXX"); - REQUIRE(testDir.isValid()); - FileManager fm; - fm.save(o, testDir.path() + "/abc.pclx"); + QString animationPath = testDir.path() + "/abc.pclx"; + fm.save(o1, animationPath); + delete o1; + + // 2. load the animation, and then clear the red frame, save it. + Object* o2 = fm.load(animationPath); + layer = dynamic_cast(o2->getLayer(2)); + + BitmapImage* b2 = layer->getBitmapImageAtFrame(2); + b2->clear(); + + fm.save(o2, animationPath); + delete o2; + + // 3. load the animation again, check whether it's an empty frame + Object* o3 = fm.load(animationPath); + layer = dynamic_cast(o3->getLayer(2)); + + BitmapImage* b3 = layer->getBitmapImageAtFrame(2); + REQUIRE(b3->bounds().isEmpty()); - delete o; + delete o3; } } From 29051b48f109684a53fa4f8137d71b0c76ef9730 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Tue, 4 Sep 2018 17:37:17 +1000 Subject: [PATCH 174/184] Completely fix #966 with a unit test --- app/src/filedialogex.cpp | 2 +- core_lib/src/activeframepool.cpp | 7 +++ core_lib/src/activeframepool.h | 1 + core_lib/src/graphics/bitmap/bitmapimage.cpp | 6 +++ core_lib/src/graphics/bitmap/bitmapimage.h | 1 + core_lib/src/structure/filemanager.cpp | 6 +++ core_lib/src/structure/keyframe.h | 1 + core_lib/src/structure/layerbitmap.cpp | 6 ++- core_lib/src/structure/object.cpp | 2 +- tests/src/test_filemanager.cpp | 54 +++++++++++++++++++- 10 files changed, 81 insertions(+), 5 deletions(-) diff --git a/app/src/filedialogex.cpp b/app/src/filedialogex.cpp index 9fcaf5bb7..bf66ceedb 100644 --- a/app/src/filedialogex.cpp +++ b/app/src/filedialogex.cpp @@ -191,7 +191,7 @@ QString FileDialog::saveFileFilters( FileType fileType ) QString FileDialog::getFilterForFile(QString filters, QString filePath) { - qDebug() << "Getfilterforfile" << filters << filePath; + qDebug() << __FUNCTION__ << filters << filePath; if(!filePath.contains(".")) { return QString(); diff --git a/core_lib/src/activeframepool.cpp b/core_lib/src/activeframepool.cpp index 0d5f03867..91f8083b0 100644 --- a/core_lib/src/activeframepool.cpp +++ b/core_lib/src/activeframepool.cpp @@ -73,6 +73,12 @@ void ActiveFramePool::clear() mCacheFramesMap.clear(); } +bool ActiveFramePool::isFrameInPool(KeyFrame* key) +{ + auto it = mCacheFramesMap.find(key); + return (it != mCacheFramesMap.end()); +} + void ActiveFramePool::onKeyFrameDestroy(KeyFrame* key) { auto it = mCacheFramesMap.find(key); @@ -85,5 +91,6 @@ void ActiveFramePool::onKeyFrameDestroy(KeyFrame* key) void ActiveFramePool::unloadFrame(KeyFrame* key) { + //qDebug() << "Unload frame:" << key->pos(); key->unloadFile(); } diff --git a/core_lib/src/activeframepool.h b/core_lib/src/activeframepool.h index 2cd7af0bc..ce55d4310 100644 --- a/core_lib/src/activeframepool.h +++ b/core_lib/src/activeframepool.h @@ -36,6 +36,7 @@ class ActiveFramePool : public KeyFrameEventListener void put(KeyFrame* key); size_t size() const; void clear(); + bool isFrameInPool(KeyFrame*); void onKeyFrameDestroy(KeyFrame*) override; diff --git a/core_lib/src/graphics/bitmap/bitmapimage.cpp b/core_lib/src/graphics/bitmap/bitmapimage.cpp index f111876c0..3972db672 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.cpp +++ b/core_lib/src/graphics/bitmap/bitmapimage.cpp @@ -106,6 +106,11 @@ void BitmapImage::unloadFile() } } +bool BitmapImage::isLoaded() +{ + return (mImage != nullptr); +} + void BitmapImage::paintImage(QPainter& painter) { painter.drawImage(mBounds.topLeft(), *image()); @@ -354,6 +359,7 @@ void BitmapImage::autoCrop() { // Exit if current bounds are null if (mBounds.isEmpty()) return; + if (!mImage) return; Q_ASSERT(mBounds.size() == mImage->size()); diff --git a/core_lib/src/graphics/bitmap/bitmapimage.h b/core_lib/src/graphics/bitmap/bitmapimage.h index a42bce619..aa7b2bbc1 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.h +++ b/core_lib/src/graphics/bitmap/bitmapimage.h @@ -37,6 +37,7 @@ class BitmapImage : public KeyFrame BitmapImage* clone() override; void loadFile() override; void unloadFile() override; + bool isLoaded() override; void paintImage(QPainter& painter); void paintImage(QPainter &painter, QImage &image, QRect sourceRect, QRect destRect); diff --git a/core_lib/src/structure/filemanager.cpp b/core_lib/src/structure/filemanager.cpp index 0b7344052..124dcff99 100644 --- a/core_lib/src/structure/filemanager.cpp +++ b/core_lib/src/structure/filemanager.cpp @@ -296,6 +296,12 @@ Status FileManager::save(Object* object, QString sFileName) int numLayers = object->getLayerCount(); dd << QString("Total %1 layers").arg(numLayers); + for (int i = 0; i < numLayers; ++i) + { + Layer* layer = object->getLayer(i); + layer->presave(sDataFolder); + } + QStringList zippedFiles; bool saveLayersOK = true; diff --git a/core_lib/src/structure/keyframe.h b/core_lib/src/structure/keyframe.h index 8922a7836..2475c3950 100644 --- a/core_lib/src/structure/keyframe.h +++ b/core_lib/src/structure/keyframe.h @@ -55,6 +55,7 @@ class KeyFrame virtual KeyFrame* clone() { return nullptr; } virtual void loadFile() {}; virtual void unloadFile() {} + virtual bool isLoaded() { return true; } private: int mFrame = -1; diff --git a/core_lib/src/structure/layerbitmap.cpp b/core_lib/src/structure/layerbitmap.cpp index 549847457..4596fe199 100644 --- a/core_lib/src/structure/layerbitmap.cpp +++ b/core_lib/src/structure/layerbitmap.cpp @@ -92,7 +92,7 @@ KeyFrame* LayerBitmap::createKeyFrame(int position, Object*) return b; } -Status LayerBitmap::presave(const QString& sDataFolder) +Status LayerBitmap::presave(const QString&) { // handles those moved keys but note loaded yet std::vector bitmapArray; @@ -100,7 +100,9 @@ Status LayerBitmap::presave(const QString& sDataFolder) { auto bitmap = static_cast(key); // null image + modified => the keyframe has been moved, but users didn't draw on it. - if (bitmap->image()->isNull() && bitmap->isModified()) + if (!bitmap->fileName().isEmpty() + && bitmap->image()->isNull() + && bitmap->isModified()) { bitmapArray.push_back(bitmap); } diff --git a/core_lib/src/structure/object.cpp b/core_lib/src/structure/object.cpp index cfc7a00d5..c9a05f153 100644 --- a/core_lib/src/structure/object.cpp +++ b/core_lib/src/structure/object.cpp @@ -38,7 +38,7 @@ GNU General Public License for more details. Object::Object(QObject* parent) : QObject(parent) { setData(new ObjectData()); - mActiveFramePool.reset(new ActiveFramePool(200)); + mActiveFramePool.reset(new ActiveFramePool(12)); } Object::~Object() diff --git a/tests/src/test_filemanager.cpp b/tests/src/test_filemanager.cpp index 7c0087e67..5911fd17b 100644 --- a/tests/src/test_filemanager.cpp +++ b/tests/src/test_filemanager.cpp @@ -239,7 +239,6 @@ TEST_CASE("FileManager File-saving") b1->drawRect(QRectF(0, 0, 10, 10), QPen(QColor(255, 0, 0)), QBrush(Qt::red), QPainter::CompositionMode_SourceOver, false); QTemporaryDir testDir("PENCIL_TEST_XXXXXXXX"); - QString animationPath = testDir.path() + "/abc.pclx"; fm.save(o1, animationPath); delete o1; @@ -263,4 +262,57 @@ TEST_CASE("FileManager File-saving") delete o3; } + + //https://github.com/pencil2d/pencil/issues/966 + SECTION("#966 Moving more than 200 frames corrupts frames upon save") + { + FileManager fm; + + // 1. Create a animation with 500 frames & save it + Object* o1 = new Object; + o1->init(); + o1->createDefaultLayers(); + LayerBitmap* layer = dynamic_cast(o1->getLayer(2)); + + for (int i = 100; i < 500; ++i) + { + layer->addNewKeyFrameAt(i); + auto bitmap = layer->getBitmapImageAtFrame(i); + bitmap->drawRect(QRectF(0, 0, 10, 10), QPen(QColor(255, 0, 0)), QBrush(Qt::red), QPainter::CompositionMode_SourceOver, false); + } + + QTemporaryDir testDir("PENCIL_TEST_XXXXXXXX"); + QString animationPath = testDir.path() + "/abc.pclx"; + fm.save(o1, animationPath); + delete o1; + + // 2. Load the animation back and then make some frames unloaded by active frame pool + Object* o2 = fm.load(animationPath); + + layer = dynamic_cast(o2->getLayer(2)); + for (int i = 1; i < 500; ++i) + o2->updateActiveFrames(i); + + // 3. Move those unloaded frames around + for (int i = 100; i < 200; ++i) + layer->setFrameSelected(i, true); + + layer->moveSelectedFrames(-98); + fm.save(o2, animationPath); + delete o2; + + // 4. Check no lost frames + Object* o3 = fm.load(animationPath); + layer = dynamic_cast(o3->getLayer(2)); + for (int i = 2; i < 500; ++i) + { + auto bitmap = layer->getBitmapImageAtFrame(i); + if (bitmap) + { + REQUIRE(bitmap->image()->width() > 1); + REQUIRE(bitmap->image()->height() > 1); + } + } + delete o3; + } } From d267a39148f3957e5754330b1f01ff90654748da Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Wed, 5 Sep 2018 11:36:16 +1000 Subject: [PATCH 175/184] Revert a mistake from 9be26d85 --- core_lib/src/graphics/bitmap/bitmapimage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core_lib/src/graphics/bitmap/bitmapimage.cpp b/core_lib/src/graphics/bitmap/bitmapimage.cpp index 3972db672..9b8ff6c97 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.cpp +++ b/core_lib/src/graphics/bitmap/bitmapimage.cpp @@ -41,7 +41,7 @@ BitmapImage::BitmapImage(const QRect& rectangle, const QColor& colour) mBounds = rectangle; mImage = std::make_shared(mBounds.size(), QImage::Format_ARGB32_Premultiplied); mImage->fill(colour.rgba()); - mMinBound = true; + mMinBound = false; } BitmapImage::BitmapImage(const QPoint& topLeft, const QImage& image) From c4afd6dc13f0e466895af48142d5871c6d0f38bd Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Wed, 5 Sep 2018 11:36:49 +1000 Subject: [PATCH 176/184] Double the active frame pool size in 64bit arch --- core_lib/core_lib.pro | 12 ++++++++++-- core_lib/src/structure/object.cpp | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/core_lib/core_lib.pro b/core_lib/core_lib.pro index 331689e28..693843c88 100644 --- a/core_lib/core_lib.pro +++ b/core_lib/core_lib.pro @@ -157,6 +157,9 @@ SOURCES += src/graphics/bitmap/bitmapimage.cpp \ src/qminiz.cpp \ src/activeframepool.cpp +FORMS += \ + ui/camerapropertiesdialog.ui + win32 { CONFIG -= flat @@ -174,5 +177,10 @@ unix:!macx { SOURCES += src/external/linux/linux.cpp } -FORMS += \ - ui/camerapropertiesdialog.ui +contains(QT_ARCH, i386) { + message("32-bit") + DEFINES += "FRAME_POOL_SIZE=200" +} else { + message("64-bit") + DEFINES += "FRAME_POOL_SIZE=400" +} diff --git a/core_lib/src/structure/object.cpp b/core_lib/src/structure/object.cpp index c9a05f153..33ddf7385 100644 --- a/core_lib/src/structure/object.cpp +++ b/core_lib/src/structure/object.cpp @@ -38,7 +38,7 @@ GNU General Public License for more details. Object::Object(QObject* parent) : QObject(parent) { setData(new ObjectData()); - mActiveFramePool.reset(new ActiveFramePool(12)); + mActiveFramePool.reset(new ActiveFramePool(FRAME_POOL_SIZE)); } Object::~Object() From 3892671dcd7c43f159949e0fb99f8fe078a85feb Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Wed, 5 Sep 2018 14:03:10 +1000 Subject: [PATCH 177/184] Fix scale to NaN - the scaleX & scaleY could be NaN if mySelection's width & height are zero --- core_lib/src/interface/scribblearea.cpp | 16 ++++++++-------- core_lib/src/interface/scribblearea.h | 4 +++- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index 1bb61834d..80375297b 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -1552,23 +1552,23 @@ QVector ScribbleArea::calcSelectionCenterPoints() void ScribbleArea::calculateSelectionTransformation() { - float scaleX, scaleY; - QVector centerPoints = calcSelectionCenterPoints(); selectionTransformation.reset(); - scaleX = myTempTransformedSelection.width() / mySelection.width(); - - scaleY = myTempTransformedSelection.height() / mySelection.height(); + float scaleX = myTempTransformedSelection.width() / mySelection.width(); + float scaleY = myTempTransformedSelection.height() / mySelection.height(); selectionTransformation.translate(centerPoints[0].x(), centerPoints[0].y()); selectionTransformation.rotate(myRotatedAngle); - selectionTransformation.scale(scaleX, scaleY); - + if (mySelection.width() > 0 && mySelection.height() > 0) // can't divide by 0 + { + float scaleX = myTempTransformedSelection.width() / mySelection.width(); + float scaleY = myTempTransformedSelection.height() / mySelection.height(); + selectionTransformation.scale(scaleX, scaleY); + } selectionTransformation.translate(-centerPoints[1].x(), -centerPoints[1].y()); - } diff --git a/core_lib/src/interface/scribblearea.h b/core_lib/src/interface/scribblearea.h index 371ffd8c2..db9445563 100644 --- a/core_lib/src/interface/scribblearea.h +++ b/core_lib/src/interface/scribblearea.h @@ -70,7 +70,9 @@ class ScribbleArea : public QWidget bool isSomethingSelected() const; QRectF getSelection() const { return mySelection; } - QRectF mySelection, myTransformedSelection, myTempTransformedSelection; + QRectF mySelection; + QRectF myTransformedSelection; + QRectF myTempTransformedSelection; qreal myRotatedAngle = 0.0; QList mClosestCurves; From e0259f0276217b439fb80505a366f8876ae151a5 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Wed, 5 Sep 2018 15:53:39 +1000 Subject: [PATCH 178/184] Clean up --- app/src/colorpalettewidget.cpp | 13 +++----- core_lib/src/interface/editor.cpp | 43 +++++++++++++------------ core_lib/src/interface/scribblearea.cpp | 3 -- 3 files changed, 27 insertions(+), 32 deletions(-) diff --git a/app/src/colorpalettewidget.cpp b/app/src/colorpalettewidget.cpp index 60dd271eb..21c611619 100644 --- a/app/src/colorpalettewidget.cpp +++ b/app/src/colorpalettewidget.cpp @@ -137,7 +137,6 @@ void ColorPaletteWidget::replaceItem() emit colorChanged(newColour); ui->colorListWidget->setCurrentRow(index); } - } void ColorPaletteWidget::removeItem() @@ -157,7 +156,6 @@ void ColorPaletteWidget::setColor(QColor newColor, int colorIndex) } } - void ColorPaletteWidget::selectColorNumber(int colorNumber) { ui->colorListWidget->setCurrentRow(colorNumber); @@ -405,7 +403,8 @@ void ColorPaletteWidget::updateGridUI() ui->colorListWidget->setGridSize(QSize(tempSize.width(), mIconSize.height() + 2)); mIconSize.setWidth(mIconSize.width()); } - else { + else + { ui->colorListWidget->setIconSize(mIconSize); ui->colorListWidget->setGridSize(QSize(-1, -1)); } @@ -483,16 +482,14 @@ void ColorPaletteWidget::clickAddColorButton() QColor newColour; - if (mIsColorDialog) { + if (mIsColorDialog) newColour = QColorDialog::getColor(prevColor.rgba(), this, QString(), QColorDialog::ShowAlphaChannel); - } else { + else newColour = editor()->color()->frontColor(); - } if (!newColour.isValid()) { - // User canceled operation - return; + return; // User canceled operation } int colorIndex = editor()->object()->getColourCount(); diff --git a/core_lib/src/interface/editor.cpp b/core_lib/src/interface/editor.cpp index 0899cbf56..6c63887a3 100644 --- a/core_lib/src/interface/editor.cpp +++ b/core_lib/src/interface/editor.cpp @@ -187,7 +187,8 @@ void Editor::backup(QString undoText) if (layers()->currentLayer()->type() == Layer::SOUND) { frame = layers()->currentLayer()->getKeyFrameWhichCovers(mLastModifiedFrame); - if (frame != nullptr) { + if (frame != nullptr) + { backup(mLastModifiedLayer, frame->pos(), undoText); } } @@ -225,6 +226,7 @@ void Editor::backup(int backupLayer, int backupFrame, QString undoText) delete mBackupList.takeFirst(); mBackupIndex--; } + Layer* layer = mObject->getLayer(backupLayer); if (layer != NULL) { @@ -492,24 +494,28 @@ void Editor::copy() Layer* layer = mObject->getLayer(layers()->currentLayerIndex()); if (layer != NULL) { - if (layer->type() == Layer::BITMAP) + return; + } + + if (layer->type() == Layer::BITMAP) + { + LayerBitmap* layerBitmap = (LayerBitmap*)layer; + if (mScribbleArea->isSomethingSelected()) { - if (mScribbleArea->isSomethingSelected()) - { - g_clipboardBitmapImage = ((LayerBitmap*)layer)->getLastBitmapImageAtFrame(currentFrame(), 0)->copy(mScribbleArea->getSelection().toRect()); // copy part of the image - } - else - { - g_clipboardBitmapImage = ((LayerBitmap*)layer)->getLastBitmapImageAtFrame(currentFrame(), 0)->copy(); // copy the whole image - } - clipboardBitmapOk = true; - if (g_clipboardBitmapImage.image() != NULL) QApplication::clipboard()->setImage(*g_clipboardBitmapImage.image()); + g_clipboardBitmapImage = layerBitmap->getLastBitmapImageAtFrame(currentFrame(), 0)->copy(mScribbleArea->getSelection().toRect()); // copy part of the image } - if (layer->type() == Layer::VECTOR) + else { - clipboardVectorOk = true; - g_clipboardVectorImage = *(((LayerVector*)layer)->getLastVectorImageAtFrame(currentFrame(), 0)); // copy the image + g_clipboardBitmapImage = layerBitmap->getLastBitmapImageAtFrame(currentFrame(), 0)->copy(); // copy the whole image } + clipboardBitmapOk = true; + if (g_clipboardBitmapImage.image() != NULL) + QApplication::clipboard()->setImage(*g_clipboardBitmapImage.image()); + } + if (layer->type() == Layer::VECTOR) + { + clipboardVectorOk = true; + g_clipboardVectorImage = *(((LayerVector*)layer)->getLastVectorImageAtFrame(currentFrame(), 0)); // copy the image } } @@ -822,7 +828,6 @@ bool Editor::importGIF(QString filePath, int numOfImages) } else { return false; } - } void Editor::updateFrame(int frameNumber) @@ -853,10 +858,7 @@ void Editor::setCurrentLayerIndex(int i) void Editor::scrubTo(int frame) { - if (frame < 1) - { - frame = 1; - } + if (frame < 1) { frame = 1; } int oldFrame = mFrame; mFrame = frame; @@ -870,7 +872,6 @@ void Editor::scrubTo(int frame) { emit updateTimeLine(); // needs to update the timeline to update onion skin positions } - mObject->updateActiveFrames(frame); } diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index 80375297b..d64c0d837 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -1556,9 +1556,6 @@ void ScribbleArea::calculateSelectionTransformation() selectionTransformation.reset(); - float scaleX = myTempTransformedSelection.width() / mySelection.width(); - float scaleY = myTempTransformedSelection.height() / mySelection.height(); - selectionTransformation.translate(centerPoints[0].x(), centerPoints[0].y()); selectionTransformation.rotate(myRotatedAngle); From 52a0dd9cfb36ee127d940e859fc90deb82b912f6 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Wed, 5 Sep 2018 15:50:59 +1000 Subject: [PATCH 179/184] Update Catch2 test framework to 2.4.0 --- tests/src/catch.hpp | 7858 +++++++++++++++++++++++++++---------------- 1 file changed, 4884 insertions(+), 2974 deletions(-) diff --git a/tests/src/catch.hpp b/tests/src/catch.hpp index 362f8693f..b0fa64167 100644 --- a/tests/src/catch.hpp +++ b/tests/src/catch.hpp @@ -1,9 +1,9 @@ /* - * Catch v2.0.1 - * Generated: 2017-11-03 11:53:39.642003 + * Catch v2.4.0 + * Generated: 2018-09-04 11:55:01.682061 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly - * Copyright (c) 2017 Two Blue Cubes Ltd. All rights reserved. + * Copyright (c) 2018 Two Blue Cubes Ltd. All rights reserved. * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -13,6 +13,10 @@ // start catch.hpp +#define CATCH_VERSION_MAJOR 2 +#define CATCH_VERSION_MINOR 4 +#define CATCH_VERSION_PATCH 0 + #ifdef __clang__ # pragma clang system_header #elif defined __GNUC__ @@ -26,37 +30,44 @@ # pragma warning(push) # pragma warning(disable: 161 1682) # else // __ICC -# pragma clang diagnostic ignored "-Wglobal-constructors" -# pragma clang diagnostic ignored "-Wvariadic-macros" -# pragma clang diagnostic ignored "-Wc99-extensions" -# pragma clang diagnostic ignored "-Wunused-variable" # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wpadded" # pragma clang diagnostic ignored "-Wswitch-enum" # pragma clang diagnostic ignored "-Wcovered-switch-default" # endif #elif defined __GNUC__ -# pragma GCC diagnostic ignored "-Wvariadic-macros" -# pragma GCC diagnostic ignored "-Wunused-variable" + // GCC likes to warn on REQUIREs, and we cannot suppress them + // locally because g++'s support for _Pragma is lacking in older, + // still supported, versions # pragma GCC diagnostic ignored "-Wparentheses" - # pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-variable" # pragma GCC diagnostic ignored "-Wpadded" #endif // end catch_suppress_warnings.h #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) # define CATCH_IMPL +# define CATCH_CONFIG_ALL_PARTS +#endif + +// In the impl file, we want to have access to all parts of the headers +// Can also be used to sanely support PCHs +#if defined(CATCH_CONFIG_ALL_PARTS) # define CATCH_CONFIG_EXTERNAL_INTERFACES # if defined(CATCH_CONFIG_DISABLE_MATCHERS) # undef CATCH_CONFIG_DISABLE_MATCHERS # endif +# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +# endif #endif +#if !defined(CATCH_CONFIG_IMPL_ONLY) // start catch_platform.h #ifdef __APPLE__ # include -# if TARGET_OS_MAC == 1 +# if TARGET_OS_OSX == 1 # define CATCH_PLATFORM_MAC # elif TARGET_OS_IPHONE == 1 # define CATCH_PLATFORM_IPHONE @@ -65,11 +76,12 @@ #elif defined(linux) || defined(__linux) || defined(__linux__) # define CATCH_PLATFORM_LINUX -#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) # define CATCH_PLATFORM_WINDOWS #endif // end catch_platform.h + #ifdef CATCH_IMPL # ifndef CLARA_CONFIG_MAIN # define CLARA_CONFIG_MAIN_NOT_DEFINED @@ -77,6 +89,13 @@ # endif #endif +// start catch_user_interfaces.h + +namespace Catch { + unsigned int rngSeed(); +} + +// end catch_user_interfaces.h // start catch_tag_alias_autoregistrar.h // start catch_common.h @@ -89,6 +108,7 @@ // CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? // CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? // CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? +// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? // **************** // Note to maintainers: if new toggles are added please document them // in configuration.md, too @@ -105,6 +125,14 @@ # define CATCH_CPP14_OR_GREATER # endif +# if __cplusplus >= 201703L +# define CATCH_CPP17_OR_GREATER +# endif + +#endif + +#if defined(CATCH_CPP17_OR_GREATER) +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS #endif #ifdef __clang__ @@ -122,16 +150,24 @@ # define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ _Pragma( "clang diagnostic pop" ) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic push" ) \ + _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) +# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic pop" ) + #endif // __clang__ //////////////////////////////////////////////////////////////////////////////// -// We know some environments not to support full POSIX signals -#if defined(__CYGWIN__) || defined(__QNX__) - -# if !defined(CATCH_CONFIG_POSIX_SIGNALS) -# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -# endif +// Assume that non-Windows platforms support posix signals by default +#if !defined(CATCH_PLATFORM_WINDOWS) + #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS +#endif +//////////////////////////////////////////////////////////////////////////////// +// We know some environments not to support full POSIX signals +#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) + #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS #endif #ifdef __OS400__ @@ -139,6 +175,24 @@ # define CATCH_CONFIG_COLOUR_NONE #endif +//////////////////////////////////////////////////////////////////////////////// +// Android somehow still does not support std::to_string +#if defined(__ANDROID__) +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Not all Windows environments support SEH properly +#if defined(__MINGW32__) +# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH +#endif + +//////////////////////////////////////////////////////////////////////////////// +// PS4 +#if defined(__ORBIS__) +# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE +#endif + //////////////////////////////////////////////////////////////////////////////// // Cygwin #ifdef __CYGWIN__ @@ -153,6 +207,10 @@ // Visual C++ #ifdef _MSC_VER +# if _MSC_VER >= 1900 // Visual Studio 2015 or newer +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +# endif + // Universal Windows platform does not support SEH // Or console colours (or console at all...) # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) @@ -163,6 +221,18 @@ #endif // _MSC_VER +//////////////////////////////////////////////////////////////////////////////// +// Check if we are compiled with -fno-exceptions or equivalent +#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) +# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED +#endif + +//////////////////////////////////////////////////////////////////////////////// +// DJGPP +#ifdef __DJGPP__ +# define CATCH_INTERNAL_CONFIG_NO_WCHAR +#endif // __DJGPP__ + //////////////////////////////////////////////////////////////////////////////// // Use of __COUNTER__ is suppressed during code analysis in @@ -177,13 +247,37 @@ #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) # define CATCH_CONFIG_COUNTER #endif -#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) +#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) # define CATCH_CONFIG_WINDOWS_SEH #endif // This is set by default, because we assume that unix compilers are posix-signal-compatible by default. -#if !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) +#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) # define CATCH_CONFIG_POSIX_SIGNALS #endif +// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. +#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) +# define CATCH_CONFIG_WCHAR +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) +# define CATCH_CONFIG_CPP11_TO_STRING +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) +# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) +# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) +# define CATCH_CONFIG_NEW_CAPTURE +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +# define CATCH_CONFIG_DISABLE_EXCEPTIONS +#endif #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS @@ -193,6 +287,20 @@ # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS # define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS #endif +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS +# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS +#endif + +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +#define CATCH_TRY if ((true)) +#define CATCH_CATCH_ALL if ((false)) +#define CATCH_CATCH_ANON(type) if ((false)) +#else +#define CATCH_TRY try +#define CATCH_CATCH_ALL catch (...) +#define CATCH_CATCH_ANON(type) catch (type) +#endif // end catch_compiler_capabilities.h #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line @@ -228,7 +336,10 @@ namespace Catch { struct SourceLineInfo { SourceLineInfo() = delete; - SourceLineInfo( char const* _file, std::size_t _line ) noexcept; + SourceLineInfo( char const* _file, std::size_t _line ) noexcept + : file( _file ), + line( _line ) + {} SourceLineInfo( SourceLineInfo const& other ) = default; SourceLineInfo( SourceLineInfo && ) = default; @@ -245,11 +356,6 @@ namespace Catch { std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); - // This is just here to avoid compiler warnings with macro constants and boolean literals - bool isTrue( bool value ); - bool alwaysTrue(); - bool alwaysFalse(); - // Use this in variadic streaming macros to allow // >> +StreamEndStop // as well as @@ -275,7 +381,10 @@ namespace Catch { } // end namespace Catch -#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS // end catch_tag_alias_autoregistrar.h // start catch_test_registry.h @@ -330,10 +439,12 @@ namespace Catch { /// visible - but it does mean (substring) StringRefs should not be shared between /// threads. class StringRef { - friend struct StringRefTestAccess; - + public: using size_type = std::size_t; + private: + friend struct StringRefTestAccess; + char const* m_start; size_type m_size; @@ -341,16 +452,50 @@ namespace Catch { void takeOwnership(); + static constexpr char const* const s_empty = ""; + public: // construction/ assignment - StringRef() noexcept; - StringRef( StringRef const& other ) noexcept; - StringRef( StringRef&& other ) noexcept; + StringRef() noexcept + : StringRef( s_empty, 0 ) + {} + + StringRef( StringRef const& other ) noexcept + : m_start( other.m_start ), + m_size( other.m_size ) + {} + + StringRef( StringRef&& other ) noexcept + : m_start( other.m_start ), + m_size( other.m_size ), + m_data( other.m_data ) + { + other.m_data = nullptr; + } + StringRef( char const* rawChars ) noexcept; - StringRef( char const* rawChars, size_type size ) noexcept; - StringRef( std::string const& stdString ) noexcept; - ~StringRef() noexcept; - auto operator = ( StringRef other ) noexcept -> StringRef&; + StringRef( char const* rawChars, size_type size ) noexcept + : m_start( rawChars ), + m_size( size ) + {} + + StringRef( std::string const& stdString ) noexcept + : m_start( stdString.c_str() ), + m_size( stdString.size() ) + {} + + ~StringRef() noexcept { + delete[] m_data; + } + + auto operator = ( StringRef const &other ) noexcept -> StringRef& { + delete[] m_data; + m_data = nullptr; + m_start = other.m_start; + m_size = other.m_size; + return *this; + } + operator std::string() const; void swap( StringRef& other ) noexcept; @@ -362,28 +507,45 @@ namespace Catch { auto operator[] ( size_type index ) const noexcept -> char; public: // named queries - auto empty() const noexcept -> bool; - auto size() const noexcept -> size_type; + auto empty() const noexcept -> bool { + return m_size == 0; + } + auto size() const noexcept -> size_type { + return m_size; + } + auto numberOfCharacters() const noexcept -> size_type; auto c_str() const -> char const*; public: // substrings and searches auto substr( size_type start, size_type size ) const noexcept -> StringRef; + // Returns the current start pointer. + // Note that the pointer can change when if the StringRef is a substring + auto currentData() const noexcept -> char const*; + private: // ownership queries - may not be consistent between calls auto isOwned() const noexcept -> bool; auto isSubstring() const noexcept -> bool; - auto data() const noexcept -> char const*; }; auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string; auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string; auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string; + auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; + inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + return StringRef( rawChars, size ); + } + } // namespace Catch +inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { + return Catch::StringRef( rawChars, size ); +} + // end catch_stringref.h namespace Catch { @@ -407,24 +569,29 @@ auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* { } struct NameAndTags { - NameAndTags( StringRef name_ = "", StringRef tags_ = "" ) noexcept; + NameAndTags( StringRef const& name_ = StringRef(), StringRef const& tags_ = StringRef() ) noexcept; StringRef name; StringRef tags; }; struct AutoReg : NonCopyable { - AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept; + AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept; ~AutoReg(); }; } // end namespace Catch +#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) +#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ +#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ +#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF + #if defined(CATCH_CONFIG_DISABLE) #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \ static void TestName() #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \ namespace{ \ - struct TestName : ClassName { \ + struct TestName : INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF ClassName) { \ void test(); \ }; \ } \ @@ -436,7 +603,7 @@ struct AutoReg : NonCopyable { #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ static void TestName(); \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, "", Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ static void TestName() #define INTERNAL_CATCH_TESTCASE( ... ) \ @@ -452,7 +619,7 @@ struct AutoReg : NonCopyable { #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ \ - struct TestName : ClassName{ \ + struct TestName : INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF ClassName) { \ void test(); \ }; \ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ @@ -465,7 +632,7 @@ struct AutoReg : NonCopyable { /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, "", Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS // end catch_test_registry.h @@ -473,15 +640,119 @@ struct AutoReg : NonCopyable { // start catch_assertionhandler.h +// start catch_assertioninfo.h + +// start catch_result_type.h + +namespace Catch { + + // ResultWas::OfType enum + struct ResultWas { enum OfType { + Unknown = -1, + Ok = 0, + Info = 1, + Warning = 2, + + FailureBit = 0x10, + + ExpressionFailed = FailureBit | 1, + ExplicitFailure = FailureBit | 2, + + Exception = 0x100 | FailureBit, + + ThrewException = Exception | 1, + DidntThrowException = Exception | 2, + + FatalErrorCondition = 0x200 | FailureBit + + }; }; + + bool isOk( ResultWas::OfType resultType ); + bool isJustInfo( int flags ); + + // ResultDisposition::Flags enum + struct ResultDisposition { enum Flags { + Normal = 0x01, + + ContinueOnFailure = 0x02, // Failures fail test, but execution continues + FalseTest = 0x04, // Prefix expression with ! + SuppressFail = 0x08 // Failures are reported but do not fail the test + }; }; + + ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ); + + bool shouldContinueOnFailure( int flags ); + inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } + bool shouldSuppressFailure( int flags ); + +} // end namespace Catch + +// end catch_result_type.h +namespace Catch { + + struct AssertionInfo + { + StringRef macroName; + SourceLineInfo lineInfo; + StringRef capturedExpression; + ResultDisposition::Flags resultDisposition; + + // We want to delete this constructor but a compiler bug in 4.8 means + // the struct is then treated as non-aggregate + //AssertionInfo() = delete; + }; + +} // end namespace Catch + +// end catch_assertioninfo.h // start catch_decomposer.h // start catch_tostring.h -#include #include #include #include #include +// start catch_stream.h + +#include +#include +#include + +namespace Catch { + + std::ostream& cout(); + std::ostream& cerr(); + std::ostream& clog(); + + class StringRef; + + struct IStream { + virtual ~IStream(); + virtual std::ostream& stream() const = 0; + }; + + auto makeStream( StringRef const &filename ) -> IStream const*; + + class ReusableStringStream { + std::size_t m_index; + std::ostream* m_oss; + public: + ReusableStringStream(); + ~ReusableStringStream(); + + auto str() const -> std::string; + + template + auto operator << ( T const& value ) -> ReusableStringStream& { + *m_oss << value; + return *this; + } + auto get() -> std::ostream& { return *m_oss; } + }; +} + +// end catch_stream.h #ifdef __OBJC__ // start catch_objc_arc.hpp @@ -535,7 +806,7 @@ inline id performOptionalSelector( id obj, SEL sel ) { #endif // We need a dummy global operator<< so we can bring it into Catch namespace later -struct Catch_global_namespace_dummy; +struct Catch_global_namespace_dummy {}; std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); namespace Catch { @@ -566,25 +837,66 @@ namespace Catch { static const bool value = decltype(test(0))::value; }; + template + std::string convertUnknownEnumToString( E e ); + + template + typename std::enable_if< + !std::is_enum::value && !std::is_base_of::value, + std::string>::type convertUnstreamable( T const& ) { + return Detail::unprintableString; + } + template + typename std::enable_if< + !std::is_enum::value && std::is_base_of::value, + std::string>::type convertUnstreamable(T const& ex) { + return ex.what(); + } + + template + typename std::enable_if< + std::is_enum::value + , std::string>::type convertUnstreamable( T const& value ) { + return convertUnknownEnumToString( value ); + } + +#if defined(_MANAGED) + //! Convert a CLR string to a utf8 std::string + template + std::string clrReferenceToString( T^ ref ) { + if (ref == nullptr) + return std::string("null"); + auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString()); + cli::pin_ptr p = &bytes[0]; + return std::string(reinterpret_cast(p), bytes->Length); + } +#endif + } // namespace Detail // If we decide for C++14, change these to enable_if_ts - template + template struct StringMaker { template static typename std::enable_if<::Catch::Detail::IsStreamInsertable::value, std::string>::type - convert(const Fake& t) { - std::ostringstream sstr; - sstr << t; - return sstr.str(); + convert(const Fake& value) { + ReusableStringStream rss; + // NB: call using the function-like syntax to avoid ambiguity with + // user-defined templated operator<< under clang. + rss.operator<<(value); + return rss.str(); } template static typename std::enable_if::value, std::string>::type - convert(const Fake&) { - return Detail::unprintableString; + convert( const Fake& value ) { +#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER) + return Detail::convertUnstreamable(value); +#else + return CATCH_CONFIG_FALLBACK_STRINGIFIER(value); +#endif } }; @@ -597,6 +909,18 @@ namespace Catch { return ::Catch::StringMaker::type>::type>::convert(e); } + template + std::string convertUnknownEnumToString( E e ) { + return ::Catch::Detail::stringify(static_cast::type>(e)); + } + +#if defined(_MANAGED) + template + std::string stringify( T^ e ) { + return ::Catch::StringMaker::convert(e); + } +#endif + } // namespace Detail // Some predefined specializations @@ -605,10 +929,12 @@ namespace Catch { struct StringMaker { static std::string convert(const std::string& str); }; +#ifdef CATCH_CONFIG_WCHAR template<> struct StringMaker { static std::string convert(const std::wstring& wstr); }; +#endif template<> struct StringMaker { @@ -618,6 +944,8 @@ namespace Catch { struct StringMaker { static std::string convert(char * str); }; + +#ifdef CATCH_CONFIG_WCHAR template<> struct StringMaker { static std::string convert(wchar_t const * str); @@ -626,23 +954,26 @@ namespace Catch { struct StringMaker { static std::string convert(wchar_t * str); }; +#endif + // TBD: Should we use `strnlen` to ensure that we don't go out of the buffer, + // while keeping string semantics? template struct StringMaker { - static std::string convert(const char* str) { + static std::string convert(char const* str) { return ::Catch::Detail::stringify(std::string{ str }); } }; template struct StringMaker { - static std::string convert(const char* str) { - return ::Catch::Detail::stringify(std::string{ str }); + static std::string convert(signed char const* str) { + return ::Catch::Detail::stringify(std::string{ reinterpret_cast(str) }); } }; template struct StringMaker { - static std::string convert(const char* str) { - return ::Catch::Detail::stringify(std::string{ str }); + static std::string convert(unsigned char const* str) { + return ::Catch::Detail::stringify(std::string{ reinterpret_cast(str) }); } }; @@ -726,35 +1057,30 @@ namespace Catch { } }; +#if defined(_MANAGED) + template + struct StringMaker { + static std::string convert( T^ ref ) { + return ::Catch::Detail::clrReferenceToString(ref); + } + }; +#endif + namespace Detail { template std::string rangeToString(InputIterator first, InputIterator last) { - std::ostringstream oss; - oss << "{ "; + ReusableStringStream rss; + rss << "{ "; if (first != last) { - oss << ::Catch::Detail::stringify(*first); + rss << ::Catch::Detail::stringify(*first); for (++first; first != last; ++first) - oss << ", " << ::Catch::Detail::stringify(*first); + rss << ", " << ::Catch::Detail::stringify(*first); } - oss << " }"; - return oss.str(); + rss << " }"; + return rss.str(); } } - template - struct StringMaker > { - static std::string convert( std::vector const& v ) { - return ::Catch::Detail::rangeToString( v.begin(), v.end() ); - } - }; - - template - struct EnumStringMaker { - static std::string convert(const T& t) { - return ::Catch::Detail::stringify(static_cast::type>(t)); - } - }; - #ifdef __OBJC__ template<> struct StringMaker { @@ -798,13 +1124,13 @@ namespace Catch { template struct StringMaker > { static std::string convert(const std::pair& pair) { - std::ostringstream oss; - oss << "{ " + ReusableStringStream rss; + rss << "{ " << ::Catch::Detail::stringify(pair.first) << ", " << ::Catch::Detail::stringify(pair.second) << " }"; - return oss.str(); + return rss.str(); } }; } @@ -841,22 +1167,86 @@ namespace Catch { template struct StringMaker> { static std::string convert(const std::tuple& tuple) { - std::ostringstream os; - os << '{'; - Detail::TupleElementPrinter>::print(tuple, os); - os << " }"; - return os.str(); + ReusableStringStream rss; + rss << '{'; + Detail::TupleElementPrinter>::print(tuple, rss.get()); + rss << " }"; + return rss.str(); } }; } #endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER +namespace Catch { + struct not_this_one {}; // Tag type for detecting which begin/ end are being selected + + // Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace + using std::begin; + using std::end; + + not_this_one begin( ... ); + not_this_one end( ... ); + + template + struct is_range { + static const bool value = + !std::is_same())), not_this_one>::value && + !std::is_same())), not_this_one>::value; + }; + +#if defined(_MANAGED) // Managed types are never ranges + template + struct is_range { + static const bool value = false; + }; +#endif + + template + std::string rangeToString( Range const& range ) { + return ::Catch::Detail::rangeToString( begin( range ), end( range ) ); + } + + // Handle vector specially + template + std::string rangeToString( std::vector const& v ) { + ReusableStringStream rss; + rss << "{ "; + bool first = true; + for( bool b : v ) { + if( first ) + first = false; + else + rss << ", "; + rss << ::Catch::Detail::stringify( b ); + } + rss << " }"; + return rss.str(); + } + + template + struct StringMaker::value && !::Catch::Detail::IsStreamInsertable::value>::type> { + static std::string convert( R const& range ) { + return rangeToString( range ); + } + }; + + template + struct StringMaker { + static std::string convert(T const(&arr)[SZ]) { + return rangeToString(arr); + } + }; + +} // namespace Catch + // Separate std::chrono::duration specialization #if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) #include #include #include +namespace Catch { + template struct ratio_string { static std::string symbol(); @@ -864,69 +1254,68 @@ struct ratio_string { template std::string ratio_string::symbol() { - std::ostringstream oss; - oss << '[' << Ratio::num << '/' + Catch::ReusableStringStream rss; + rss << '[' << Ratio::num << '/' << Ratio::den << ']'; - return oss.str(); + return rss.str(); } template <> struct ratio_string { - static std::string symbol() { return "a"; } + static std::string symbol(); }; template <> struct ratio_string { - static std::string symbol() { return "f"; } + static std::string symbol(); }; template <> struct ratio_string { - static std::string symbol() { return "p"; } + static std::string symbol(); }; template <> struct ratio_string { - static std::string symbol() { return "n"; } + static std::string symbol(); }; template <> struct ratio_string { - static std::string symbol() { return "u"; } + static std::string symbol(); }; template <> struct ratio_string { - static std::string symbol() { return "m"; } + static std::string symbol(); }; -namespace Catch { //////////// // std::chrono::duration specializations template struct StringMaker> { static std::string convert(std::chrono::duration const& duration) { - std::ostringstream oss; - oss << duration.count() << ' ' << ratio_string::symbol() << 's'; - return oss.str(); + ReusableStringStream rss; + rss << duration.count() << ' ' << ratio_string::symbol() << 's'; + return rss.str(); } }; template struct StringMaker>> { static std::string convert(std::chrono::duration> const& duration) { - std::ostringstream oss; - oss << duration.count() << " s"; - return oss.str(); + ReusableStringStream rss; + rss << duration.count() << " s"; + return rss.str(); } }; template struct StringMaker>> { static std::string convert(std::chrono::duration> const& duration) { - std::ostringstream oss; - oss << duration.count() << " m"; - return oss.str(); + ReusableStringStream rss; + rss << duration.count() << " m"; + return rss.str(); } }; template struct StringMaker>> { static std::string convert(std::chrono::duration> const& duration) { - std::ostringstream oss; - oss << duration.count() << " h"; - return oss.str(); + ReusableStringStream rss; + rss << duration.count() << " h"; + return rss.str(); } }; @@ -972,7 +1361,7 @@ namespace Catch { #endif // end catch_tostring.h -#include +#include #ifdef _MSC_VER #pragma warning(push) @@ -985,27 +1374,32 @@ namespace Catch { namespace Catch { struct ITransientExpression { - virtual auto isBinaryExpression() const -> bool = 0; - virtual auto getResult() const -> bool = 0; + auto isBinaryExpression() const -> bool { return m_isBinaryExpression; } + auto getResult() const -> bool { return m_result; } virtual void streamReconstructedExpression( std::ostream &os ) const = 0; - // We don't actually need a virtual destructore, but many static analysers + ITransientExpression( bool isBinaryExpression, bool result ) + : m_isBinaryExpression( isBinaryExpression ), + m_result( result ) + {} + + // We don't actually need a virtual destructor, but many static analysers // complain if it's not here :-( virtual ~ITransientExpression(); + + bool m_isBinaryExpression; + bool m_result; + }; void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ); template class BinaryExpr : public ITransientExpression { - bool m_result; LhsT m_lhs; StringRef m_op; RhsT m_rhs; - auto isBinaryExpression() const -> bool override { return true; } - auto getResult() const -> bool override { return m_result; } - void streamReconstructedExpression( std::ostream &os ) const override { formatReconstructedExpression ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) ); @@ -1013,7 +1407,7 @@ namespace Catch { public: BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs ) - : m_result( comparisonResult ), + : ITransientExpression{ true, comparisonResult }, m_lhs( lhs ), m_op( op ), m_rhs( rhs ) @@ -1024,20 +1418,20 @@ namespace Catch { class UnaryExpr : public ITransientExpression { LhsT m_lhs; - auto isBinaryExpression() const -> bool override { return false; } - auto getResult() const -> bool override { return m_lhs ? true : false; } - void streamReconstructedExpression( std::ostream &os ) const override { os << Catch::Detail::stringify( m_lhs ); } public: - UnaryExpr( LhsT lhs ) : m_lhs( lhs ) {} + explicit UnaryExpr( LhsT lhs ) + : ITransientExpression{ false, lhs ? true : false }, + m_lhs( lhs ) + {} }; // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int) template - auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return lhs == rhs; }; + auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast(lhs == rhs); } template auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast( rhs ); } template @@ -1048,7 +1442,7 @@ namespace Catch { auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) == rhs; } template - auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return lhs != rhs; }; + auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast(lhs != rhs); } template auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast( rhs ); } template @@ -1062,43 +1456,43 @@ namespace Catch { class ExprLhs { LhsT m_lhs; public: - ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} + explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} template auto operator == ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( compareEqual( m_lhs, rhs ), m_lhs, "==", rhs ); + return { compareEqual( m_lhs, rhs ), m_lhs, "==", rhs }; } auto operator == ( bool rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs == rhs, m_lhs, "==", rhs ); + return { m_lhs == rhs, m_lhs, "==", rhs }; } template auto operator != ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs ); + return { compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs }; } auto operator != ( bool rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs != rhs, m_lhs, "!=", rhs ); + return { m_lhs != rhs, m_lhs, "!=", rhs }; } template auto operator > ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs > rhs, m_lhs, ">", rhs ); + return { static_cast(m_lhs > rhs), m_lhs, ">", rhs }; } template auto operator < ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs < rhs, m_lhs, "<", rhs ); + return { static_cast(m_lhs < rhs), m_lhs, "<", rhs }; } template auto operator >= ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs >= rhs, m_lhs, ">=", rhs ); + return { static_cast(m_lhs >= rhs), m_lhs, ">=", rhs }; } template auto operator <= ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs <= rhs, m_lhs, "<=", rhs ); + return { static_cast(m_lhs <= rhs), m_lhs, "<=", rhs }; } auto makeUnaryExpr() const -> UnaryExpr { - return UnaryExpr( m_lhs ); + return UnaryExpr{ m_lhs }; } }; @@ -1112,10 +1506,11 @@ namespace Catch { struct Decomposer { template auto operator <= ( T const& lhs ) -> ExprLhs { - return ExprLhs( lhs ); + return ExprLhs{ lhs }; } + auto operator <=( bool value ) -> ExprLhs { - return ExprLhs( value ); + return ExprLhs{ value }; } }; @@ -1126,79 +1521,92 @@ namespace Catch { #endif // end catch_decomposer.h -// start catch_assertioninfo.h +// start catch_interfaces_capture.h -// start catch_result_type.h +#include namespace Catch { - // ResultWas::OfType enum - struct ResultWas { enum OfType { - Unknown = -1, - Ok = 0, - Info = 1, - Warning = 2, - - FailureBit = 0x10, - - ExpressionFailed = FailureBit | 1, - ExplicitFailure = FailureBit | 2, - - Exception = 0x100 | FailureBit, - - ThrewException = Exception | 1, - DidntThrowException = Exception | 2, + class AssertionResult; + struct AssertionInfo; + struct SectionInfo; + struct SectionEndInfo; + struct MessageInfo; + struct Counts; + struct BenchmarkInfo; + struct BenchmarkStats; + struct AssertionReaction; + struct SourceLineInfo; - FatalErrorCondition = 0x200 | FailureBit + struct ITransientExpression; + struct IGeneratorTracker; - }; }; + struct IResultCapture { - bool isOk( ResultWas::OfType resultType ); - bool isJustInfo( int flags ); + virtual ~IResultCapture(); - // ResultDisposition::Flags enum - struct ResultDisposition { enum Flags { - Normal = 0x01, + virtual bool sectionStarted( SectionInfo const& sectionInfo, + Counts& assertions ) = 0; + virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; - ContinueOnFailure = 0x02, // Failures fail test, but execution continues - FalseTest = 0x04, // Prefix expression with ! - SuppressFail = 0x08 // Failures are reported but do not fail the test - }; }; + virtual auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0; - ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ); + virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0; + virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0; - bool shouldContinueOnFailure( int flags ); - bool isFalseTest( int flags ); - bool shouldSuppressFailure( int flags ); + virtual void pushScopedMessage( MessageInfo const& message ) = 0; + virtual void popScopedMessage( MessageInfo const& message ) = 0; -} // end namespace Catch + virtual void handleFatalErrorCondition( StringRef message ) = 0; -// end catch_result_type.h -namespace Catch { + virtual void handleExpr + ( AssertionInfo const& info, + ITransientExpression const& expr, + AssertionReaction& reaction ) = 0; + virtual void handleMessage + ( AssertionInfo const& info, + ResultWas::OfType resultType, + StringRef const& message, + AssertionReaction& reaction ) = 0; + virtual void handleUnexpectedExceptionNotThrown + ( AssertionInfo const& info, + AssertionReaction& reaction ) = 0; + virtual void handleUnexpectedInflightException + ( AssertionInfo const& info, + std::string const& message, + AssertionReaction& reaction ) = 0; + virtual void handleIncomplete + ( AssertionInfo const& info ) = 0; + virtual void handleNonExpr + ( AssertionInfo const &info, + ResultWas::OfType resultType, + AssertionReaction &reaction ) = 0; - struct AssertionInfo - { - StringRef macroName; - SourceLineInfo lineInfo; - StringRef capturedExpression; - ResultDisposition::Flags resultDisposition; + virtual bool lastAssertionPassed() = 0; + virtual void assertionPassed() = 0; - // We want to delete this constructor but a compiler bug in 4.8 means - // the struct is then treated as non-aggregate - //AssertionInfo() = delete; + // Deprecated, do not use: + virtual std::string getCurrentTestName() const = 0; + virtual const AssertionResult* getLastResult() const = 0; + virtual void exceptionEarlyReported() = 0; }; -} // end namespace Catch + IResultCapture& getResultCapture(); +} -// end catch_assertioninfo.h +// end catch_interfaces_capture.h namespace Catch { struct TestFailureException{}; struct AssertionResultData; + struct IResultCapture; + class RunContext; class LazyExpression { friend class AssertionHandler; friend struct AssertionStats; + friend class RunContext; ITransientExpression const* m_transientExpression = nullptr; bool m_isNegated; @@ -1212,41 +1620,51 @@ namespace Catch { friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; }; + struct AssertionReaction { + bool shouldDebugBreak = false; + bool shouldThrow = false; + }; + class AssertionHandler { AssertionInfo m_assertionInfo; - bool m_shouldDebugBreak = false; - bool m_shouldThrow = false; - bool m_inExceptionGuard = false; + AssertionReaction m_reaction; + bool m_completed = false; + IResultCapture& m_resultCapture; public: AssertionHandler - ( StringRef macroName, + ( StringRef const& macroName, SourceLineInfo const& lineInfo, StringRef capturedExpression, ResultDisposition::Flags resultDisposition ); - ~AssertionHandler(); - - void handle( ITransientExpression const& expr ); + ~AssertionHandler() { + if ( !m_completed ) { + m_resultCapture.handleIncomplete( m_assertionInfo ); + } + } template - void handle( ExprLhs const& expr ) { - handle( expr.makeUnaryExpr() ); + void handleExpr( ExprLhs const& expr ) { + handleExpr( expr.makeUnaryExpr() ); } - void handle( ResultWas::OfType resultType ); - void handle( ResultWas::OfType resultType, StringRef const& message ); - void handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated ); - void handle( AssertionResultData const& resultData, ITransientExpression const* expr ); + void handleExpr( ITransientExpression const& expr ); + + void handleMessage(ResultWas::OfType resultType, StringRef const& message); - auto shouldDebugBreak() const -> bool; + void handleExceptionThrownAsExpected(); + void handleUnexpectedExceptionNotThrown(); + void handleExceptionNotThrownAsExpected(); + void handleThrowingCallSkipped(); + void handleUnexpectedInflightException(); + + void complete(); + void setCompleted(); + + // query auto allowThrows() const -> bool; - void reactWithDebugBreak() const; - void reactWithoutDebugBreak() const; - void useActiveException(); - void setExceptionGuard(); - void unsetExceptionGuard(); }; - void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ); + void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString ); } // namespace Catch @@ -1254,16 +1672,16 @@ namespace Catch { // start catch_message.h #include -#include +#include namespace Catch { struct MessageInfo { - MessageInfo( std::string const& _macroName, + MessageInfo( StringRef const& _macroName, SourceLineInfo const& _lineInfo, ResultWas::OfType _type ); - std::string macroName; + StringRef macroName; std::string message; SourceLineInfo lineInfo; ResultWas::OfType type; @@ -1283,12 +1701,11 @@ namespace Catch { return *this; } - // !TBD reuse a global/ thread-local stream - std::ostringstream m_stream; + ReusableStringStream m_stream; }; struct MessageBuilder : MessageStream { - MessageBuilder( std::string const& macroName, + MessageBuilder( StringRef const& macroName, SourceLineInfo const& lineInfo, ResultWas::OfType type ); @@ -1303,98 +1720,37 @@ namespace Catch { class ScopedMessage { public: - ScopedMessage( MessageBuilder const& builder ); + explicit ScopedMessage( MessageBuilder const& builder ); ~ScopedMessage(); MessageInfo m_info; }; -} // end namespace Catch - -// end catch_message.h -// start catch_interfaces_capture.h - -#include - -namespace Catch { - - class AssertionResult; - struct AssertionInfo; - struct SectionInfo; - struct SectionEndInfo; - struct MessageInfo; - struct Counts; - struct BenchmarkInfo; - struct BenchmarkStats; - - struct IResultCapture { - - virtual ~IResultCapture(); - - virtual void assertionStarting( AssertionInfo const& info ) = 0; - virtual void assertionEnded( AssertionResult const& result ) = 0; - virtual bool sectionStarted( SectionInfo const& sectionInfo, - Counts& assertions ) = 0; - virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; - virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; - - virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0; - virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0; - - virtual void pushScopedMessage( MessageInfo const& message ) = 0; - virtual void popScopedMessage( MessageInfo const& message ) = 0; - - virtual std::string getCurrentTestName() const = 0; - virtual const AssertionResult* getLastResult() const = 0; + class Capturer { + std::vector m_messages; + IResultCapture& m_resultCapture = getResultCapture(); + size_t m_captured = 0; + public: + Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ); + ~Capturer(); - virtual void exceptionEarlyReported() = 0; + void captureValue( size_t index, StringRef value ); - virtual void handleFatalErrorCondition( StringRef message ) = 0; + template + void captureValues( size_t index, T&& value ) { + captureValue( index, Catch::Detail::stringify( value ) ); + } - virtual bool lastAssertionPassed() = 0; - virtual void assertionPassed() = 0; - virtual void assertionRun() = 0; + template + void captureValues( size_t index, T&& value, Ts&&... values ) { + captureValues( index, value ); + captureValues( index+1, values... ); + } }; - IResultCapture& getResultCapture(); -} - -// end catch_interfaces_capture.h -// start catch_debugger.h - -namespace Catch { - bool isDebuggerActive(); -} - -#ifdef CATCH_PLATFORM_MAC - - #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ - -#elif defined(CATCH_PLATFORM_LINUX) - // If we can use inline assembler, do it because this allows us to break - // directly at the location of the failing check instead of breaking inside - // raise() called from it, i.e. one stack frame below. - #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) - #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */ - #else // Fall back to the generic way. - #include - - #define CATCH_TRAP() raise(SIGTRAP) - #endif -#elif defined(_MSC_VER) - #define CATCH_TRAP() __debugbreak() -#elif defined(__MINGW32__) - extern "C" __declspec(dllimport) void __stdcall DebugBreak(); - #define CATCH_TRAP() DebugBreak() -#endif - -#ifdef CATCH_TRAP - #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } -#else - #define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); -#endif +} // end namespace Catch -// end catch_debugger.h +// end catch_message.h #if !defined(CATCH_CONFIG_DISABLE) #if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) @@ -1403,49 +1759,34 @@ namespace Catch { #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION" #endif -#if defined(CATCH_CONFIG_FAST_COMPILE) -/////////////////////////////////////////////////////////////////////////////// -// We can speedup compilation significantly by breaking into debugger lower in -// the callstack, because then we don't have to expand CATCH_BREAK_INTO_DEBUGGER -// macro in each assertion -#define INTERNAL_CATCH_REACT( handler ) \ - handler.reactWithDebugBreak(); +#if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) /////////////////////////////////////////////////////////////////////////////// // Another way to speed-up compilation is to omit local try-catch for REQUIRE* // macros. -// This can potentially cause false negative, if the test code catches -// the exception before it propagates back up to the runner. -#define INTERNAL_CATCH_TRY( capturer ) capturer.setExceptionGuard(); -#define INTERNAL_CATCH_CATCH( capturer ) capturer.unsetExceptionGuard(); +#define INTERNAL_CATCH_TRY +#define INTERNAL_CATCH_CATCH( capturer ) #else // CATCH_CONFIG_FAST_COMPILE -/////////////////////////////////////////////////////////////////////////////// -// In the event of a failure works out if the debugger needs to be invoked -// and/or an exception thrown and takes appropriate action. -// This needs to be done as a macro so the debugger will stop in the user -// source code rather than in Catch library code -#define INTERNAL_CATCH_REACT( handler ) \ - if( handler.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ - handler.reactWithoutDebugBreak(); - -#define INTERNAL_CATCH_TRY( capturer ) try -#define INTERNAL_CATCH_CATCH( capturer ) catch(...) { capturer.useActiveException(); } +#define INTERNAL_CATCH_TRY try +#define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); } #endif +#define INTERNAL_CATCH_REACT( handler ) handler.complete(); + /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ - INTERNAL_CATCH_TRY( catchAssertionHandler ) { \ + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ + INTERNAL_CATCH_TRY { \ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - catchAssertionHandler.handle( Catch::Decomposer() <= __VA_ARGS__ ); \ + catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \ CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::isTrue( false && static_cast( !!(__VA_ARGS__) ) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look + } while( (void)0, false && static_cast( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. /////////////////////////////////////////////////////////////////////////////// @@ -1461,83 +1802,88 @@ namespace Catch { /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \ do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ try { \ static_cast(__VA_ARGS__); \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleExceptionNotThrownAsExpected(); \ } \ catch( ... ) { \ - catchAssertionHandler.useActiveException(); \ + catchAssertionHandler.handleUnexpectedInflightException(); \ } \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \ do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \ + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \ if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast(__VA_ARGS__); \ - catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ catch( ... ) { \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleExceptionThrownAsExpected(); \ } \ else \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleThrowingCallSkipped(); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \ + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \ if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast(expr); \ - catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ catch( exceptionType const& ) { \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleExceptionThrownAsExpected(); \ } \ catch( ... ) { \ - catchAssertionHandler.useActiveException(); \ + catchAssertionHandler.handleUnexpectedInflightException(); \ } \ else \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleThrowingCallSkipped(); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ - catchAssertionHandler.handle( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \ + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \ + catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \ + auto varName = Catch::Capturer( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \ + varName.captureValues( 0, __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_INFO( macroName, log ) \ - Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; + Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ); /////////////////////////////////////////////////////////////////////////////// // Although this is matcher-based, it can be used with just a string #define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \ do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast(__VA_ARGS__); \ - catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ catch( ... ) { \ - handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \ + Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher##_catch_sr ); \ } \ else \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleThrowingCallSkipped(); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) #endif // CATCH_CONFIG_DISABLE @@ -1572,6 +1918,7 @@ namespace Catch { Totals delta( Totals const& prevTotals ) const; + int error = 0; Counts assertions; Counts testCases; }; @@ -1583,19 +1930,22 @@ namespace Catch { namespace Catch { struct SectionInfo { + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name ); + + // Deprecated SectionInfo ( SourceLineInfo const& _lineInfo, std::string const& _name, - std::string const& _description = std::string() ); + std::string const& ) : SectionInfo( _lineInfo, _name ) {} std::string name; - std::string description; + std::string description; // !Deprecated: this will always be empty SourceLineInfo lineInfo; }; struct SectionEndInfo { - SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ); - SectionInfo sectionInfo; Counts prevAssertions; double durationInSeconds; @@ -1617,8 +1967,8 @@ namespace Catch { uint64_t m_nanoseconds = 0; public: void start(); - auto getElapsedNanoseconds() const -> unsigned int; - auto getElapsedMicroseconds() const -> unsigned int; + auto getElapsedNanoseconds() const -> uint64_t; + auto getElapsedMicroseconds() const -> uint64_t; auto getElapsedMilliseconds() const -> unsigned int; auto getElapsedSeconds() const -> double; }; @@ -1649,8 +1999,15 @@ namespace Catch { } // end namespace Catch - #define INTERNAL_CATCH_SECTION( ... ) \ - if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) +#define INTERNAL_CATCH_SECTION( ... ) \ + CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \ + CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS + +#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ + CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \ + CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS // end catch_section.h // start catch_benchmark.h @@ -1726,7 +2083,7 @@ namespace Catch { virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; - virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; + virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0; virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0; }; @@ -1741,7 +2098,7 @@ namespace Catch { virtual void registerStartupException() noexcept = 0; }; - IRegistryHub& getRegistryHub(); + IRegistryHub const& getRegistryHub(); IMutableRegistryHub& getMutableRegistryHub(); void cleanUp(); std::string translateActiveException(); @@ -1812,7 +2169,9 @@ namespace Catch { /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \ static std::string translatorName( signature ); \ - namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); }\ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ static std::string translatorName( signature ) #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) @@ -1820,21 +2179,6 @@ namespace Catch { // end catch_interfaces_exception.h // start catch_approx.h -// start catch_enforce.h - -#include -#include - -#define CATCH_PREPARE_EXCEPTION( type, msg ) \ - type( static_cast( std::ostringstream() << msg ).str() ) -#define CATCH_INTERNAL_ERROR( msg ) \ - throw CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg); -#define CATCH_ERROR( msg ) \ - throw CATCH_PREPARE_EXCEPTION( std::domain_error, msg ) -#define CATCH_ENFORCE( condition, msg ) \ - do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false) - -// end catch_enforce.h #include namespace Catch { @@ -1843,18 +2187,26 @@ namespace Detail { class Approx { private: bool equalityComparisonImpl(double other) const; + // Validates the new margin (margin >= 0) + // out-of-line to avoid including stdexcept in the header + void setMargin(double margin); + // Validates the new epsilon (0 < epsilon < 1) + // out-of-line to avoid including stdexcept in the header + void setEpsilon(double epsilon); public: explicit Approx ( double value ); static Approx custom(); + Approx operator-() const; + template ::value>::type> Approx operator()( T const& value ) { Approx approx( static_cast(value) ); - approx.epsilon( m_epsilon ); - approx.margin( m_margin ); - approx.scale( m_scale ); + approx.m_epsilon = m_epsilon; + approx.m_margin = m_margin; + approx.m_scale = m_scale; return approx; } @@ -1906,20 +2258,14 @@ namespace Detail { template ::value>::type> Approx& epsilon( T const& newEpsilon ) { double epsilonAsDouble = static_cast(newEpsilon); - CATCH_ENFORCE(epsilonAsDouble >= 0 && epsilonAsDouble <= 1.0, - "Invalid Approx::epsilon: " << epsilonAsDouble - << ", Approx::epsilon has to be between 0 and 1"); - m_epsilon = epsilonAsDouble; + setEpsilon(epsilonAsDouble); return *this; } template ::value>::type> Approx& margin( T const& newMargin ) { double marginAsDouble = static_cast(newMargin); - CATCH_ENFORCE(marginAsDouble >= 0, - "Invalid Approx::margin: " << marginAsDouble - << ", Approx::Margin has to be non-negative."); - m_margin = marginAsDouble; + setMargin(marginAsDouble); return *this; } @@ -1937,7 +2283,12 @@ namespace Detail { double m_scale; double m_value; }; -} +} // end namespace Detail + +namespace literals { + Detail::Approx operator "" _a(long double val); + Detail::Approx operator "" _a(unsigned long long val); +} // end namespace literals template<> struct StringMaker { @@ -2004,6 +2355,11 @@ namespace Matchers { mutable std::string m_cachedToString; }; +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wnon-virtual-dtor" +#endif + template struct MatcherMethod { virtual bool match( ObjectT const& arg ) const = 0; @@ -2013,12 +2369,16 @@ namespace Matchers { virtual bool match( PtrT* arg ) const = 0; }; - template - struct MatcherBase : MatcherUntypedBase, MatcherMethod { +#ifdef __clang__ +# pragma clang diagnostic pop +#endif + + template + struct MatcherBase : MatcherUntypedBase, MatcherMethod { - MatchAllOf operator && ( MatcherBase const& other ) const; - MatchAnyOf operator || ( MatcherBase const& other ) const; - MatchNotOf operator ! () const; + MatchAllOf operator && ( MatcherBase const& other ) const; + MatchAnyOf operator || ( MatcherBase const& other ) const; + MatchNotOf operator ! () const; }; template @@ -2102,17 +2462,17 @@ namespace Matchers { MatcherBase const& m_underlyingMatcher; }; - template - MatchAllOf MatcherBase::operator && ( MatcherBase const& other ) const { - return MatchAllOf() && *this && other; + template + MatchAllOf MatcherBase::operator && ( MatcherBase const& other ) const { + return MatchAllOf() && *this && other; } - template - MatchAnyOf MatcherBase::operator || ( MatcherBase const& other ) const { - return MatchAnyOf() || *this || other; + template + MatchAnyOf MatcherBase::operator || ( MatcherBase const& other ) const { + return MatchAnyOf() || *this || other; } - template - MatchNotOf MatcherBase::operator ! () const { - return MatchNotOf( *this ); + template + MatchNotOf MatcherBase::operator ! () const { + return MatchNotOf( *this ); } } // namespace Impl @@ -2125,27 +2485,118 @@ using Matchers::Impl::MatcherBase; } // namespace Catch // end catch_matchers.h -// start catch_matchers_string.h +// start catch_matchers_floating.h -#include +#include +#include namespace Catch { namespace Matchers { - namespace StdString { + namespace Floating { - struct CasedString - { - CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ); - std::string adjustString( std::string const& str ) const; - std::string caseSensitivitySuffix() const; + enum class FloatingPointKind : uint8_t; - CaseSensitive::Choice m_caseSensitivity; - std::string m_str; + struct WithinAbsMatcher : MatcherBase { + WithinAbsMatcher(double target, double margin); + bool match(double const& matchee) const override; + std::string describe() const override; + private: + double m_target; + double m_margin; }; - struct StringMatcherBase : MatcherBase { - StringMatcherBase( std::string const& operation, CasedString const& comparator ); + struct WithinUlpsMatcher : MatcherBase { + WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType); + bool match(double const& matchee) const override; + std::string describe() const override; + private: + double m_target; + int m_ulps; + FloatingPointKind m_type; + }; + + } // namespace Floating + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff); + Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff); + Floating::WithinAbsMatcher WithinAbs(double target, double margin); + +} // namespace Matchers +} // namespace Catch + +// end catch_matchers_floating.h +// start catch_matchers_generic.hpp + +#include +#include + +namespace Catch { +namespace Matchers { +namespace Generic { + +namespace Detail { + std::string finalizeDescription(const std::string& desc); +} + +template +class PredicateMatcher : public MatcherBase { + std::function m_predicate; + std::string m_description; +public: + + PredicateMatcher(std::function const& elem, std::string const& descr) + :m_predicate(std::move(elem)), + m_description(Detail::finalizeDescription(descr)) + {} + + bool match( T const& item ) const override { + return m_predicate(item); + } + + std::string describe() const override { + return m_description; + } +}; + +} // namespace Generic + + // The following functions create the actual matcher objects. + // The user has to explicitly specify type to the function, because + // infering std::function is hard (but possible) and + // requires a lot of TMP. + template + Generic::PredicateMatcher Predicate(std::function const& predicate, std::string const& description = "") { + return Generic::PredicateMatcher(predicate, description); + } + +} // namespace Matchers +} // namespace Catch + +// end catch_matchers_generic.hpp +// start catch_matchers_string.h + +#include + +namespace Catch { +namespace Matchers { + + namespace StdString { + + struct CasedString + { + CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ); + std::string adjustString( std::string const& str ) const; + std::string caseSensitivitySuffix() const; + + CaseSensitive::Choice m_caseSensitivity; + std::string m_str; + }; + + struct StringMatcherBase : MatcherBase { + StringMatcherBase( std::string const& operation, CasedString const& comparator ); std::string describe() const override; CasedString m_comparator; @@ -2169,6 +2620,16 @@ namespace Matchers { bool match( std::string const& source ) const override; }; + struct RegexMatcher : MatcherBase { + RegexMatcher( std::string regex, CaseSensitive::Choice caseSensitivity ); + bool match( std::string const& matchee ) const override; + std::string describe() const override; + + private: + std::string m_regex; + CaseSensitive::Choice m_caseSensitivity; + }; + } // namespace StdString // The following functions create the actual matcher objects. @@ -2178,6 +2639,7 @@ namespace Matchers { StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + StdString::RegexMatcher Matches( std::string const& regex, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); } // namespace Matchers } // namespace Catch @@ -2185,13 +2647,36 @@ namespace Matchers { // end catch_matchers_string.h // start catch_matchers_vector.h +#include + namespace Catch { namespace Matchers { namespace Vector { + namespace Detail { + template + size_t count(InputIterator first, InputIterator last, T const& item) { + size_t cnt = 0; + for (; first != last; ++first) { + if (*first == item) { + ++cnt; + } + } + return cnt; + } + template + bool contains(InputIterator first, InputIterator last, T const& item) { + for (; first != last; ++first) { + if (*first == item) { + return true; + } + } + return false; + } + } template - struct ContainsElementMatcher : MatcherBase, T> { + struct ContainsElementMatcher : MatcherBase> { ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} @@ -2212,7 +2697,7 @@ namespace Matchers { }; template - struct ContainsMatcher : MatcherBase, std::vector > { + struct ContainsMatcher : MatcherBase> { ContainsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} @@ -2242,7 +2727,7 @@ namespace Matchers { }; template - struct EqualsMatcher : MatcherBase, std::vector > { + struct EqualsMatcher : MatcherBase> { EqualsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} @@ -2264,6 +2749,46 @@ namespace Matchers { std::vector const& m_comparator; }; + template + struct UnorderedEqualsMatcher : MatcherBase> { + UnorderedEqualsMatcher(std::vector const& target) : m_target(target) {} + bool match(std::vector const& vec) const override { + // Note: This is a reimplementation of std::is_permutation, + // because I don't want to include inside the common path + if (m_target.size() != vec.size()) { + return false; + } + auto lfirst = m_target.begin(), llast = m_target.end(); + auto rfirst = vec.begin(), rlast = vec.end(); + // Cut common prefix to optimize checking of permuted parts + while (lfirst != llast && *lfirst != *rfirst) { + ++lfirst; ++rfirst; + } + if (lfirst == llast) { + return true; + } + + for (auto mid = lfirst; mid != llast; ++mid) { + // Skip already counted items + if (Detail::contains(lfirst, mid, *mid)) { + continue; + } + size_t num_vec = Detail::count(rfirst, rlast, *mid); + if (num_vec == 0 || Detail::count(lfirst, llast, *mid) != num_vec) { + return false; + } + } + + return true; + } + + std::string describe() const override { + return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); + } + private: + std::vector const& m_target; + }; + } // namespace Vector // The following functions create the actual matcher objects. @@ -2284,6 +2809,11 @@ namespace Matchers { return Vector::EqualsMatcher( comparator ); } + template + Vector::UnorderedEqualsMatcher UnorderedEquals(std::vector const& target) { + return Vector::UnorderedEqualsMatcher(target); + } + } // namespace Matchers } // namespace Catch @@ -2295,18 +2825,14 @@ namespace Catch { ArgT const& m_arg; MatcherT m_matcher; StringRef m_matcherString; - bool m_result; public: - MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) - : m_arg( arg ), + MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) + : ITransientExpression{ true, matcher.match( arg ) }, + m_arg( arg ), m_matcher( matcher ), - m_matcherString( matcherString ), - m_result( matcher.match( arg ) ) + m_matcherString( matcherString ) {} - auto isBinaryExpression() const -> bool override { return true; } - auto getResult() const -> bool override { return m_result; } - void streamReconstructedExpression( std::ostream &os ) const override { auto matcherAsString = m_matcher.toString(); os << Catch::Detail::stringify( m_arg ) << ' '; @@ -2319,10 +2845,10 @@ namespace Catch { using StringMatcher = Matchers::Impl::MatcherBase; - void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ); + void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ); template - auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) -> MatchExpr { + auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) -> MatchExpr { return MatchExpr( arg, matcher, matcherString ); } @@ -2331,35 +2857,333 @@ namespace Catch { /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ - INTERNAL_CATCH_TRY( catchAssertionHandler ) { \ - catchAssertionHandler.handle( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \ + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ + INTERNAL_CATCH_TRY { \ + catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher##_catch_sr ) ); \ } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \ do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast(__VA_ARGS__ ); \ - catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ catch( exceptionType const& ex ) { \ - catchAssertionHandler.handle( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \ + catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher##_catch_sr ) ); \ } \ catch( ... ) { \ - catchAssertionHandler.useActiveException(); \ + catchAssertionHandler.handleUnexpectedInflightException(); \ } \ else \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleThrowingCallSkipped(); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) // end catch_capture_matchers.h #endif +// start catch_generators.hpp + +// start catch_interfaces_generatortracker.h + + +#include + +namespace Catch { + + namespace Generators { + class GeneratorBase { + protected: + size_t m_size = 0; + + public: + GeneratorBase( size_t size ) : m_size( size ) {} + virtual ~GeneratorBase(); + auto size() const -> size_t { return m_size; } + }; + using GeneratorBasePtr = std::unique_ptr; + + } // namespace Generators + + struct IGeneratorTracker { + virtual ~IGeneratorTracker(); + virtual auto hasGenerator() const -> bool = 0; + virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0; + virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0; + virtual auto getIndex() const -> std::size_t = 0; + }; + +} // namespace Catch + +// end catch_interfaces_generatortracker.h +// start catch_enforce.h + +#include + +namespace Catch { +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) + template + [[noreturn]] + void throw_exception(Ex const& e) { + throw e; + } +#else // ^^ Exceptions are enabled // Exceptions are disabled vv + [[noreturn]] + void throw_exception(std::exception const& e); +#endif +} // namespace Catch; + +#define CATCH_PREPARE_EXCEPTION( type, msg ) \ + type( ( Catch::ReusableStringStream() << msg ).str() ) +#define CATCH_INTERNAL_ERROR( msg ) \ + Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg)) +#define CATCH_ERROR( msg ) \ + Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::domain_error, msg )) +#define CATCH_RUNTIME_ERROR( msg ) \ + Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::runtime_error, msg )) +#define CATCH_ENFORCE( condition, msg ) \ + do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false) + +// end catch_enforce.h +#include +#include +#include + +#include + +namespace Catch { +namespace Generators { + + // !TBD move this into its own location? + namespace pf{ + template + std::unique_ptr make_unique( Args&&... args ) { + return std::unique_ptr(new T(std::forward(args)...)); + } + } + + template + struct IGenerator { + virtual ~IGenerator() {} + virtual auto get( size_t index ) const -> T = 0; + }; + + template + class SingleValueGenerator : public IGenerator { + T m_value; + public: + SingleValueGenerator( T const& value ) : m_value( value ) {} + + auto get( size_t ) const -> T override { + return m_value; + } + }; + + template + class FixedValuesGenerator : public IGenerator { + std::vector m_values; + + public: + FixedValuesGenerator( std::initializer_list values ) : m_values( values ) {} + + auto get( size_t index ) const -> T override { + return m_values[index]; + } + }; + + template + class RangeGenerator : public IGenerator { + T const m_first; + T const m_last; + + public: + RangeGenerator( T const& first, T const& last ) : m_first( first ), m_last( last ) { + assert( m_last > m_first ); + } + + auto get( size_t index ) const -> T override { + // ToDo:: introduce a safe cast to catch potential overflows + return static_cast(m_first+index); + } + }; + + template + struct NullGenerator : IGenerator { + auto get( size_t ) const -> T override { + CATCH_INTERNAL_ERROR("A Null Generator is always empty"); + } + }; + + template + class Generator { + std::unique_ptr> m_generator; + size_t m_size; + + public: + Generator( size_t size, std::unique_ptr> generator ) + : m_generator( std::move( generator ) ), + m_size( size ) + {} + + auto size() const -> size_t { return m_size; } + auto operator[]( size_t index ) const -> T { + assert( index < m_size ); + return m_generator->get( index ); + } + }; + + std::vector randomiseIndices( size_t selectionSize, size_t sourceSize ); + + template + class GeneratorRandomiser : public IGenerator { + Generator m_baseGenerator; + + std::vector m_indices; + public: + GeneratorRandomiser( Generator&& baseGenerator, size_t numberOfItems ) + : m_baseGenerator( std::move( baseGenerator ) ), + m_indices( randomiseIndices( numberOfItems, m_baseGenerator.size() ) ) + {} + + auto get( size_t index ) const -> T override { + return m_baseGenerator[m_indices[index]]; + } + }; + + template + struct RequiresASpecialisationFor; + + template + auto all() -> Generator { return RequiresASpecialisationFor(); } + + template<> + auto all() -> Generator; + + template + auto range( T const& first, T const& last ) -> Generator { + return Generator( (last-first), pf::make_unique>( first, last ) ); + } + + template + auto random( T const& first, T const& last ) -> Generator { + auto gen = range( first, last ); + auto size = gen.size(); + + return Generator( size, pf::make_unique>( std::move( gen ), size ) ); + } + template + auto random( size_t size ) -> Generator { + return Generator( size, pf::make_unique>( all(), size ) ); + } + + template + auto values( std::initializer_list values ) -> Generator { + return Generator( values.size(), pf::make_unique>( values ) ); + } + template + auto value( T const& val ) -> Generator { + return Generator( 1, pf::make_unique>( val ) ); + } + + template + auto as() -> Generator { + return Generator( 0, pf::make_unique>() ); + } + + template + auto table( std::initializer_list>&& tuples ) -> Generator> { + return values>( std::forward>>( tuples ) ); + } + + template + struct Generators : GeneratorBase { + std::vector> m_generators; + + using type = T; + + Generators() : GeneratorBase( 0 ) {} + + void populate( T&& val ) { + m_size += 1; + m_generators.emplace_back( value( std::move( val ) ) ); + } + template + void populate( U&& val ) { + populate( T( std::move( val ) ) ); + } + void populate( Generator&& generator ) { + m_size += generator.size(); + m_generators.emplace_back( std::move( generator ) ); + } + + template + void populate( U&& valueOrGenerator, Gs... moreGenerators ) { + populate( std::forward( valueOrGenerator ) ); + populate( std::forward( moreGenerators )... ); + } + + auto operator[]( size_t index ) const -> T { + size_t sizes = 0; + for( auto const& gen : m_generators ) { + auto localIndex = index-sizes; + sizes += gen.size(); + if( index < sizes ) + return gen[localIndex]; + } + CATCH_INTERNAL_ERROR("Index '" << index << "' is out of range (" << sizes << ')'); + } + }; + + template + auto makeGenerators( Generator&& generator, Gs... moreGenerators ) -> Generators { + Generators generators; + generators.m_generators.reserve( 1+sizeof...(Gs) ); + generators.populate( std::move( generator ), std::forward( moreGenerators )... ); + return generators; + } + template + auto makeGenerators( Generator&& generator ) -> Generators { + Generators generators; + generators.populate( std::move( generator ) ); + return generators; + } + template + auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators { + return makeGenerators( value( std::forward( val ) ), std::forward( moreGenerators )... ); + } + template + auto makeGenerators( U&& val, Gs... moreGenerators ) -> Generators { + return makeGenerators( value( T( std::forward( val ) ) ), std::forward( moreGenerators )... ); + } + + auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; + + template + // Note: The type after -> is weird, because VS2015 cannot parse + // the expression used in the typedef inside, when it is in + // return type. Yeah, ¯\_(ツ)_/¯ + auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval()[0]) { + using UnderlyingType = typename decltype(generatorExpression())::type; + + IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo ); + if( !tracker.hasGenerator() ) + tracker.setGenerator( pf::make_unique>( generatorExpression() ) ); + + auto const& generator = static_cast const&>( *tracker.getGenerator() ); + return generator[tracker.getIndex()]; + } + +} // namespace Generators +} // namespace Catch + +#define GENERATE( ... ) \ + Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, []{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) + +// end catch_generators.hpp // These files are included here so the single_include script doesn't put them // in the conditionally compiled sections @@ -2416,7 +3240,7 @@ namespace Catch { class TestCase : public TestCaseInfo { public: - TestCase( ITestInvoker* testCase, TestCaseInfo const& info ); + TestCase( ITestInvoker* testCase, TestCaseInfo&& info ); TestCase withName( std::string const& _newName ) const; @@ -2433,8 +3257,7 @@ namespace Catch { TestCase makeTestCase( ITestInvoker* testCase, std::string const& className, - std::string const& name, - std::string const& description, + NameAndTags const& nameAndTags, SourceLineInfo const& lineInfo ); } @@ -2537,7 +3360,7 @@ namespace Catch { std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); const char* className = class_getName( cls ); - getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo("",0) ) ); + getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, NameAndTags( name.c_str(), desc.c_str() ), SourceLineInfo("",0) ) ); noTestMethods++; } } @@ -2864,7 +3687,8 @@ namespace Catch { struct WarnAbout { enum What { Nothing = 0x00, - NoAssertions = 0x01 + NoAssertions = 0x01, + NoTests = 0x02 }; }; struct ShowDurations { enum OrNot { @@ -2901,10 +3725,12 @@ namespace Catch { virtual bool includeSuccessfulResults() const = 0; virtual bool shouldDebugBreak() const = 0; virtual bool warnAboutMissingAssertions() const = 0; + virtual bool warnAboutNoTests() const = 0; virtual int abortAfter() const = 0; virtual bool showInvisibles() const = 0; virtual ShowDurations::OrNot showDurations() const = 0; virtual TestSpec const& testSpec() const = 0; + virtual bool hasTestFilters() const = 0; virtual RunTests::InWhatOrder runOrder() const = 0; virtual unsigned int rngSeed() const = 0; virtual int benchmarkResolutionMultiple() const = 0; @@ -2918,81 +3744,18 @@ namespace Catch { // end catch_interfaces_config.h // Libstdc++ doesn't like incomplete classes for unique_ptr -// start catch_stream.h -// start catch_streambuf.h +#include +#include +#include -#include +#ifndef CATCH_CONFIG_CONSOLE_WIDTH +#define CATCH_CONFIG_CONSOLE_WIDTH 80 +#endif namespace Catch { - class StreamBufBase : public std::streambuf { - public: - virtual ~StreamBufBase(); - }; -} - -// end catch_streambuf.h -#include -#include -#include -#include - -namespace Catch { - - std::ostream& cout(); - std::ostream& cerr(); - std::ostream& clog(); - - struct IStream { - virtual ~IStream(); - virtual std::ostream& stream() const = 0; - }; - - class FileStream : public IStream { - mutable std::ofstream m_ofs; - public: - FileStream( std::string const& filename ); - ~FileStream() override = default; - public: // IStream - std::ostream& stream() const override; - }; - - class CoutStream : public IStream { - mutable std::ostream m_os; - public: - CoutStream(); - ~CoutStream() override = default; - - public: // IStream - std::ostream& stream() const override; - }; - - class DebugOutStream : public IStream { - std::unique_ptr m_streamBuf; - mutable std::ostream m_os; - public: - DebugOutStream(); - ~DebugOutStream() override = default; - - public: // IStream - std::ostream& stream() const override; - }; -} - -// end catch_stream.h - -#include -#include -#include - -#ifndef CATCH_CONFIG_CONSOLE_WIDTH -#define CATCH_CONFIG_CONSOLE_WIDTH 80 -#endif - -namespace Catch { - - struct IStream; + struct IStream; struct ConfigData { bool listTests = false; @@ -3022,8 +3785,12 @@ namespace Catch { std::string outputFilename; std::string name; std::string processName; +#ifndef CATCH_CONFIG_DEFAULT_REPORTER +#define CATCH_CONFIG_DEFAULT_REPORTER "console" +#endif + std::string reporterName = CATCH_CONFIG_DEFAULT_REPORTER; +#undef CATCH_CONFIG_DEFAULT_REPORTER - std::vector reporterNames; std::vector testsOrTags; std::vector sectionsToRun; }; @@ -3043,11 +3810,13 @@ namespace Catch { bool listReporters() const; std::string getProcessName() const; + std::string const& getReporterName() const; - std::vector const& getReporterNames() const; + std::vector const& getTestsOrTags() const; std::vector const& getSectionsToRun() const override; virtual TestSpec const& testSpec() const override; + bool hasTestFilters() const override; bool showHelp() const; @@ -3057,6 +3826,7 @@ namespace Catch { std::string name() const override; bool includeSuccessfulResults() const override; bool warnAboutMissingAssertions() const override; + bool warnAboutNoTests() const override; ShowDurations::OrNot showDurations() const override; RunTests::InWhatOrder runOrder() const override; unsigned int rngSeed() const override; @@ -3074,6 +3844,7 @@ namespace Catch { std::unique_ptr m_stream; TestSpec m_testSpec; + bool m_hasTestFilters = false; }; } // end namespace Catch @@ -3115,7 +3886,7 @@ namespace Catch { std::string getExpandedExpression() const; std::string getMessage() const; SourceLineInfo getSourceInfo() const; - std::string getTestMacroName() const; + StringRef getTestMacroName() const; //protected: AssertionInfo m_info; @@ -3213,6 +3984,7 @@ namespace Catch { struct ReporterPreferences { bool shouldRedirectStdOut = false; + bool shouldReportAllAssertions = false; }; template @@ -3397,8 +4169,6 @@ namespace Catch { virtual Listeners const& getListeners() const = 0; }; - void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter ); - } // end namespace Catch // end catch_interfaces_reporter.h @@ -3406,8 +4176,9 @@ namespace Catch { #include #include #include -#include +#include #include +#include namespace Catch { void prepareExpandedExpression(AssertionResult& result); @@ -3423,7 +4194,8 @@ namespace Catch { stream( _config.stream() ) { m_reporterPrefs.shouldRedirectStdOut = false; - CATCH_ENFORCE( DerivedT::getSupportedVerbosities().count( m_config->verbosity() ), "Verbosity level not supported by this reporter" ); + if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) + CATCH_ERROR( "Verbosity level not supported by this reporter" ); } ReporterPreferences getPreferences() const override { @@ -3536,7 +4308,8 @@ namespace Catch { stream( _config.stream() ) { m_reporterPrefs.shouldRedirectStdOut = false; - CATCH_ENFORCE( DerivedT::getSupportedVerbosities().count( m_config->verbosity() ), "Verbosity level not supported by this reporter" ); + if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) + CATCH_ERROR( "Verbosity level not supported by this reporter" ); } ~CumulativeReporterBase() override = default; @@ -3681,10 +4454,11 @@ namespace Catch { BrightGreen = Bright | Green, LightGrey = Bright | Grey, BrightWhite = Bright | White, + BrightYellow = Bright | Yellow, // By intention FileName = LightGrey, - Warning = Yellow, + Warning = BrightYellow, ResultError = BrightRed, ResultSuccess = BrightGreen, ResultExpectedFailure = Warning, @@ -3693,7 +4467,7 @@ namespace Catch { Success = Green, OriginalExpression = Cyan, - ReconstructedExpression = Yellow, + ReconstructedExpression = BrightYellow, SecondaryText = LightGrey, Headers = White @@ -3738,7 +4512,7 @@ namespace Catch { public: - ReporterRegistrar( std::string const& name ) { + explicit ReporterRegistrar( std::string const& name ) { getMutableRegistryHub().registerReporter( name, std::make_shared() ); } }; @@ -3783,217 +4557,504 @@ namespace Catch { #endif // CATCH_CONFIG_DISABLE // end catch_reporter_registrars.hpp -// end catch_external_interfaces.h -#endif - -#ifdef CATCH_IMPL -// start catch_impl.hpp - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wweak-vtables" -#endif - -// Keep these here for external reporters -// start catch_test_case_tracker.h - -#include -#include -#include +// Allow users to base their work off existing reporters +// start catch_reporter_compact.h namespace Catch { -namespace TestCaseTracking { - struct NameAndLocation { - std::string name; - SourceLineInfo location; + struct CompactReporter : StreamingReporterBase { - NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); - }; + using StreamingReporterBase::StreamingReporterBase; - struct ITracker; + ~CompactReporter() override; - using ITrackerPtr = std::shared_ptr; + static std::string getDescription(); - struct ITracker { - virtual ~ITracker(); + ReporterPreferences getPreferences() const override; - // static queries - virtual NameAndLocation const& nameAndLocation() const = 0; + void noMatchingTestCases(std::string const& spec) override; - // dynamic queries - virtual bool isComplete() const = 0; // Successfully completed or failed - virtual bool isSuccessfullyCompleted() const = 0; - virtual bool isOpen() const = 0; // Started but not complete - virtual bool hasChildren() const = 0; + void assertionStarting(AssertionInfo const&) override; - virtual ITracker& parent() = 0; + bool assertionEnded(AssertionStats const& _assertionStats) override; - // actions - virtual void close() = 0; // Successfully complete - virtual void fail() = 0; - virtual void markAsNeedingAnotherRun() = 0; + void sectionEnded(SectionStats const& _sectionStats) override; - virtual void addChild( ITrackerPtr const& child ) = 0; - virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) = 0; - virtual void openChild() = 0; + void testRunEnded(TestRunStats const& _testRunStats) override; - // Debug/ checking - virtual bool isSectionTracker() const = 0; - virtual bool isIndexTracker() const = 0; }; - class TrackerContext { +} // end namespace Catch - enum RunState { - NotStarted, - Executing, - CompletedCycle - }; +// end catch_reporter_compact.h +// start catch_reporter_console.h - ITrackerPtr m_rootTracker; - ITracker* m_currentTracker = nullptr; - RunState m_runState = NotStarted; +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch + // Note that 4062 (not all labels are handled + // and default is missing) is enabled +#endif - public: +namespace Catch { + // Fwd decls + struct SummaryColumn; + class TablePrinter; - static TrackerContext& instance(); + struct ConsoleReporter : StreamingReporterBase { + std::unique_ptr m_tablePrinter; - ITracker& startRun(); - void endRun(); + ConsoleReporter(ReporterConfig const& config); + ~ConsoleReporter() override; + static std::string getDescription(); - void startCycle(); - void completeCycle(); + void noMatchingTestCases(std::string const& spec) override; - bool completedCycle() const; - ITracker& currentTracker(); - void setCurrentTracker( ITracker* tracker ); - }; + void assertionStarting(AssertionInfo const&) override; - class TrackerBase : public ITracker { - protected: - enum CycleState { - NotStarted, - Executing, - ExecutingChildren, - NeedsAnotherRun, - CompletedSuccessfully, - Failed - }; + bool assertionEnded(AssertionStats const& _assertionStats) override; - class TrackerHasName { - NameAndLocation m_nameAndLocation; - public: - TrackerHasName( NameAndLocation const& nameAndLocation ); - bool operator ()( ITrackerPtr const& tracker ) const; - }; + void sectionStarting(SectionInfo const& _sectionInfo) override; + void sectionEnded(SectionStats const& _sectionStats) override; - using Children = std::vector; - NameAndLocation m_nameAndLocation; - TrackerContext& m_ctx; - ITracker* m_parent; - Children m_children; - CycleState m_runState = NotStarted; + void benchmarkStarting(BenchmarkInfo const& info) override; + void benchmarkEnded(BenchmarkStats const& stats) override; - public: - TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); + void testCaseEnded(TestCaseStats const& _testCaseStats) override; + void testGroupEnded(TestGroupStats const& _testGroupStats) override; + void testRunEnded(TestRunStats const& _testRunStats) override; - NameAndLocation const& nameAndLocation() const override; - bool isComplete() const override; - bool isSuccessfullyCompleted() const override; - bool isOpen() const override; - bool hasChildren() const override; + private: - void addChild( ITrackerPtr const& child ) override; + void lazyPrint(); - ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override; - ITracker& parent() override; + void lazyPrintWithoutClosingBenchmarkTable(); + void lazyPrintRunInfo(); + void lazyPrintGroupInfo(); + void printTestCaseAndSectionHeader(); - void openChild() override; + void printClosedHeader(std::string const& _name); + void printOpenHeader(std::string const& _name); - bool isSectionTracker() const override; - bool isIndexTracker() const override; + // if string has a : in first line will set indent to follow it on + // subsequent lines + void printHeaderString(std::string const& _string, std::size_t indent = 0); - void open(); + void printTotals(Totals const& totals); + void printSummaryRow(std::string const& label, std::vector const& cols, std::size_t row); - void close() override; - void fail() override; - void markAsNeedingAnotherRun() override; + void printTotalsDivider(Totals const& totals); + void printSummaryDivider(); private: - void moveToParent(); - void moveToThis(); + bool m_headerPrinted = false; }; - class SectionTracker : public TrackerBase { - std::vector m_filters; - public: - SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); +} // end namespace Catch - bool isSectionTracker() const override; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif - static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ); +// end catch_reporter_console.h +// start catch_reporter_junit.h - void tryOpen(); +// start catch_xmlwriter.h - void addInitialFilters( std::vector const& filters ); - void addNextFilters( std::vector const& filters ); - }; +#include - class IndexTracker : public TrackerBase { - int m_size; - int m_index = -1; +namespace Catch { + + class XmlEncode { public: - IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ); + enum ForWhat { ForTextNodes, ForAttributes }; - bool isIndexTracker() const override; - void close() override; + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); - static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ); + void encodeTo( std::ostream& os ) const; - int index() const; + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); - void moveNext(); + private: + std::string m_str; + ForWhat m_forWhat; }; -} // namespace TestCaseTracking + class XmlWriter { + public: -using TestCaseTracking::ITracker; -using TestCaseTracking::TrackerContext; -using TestCaseTracking::SectionTracker; -using TestCaseTracking::IndexTracker; + class ScopedElement { + public: + ScopedElement( XmlWriter* writer ); -} // namespace Catch + ScopedElement( ScopedElement&& other ) noexcept; + ScopedElement& operator=( ScopedElement&& other ) noexcept; -// end catch_test_case_tracker.h + ~ScopedElement(); -// start catch_leak_detector.h + ScopedElement& writeText( std::string const& text, bool indent = true ); -namespace Catch { + template + ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { + m_writer->writeAttribute( name, attribute ); + return *this; + } - struct LeakDetector { - LeakDetector(); - }; + private: + mutable XmlWriter* m_writer = nullptr; + }; -} -// end catch_leak_detector.h -// Cpp files will be included in the single-header file here -// start catch_approx.cpp + XmlWriter( std::ostream& os = Catch::cout() ); + ~XmlWriter(); -#include -#include + XmlWriter( XmlWriter const& ) = delete; + XmlWriter& operator=( XmlWriter const& ) = delete; -namespace { + XmlWriter& startElement( std::string const& name ); -// Performs equivalent check of std::fabs(lhs - rhs) <= margin -// But without the subtraction to allow for INFINITY in comparison -bool marginComparison(double lhs, double rhs, double margin) { - return (lhs + margin >= rhs) && (rhs + margin >= lhs); -} + ScopedElement scopedElement( std::string const& name ); -} + XmlWriter& endElement(); -namespace Catch { + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); + + XmlWriter& writeAttribute( std::string const& name, bool attribute ); + + template + XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { + ReusableStringStream rss; + rss << attribute; + return writeAttribute( name, rss.str() ); + } + + XmlWriter& writeText( std::string const& text, bool indent = true ); + + XmlWriter& writeComment( std::string const& text ); + + void writeStylesheetRef( std::string const& url ); + + XmlWriter& writeBlankLine(); + + void ensureTagClosed(); + + private: + + void writeDeclaration(); + + void newlineIfNecessary(); + + bool m_tagIsOpen = false; + bool m_needsNewline = false; + std::vector m_tags; + std::string m_indent; + std::ostream& m_os; + }; + +} + +// end catch_xmlwriter.h +namespace Catch { + + class JunitReporter : public CumulativeReporterBase { + public: + JunitReporter(ReporterConfig const& _config); + + ~JunitReporter() override; + + static std::string getDescription(); + + void noMatchingTestCases(std::string const& /*spec*/) override; + + void testRunStarting(TestRunInfo const& runInfo) override; + + void testGroupStarting(GroupInfo const& groupInfo) override; + + void testCaseStarting(TestCaseInfo const& testCaseInfo) override; + bool assertionEnded(AssertionStats const& assertionStats) override; + + void testCaseEnded(TestCaseStats const& testCaseStats) override; + + void testGroupEnded(TestGroupStats const& testGroupStats) override; + + void testRunEndedCumulative() override; + + void writeGroup(TestGroupNode const& groupNode, double suiteTime); + + void writeTestCase(TestCaseNode const& testCaseNode); + + void writeSection(std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode); + + void writeAssertions(SectionNode const& sectionNode); + void writeAssertion(AssertionStats const& stats); + + XmlWriter xml; + Timer suiteTimer; + std::string stdOutForSuite; + std::string stdErrForSuite; + unsigned int unexpectedExceptions = 0; + bool m_okToFail = false; + }; + +} // end namespace Catch + +// end catch_reporter_junit.h +// start catch_reporter_xml.h + +namespace Catch { + class XmlReporter : public StreamingReporterBase { + public: + XmlReporter(ReporterConfig const& _config); + + ~XmlReporter() override; + + static std::string getDescription(); + + virtual std::string getStylesheetRef() const; + + void writeSourceInfo(SourceLineInfo const& sourceInfo); + + public: // StreamingReporterBase + + void noMatchingTestCases(std::string const& s) override; + + void testRunStarting(TestRunInfo const& testInfo) override; + + void testGroupStarting(GroupInfo const& groupInfo) override; + + void testCaseStarting(TestCaseInfo const& testInfo) override; + + void sectionStarting(SectionInfo const& sectionInfo) override; + + void assertionStarting(AssertionInfo const&) override; + + bool assertionEnded(AssertionStats const& assertionStats) override; + + void sectionEnded(SectionStats const& sectionStats) override; + + void testCaseEnded(TestCaseStats const& testCaseStats) override; + + void testGroupEnded(TestGroupStats const& testGroupStats) override; + + void testRunEnded(TestRunStats const& testRunStats) override; + + private: + Timer m_testCaseTimer; + XmlWriter m_xml; + int m_sectionDepth = 0; + }; + +} // end namespace Catch + +// end catch_reporter_xml.h + +// end catch_external_interfaces.h +#endif + +#endif // ! CATCH_CONFIG_IMPL_ONLY + +#ifdef CATCH_IMPL +// start catch_impl.hpp + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +// Keep these here for external reporters +// start catch_test_case_tracker.h + +#include +#include +#include + +namespace Catch { +namespace TestCaseTracking { + + struct NameAndLocation { + std::string name; + SourceLineInfo location; + + NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); + }; + + struct ITracker; + + using ITrackerPtr = std::shared_ptr; + + struct ITracker { + virtual ~ITracker(); + + // static queries + virtual NameAndLocation const& nameAndLocation() const = 0; + + // dynamic queries + virtual bool isComplete() const = 0; // Successfully completed or failed + virtual bool isSuccessfullyCompleted() const = 0; + virtual bool isOpen() const = 0; // Started but not complete + virtual bool hasChildren() const = 0; + + virtual ITracker& parent() = 0; + + // actions + virtual void close() = 0; // Successfully complete + virtual void fail() = 0; + virtual void markAsNeedingAnotherRun() = 0; + + virtual void addChild( ITrackerPtr const& child ) = 0; + virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) = 0; + virtual void openChild() = 0; + + // Debug/ checking + virtual bool isSectionTracker() const = 0; + virtual bool isIndexTracker() const = 0; + }; + + class TrackerContext { + + enum RunState { + NotStarted, + Executing, + CompletedCycle + }; + + ITrackerPtr m_rootTracker; + ITracker* m_currentTracker = nullptr; + RunState m_runState = NotStarted; + + public: + + static TrackerContext& instance(); + + ITracker& startRun(); + void endRun(); + + void startCycle(); + void completeCycle(); + + bool completedCycle() const; + ITracker& currentTracker(); + void setCurrentTracker( ITracker* tracker ); + }; + + class TrackerBase : public ITracker { + protected: + enum CycleState { + NotStarted, + Executing, + ExecutingChildren, + NeedsAnotherRun, + CompletedSuccessfully, + Failed + }; + + using Children = std::vector; + NameAndLocation m_nameAndLocation; + TrackerContext& m_ctx; + ITracker* m_parent; + Children m_children; + CycleState m_runState = NotStarted; + + public: + TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); + + NameAndLocation const& nameAndLocation() const override; + bool isComplete() const override; + bool isSuccessfullyCompleted() const override; + bool isOpen() const override; + bool hasChildren() const override; + + void addChild( ITrackerPtr const& child ) override; + + ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override; + ITracker& parent() override; + + void openChild() override; + + bool isSectionTracker() const override; + bool isIndexTracker() const override; + + void open(); + + void close() override; + void fail() override; + void markAsNeedingAnotherRun() override; + + private: + void moveToParent(); + void moveToThis(); + }; + + class SectionTracker : public TrackerBase { + std::vector m_filters; + public: + SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); + + bool isSectionTracker() const override; + + static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ); + + void tryOpen(); + + void addInitialFilters( std::vector const& filters ); + void addNextFilters( std::vector const& filters ); + }; + + class IndexTracker : public TrackerBase { + int m_size; + int m_index = -1; + public: + IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ); + + bool isIndexTracker() const override; + void close() override; + + static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ); + + int index() const; + + void moveNext(); + }; + +} // namespace TestCaseTracking + +using TestCaseTracking::ITracker; +using TestCaseTracking::TrackerContext; +using TestCaseTracking::SectionTracker; +using TestCaseTracking::IndexTracker; + +} // namespace Catch + +// end catch_test_case_tracker.h + +// start catch_leak_detector.h + +namespace Catch { + + struct LeakDetector { + LeakDetector(); + }; + +} +// end catch_leak_detector.h +// Cpp files will be included in the single-header file here +// start catch_approx.cpp + +#include +#include + +namespace { + +// Performs equivalent check of std::fabs(lhs - rhs) <= margin +// But without the subtraction to allow for INFINITY in comparison +bool marginComparison(double lhs, double rhs, double margin) { + return (lhs + margin >= rhs) && (rhs + margin >= lhs); +} + +} + +namespace Catch { namespace Detail { Approx::Approx ( double value ) @@ -4007,70 +5068,364 @@ namespace Detail { return Approx( 0 ); } - std::string Approx::toString() const { - std::ostringstream oss; - oss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )"; - return oss.str(); - } + Approx Approx::operator-() const { + auto temp(*this); + temp.m_value = -temp.m_value; + return temp; + } + + std::string Approx::toString() const { + ReusableStringStream rss; + rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )"; + return rss.str(); + } + + bool Approx::equalityComparisonImpl(const double other) const { + // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value + // Thanks to Richard Harris for his help refining the scaled margin value + return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value))); + } + + void Approx::setMargin(double margin) { + CATCH_ENFORCE(margin >= 0, + "Invalid Approx::margin: " << margin << '.' + << " Approx::Margin has to be non-negative."); + m_margin = margin; + } + + void Approx::setEpsilon(double epsilon) { + CATCH_ENFORCE(epsilon >= 0 && epsilon <= 1.0, + "Invalid Approx::epsilon: " << epsilon << '.' + << " Approx::epsilon has to be in [0, 1]"); + m_epsilon = epsilon; + } + +} // end namespace Detail + +namespace literals { + Detail::Approx operator "" _a(long double val) { + return Detail::Approx(val); + } + Detail::Approx operator "" _a(unsigned long long val) { + return Detail::Approx(val); + } +} // end namespace literals + +std::string StringMaker::convert(Catch::Detail::Approx const& value) { + return value.toString(); +} + +} // end namespace Catch +// end catch_approx.cpp +// start catch_assertionhandler.cpp + +// start catch_context.h + +#include + +namespace Catch { + + struct IResultCapture; + struct IRunner; + struct IConfig; + struct IMutableContext; + + using IConfigPtr = std::shared_ptr; + + struct IContext + { + virtual ~IContext(); + + virtual IResultCapture* getResultCapture() = 0; + virtual IRunner* getRunner() = 0; + virtual IConfigPtr const& getConfig() const = 0; + }; + + struct IMutableContext : IContext + { + virtual ~IMutableContext(); + virtual void setResultCapture( IResultCapture* resultCapture ) = 0; + virtual void setRunner( IRunner* runner ) = 0; + virtual void setConfig( IConfigPtr const& config ) = 0; + + private: + static IMutableContext *currentContext; + friend IMutableContext& getCurrentMutableContext(); + friend void cleanUpContext(); + static void createContext(); + }; + + inline IMutableContext& getCurrentMutableContext() + { + if( !IMutableContext::currentContext ) + IMutableContext::createContext(); + return *IMutableContext::currentContext; + } + + inline IContext& getCurrentContext() + { + return getCurrentMutableContext(); + } + + void cleanUpContext(); +} + +// end catch_context.h +// start catch_debugger.h + +namespace Catch { + bool isDebuggerActive(); +} + +#ifdef CATCH_PLATFORM_MAC + + #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ + +#elif defined(CATCH_PLATFORM_LINUX) + // If we can use inline assembler, do it because this allows us to break + // directly at the location of the failing check instead of breaking inside + // raise() called from it, i.e. one stack frame below. + #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) + #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */ + #else // Fall back to the generic way. + #include + + #define CATCH_TRAP() raise(SIGTRAP) + #endif +#elif defined(_MSC_VER) + #define CATCH_TRAP() __debugbreak() +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) void __stdcall DebugBreak(); + #define CATCH_TRAP() DebugBreak() +#endif + +#ifdef CATCH_TRAP + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } +#else + namespace Catch { + inline void doNothing() {} + } + #define CATCH_BREAK_INTO_DEBUGGER() Catch::doNothing() +#endif + +// end catch_debugger.h +// start catch_run_context.h + +// start catch_fatal_condition.h + +// start catch_windows_h_proxy.h + + +#if defined(CATCH_PLATFORM_WINDOWS) + +#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) +# define CATCH_DEFINED_NOMINMAX +# define NOMINMAX +#endif +#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) +# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif + +#ifdef __AFXDLL +#include +#else +#include +#endif + +#ifdef CATCH_DEFINED_NOMINMAX +# undef NOMINMAX +#endif +#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN +# undef WIN32_LEAN_AND_MEAN +#endif + +#endif // defined(CATCH_PLATFORM_WINDOWS) + +// end catch_windows_h_proxy.h +#if defined( CATCH_CONFIG_WINDOWS_SEH ) + +namespace Catch { - bool Approx::equalityComparisonImpl(const double other) const { - // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value - // Thanks to Richard Harris for his help refining the scaled margin value - return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value))); - } + struct FatalConditionHandler { -} // end namespace Detail + static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo); + FatalConditionHandler(); + static void reset(); + ~FatalConditionHandler(); -std::string StringMaker::convert(Catch::Detail::Approx const& value) { - return value.toString(); -} + private: + static bool isSet; + static ULONG guaranteeSize; + static PVOID exceptionHandlerHandle; + }; -} // end namespace Catch -// end catch_approx.cpp -// start catch_assertionhandler.cpp +} // namespace Catch -// start catch_context.h +#elif defined ( CATCH_CONFIG_POSIX_SIGNALS ) -#include +#include namespace Catch { - struct IResultCapture; - struct IRunner; - struct IConfig; + struct FatalConditionHandler { - using IConfigPtr = std::shared_ptr; + static bool isSet; + static struct sigaction oldSigActions[]; + static stack_t oldSigStack; + static char altStackMem[]; - struct IContext - { - virtual ~IContext(); + static void handleSignal( int sig ); - virtual IResultCapture* getResultCapture() = 0; - virtual IRunner* getRunner() = 0; - virtual IConfigPtr getConfig() const = 0; + FatalConditionHandler(); + ~FatalConditionHandler(); + static void reset(); }; - struct IMutableContext : IContext - { - virtual ~IMutableContext(); - virtual void setResultCapture( IResultCapture* resultCapture ) = 0; - virtual void setRunner( IRunner* runner ) = 0; - virtual void setConfig( IConfigPtr const& config ) = 0; - }; +} // namespace Catch - IContext& getCurrentContext(); - IMutableContext& getCurrentMutableContext(); - void cleanUpContext(); +#else + +namespace Catch { + struct FatalConditionHandler { + void reset(); + }; } -// end catch_context.h -#include +#endif + +// end catch_fatal_condition.h +#include namespace Catch { - auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& { - expr.streamReconstructedExpression( os ); - return os; + struct IMutableContext; + + /////////////////////////////////////////////////////////////////////////// + + class RunContext : public IResultCapture, public IRunner { + + public: + RunContext( RunContext const& ) = delete; + RunContext& operator =( RunContext const& ) = delete; + + explicit RunContext( IConfigPtr const& _config, IStreamingReporterPtr&& reporter ); + + ~RunContext() override; + + void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ); + void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ); + + Totals runTest(TestCase const& testCase); + + IConfigPtr config() const; + IStreamingReporter& reporter() const; + + public: // IResultCapture + + // Assertion handlers + void handleExpr + ( AssertionInfo const& info, + ITransientExpression const& expr, + AssertionReaction& reaction ) override; + void handleMessage + ( AssertionInfo const& info, + ResultWas::OfType resultType, + StringRef const& message, + AssertionReaction& reaction ) override; + void handleUnexpectedExceptionNotThrown + ( AssertionInfo const& info, + AssertionReaction& reaction ) override; + void handleUnexpectedInflightException + ( AssertionInfo const& info, + std::string const& message, + AssertionReaction& reaction ) override; + void handleIncomplete + ( AssertionInfo const& info ) override; + void handleNonExpr + ( AssertionInfo const &info, + ResultWas::OfType resultType, + AssertionReaction &reaction ) override; + + bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override; + + void sectionEnded( SectionEndInfo const& endInfo ) override; + void sectionEndedEarly( SectionEndInfo const& endInfo ) override; + + auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override; + + void benchmarkStarting( BenchmarkInfo const& info ) override; + void benchmarkEnded( BenchmarkStats const& stats ) override; + + void pushScopedMessage( MessageInfo const& message ) override; + void popScopedMessage( MessageInfo const& message ) override; + + std::string getCurrentTestName() const override; + + const AssertionResult* getLastResult() const override; + + void exceptionEarlyReported() override; + + void handleFatalErrorCondition( StringRef message ) override; + + bool lastAssertionPassed() override; + + void assertionPassed() override; + + public: + // !TBD We need to do this another way! + bool aborting() const final; + + private: + + void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ); + void invokeActiveTestCase(); + + void resetAssertionInfo(); + bool testForMissingAssertions( Counts& assertions ); + + void assertionEnded( AssertionResult const& result ); + void reportExpr + ( AssertionInfo const &info, + ResultWas::OfType resultType, + ITransientExpression const *expr, + bool negated ); + + void populateReaction( AssertionReaction& reaction ); + + private: + + void handleUnfinishedSections(); + + TestRunInfo m_runInfo; + IMutableContext& m_context; + TestCase const* m_activeTestCase = nullptr; + ITracker* m_testCaseTracker; + Option m_lastResult; + + IConfigPtr m_config; + Totals m_totals; + IStreamingReporterPtr m_reporter; + std::vector m_messages; + AssertionInfo m_lastAssertionInfo; + std::vector m_unfinishedSections; + std::vector m_activeSections; + TrackerContext m_trackerContext; + bool m_lastAssertionPassed = false; + bool m_shouldReportUnexpected = true; + bool m_includeSuccessfulResults; + }; + +} // end namespace Catch + +// end catch_run_context.h +namespace Catch { + + namespace { + auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& { + expr.streamReconstructedExpression( os ); + return os; + } } LazyExpression::LazyExpression( bool isNegated ) @@ -4100,95 +5455,69 @@ namespace Catch { } AssertionHandler::AssertionHandler - ( StringRef macroName, + ( StringRef const& macroName, SourceLineInfo const& lineInfo, StringRef capturedExpression, ResultDisposition::Flags resultDisposition ) - : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition } - { - getCurrentContext().getResultCapture()->assertionStarting( m_assertionInfo ); - } - AssertionHandler::~AssertionHandler() { - if ( m_inExceptionGuard ) { - handle( ResultWas::ThrewException, "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE" ); - getCurrentContext().getResultCapture()->exceptionEarlyReported(); - } - } - - void AssertionHandler::handle( ITransientExpression const& expr ) { - - bool negated = isFalseTest( m_assertionInfo.resultDisposition ); - bool result = expr.getResult() != negated; + : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, + m_resultCapture( getResultCapture() ) + {} - handle( result ? ResultWas::Ok : ResultWas::ExpressionFailed, &expr, negated ); - } - void AssertionHandler::handle( ResultWas::OfType resultType ) { - handle( resultType, nullptr, false ); + void AssertionHandler::handleExpr( ITransientExpression const& expr ) { + m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction ); } - void AssertionHandler::handle( ResultWas::OfType resultType, StringRef const& message ) { - AssertionResultData data( resultType, LazyExpression( false ) ); - data.message = message; - handle( data, nullptr ); - } - void AssertionHandler::handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated ) { - AssertionResultData data( resultType, LazyExpression( negated ) ); - handle( data, expr ); + void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const& message) { + m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction ); } - void AssertionHandler::handle( AssertionResultData const& resultData, ITransientExpression const* expr ) { - getResultCapture().assertionRun(); + auto AssertionHandler::allowThrows() const -> bool { + return getCurrentContext().getConfig()->allowThrows(); + } - AssertionResult assertionResult{ m_assertionInfo, resultData }; - assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; + void AssertionHandler::complete() { + setCompleted(); + if( m_reaction.shouldDebugBreak ) { - getResultCapture().assertionEnded( assertionResult ); + // If you find your debugger stopping you here then go one level up on the + // call-stack for the code that caused it (typically a failed assertion) - if( !assertionResult.isOk() ) { - m_shouldDebugBreak = getCurrentContext().getConfig()->shouldDebugBreak(); - m_shouldThrow = - getCurrentContext().getRunner()->aborting() || - (m_assertionInfo.resultDisposition & ResultDisposition::Normal); + // (To go back to the test and change execution, jump over the throw, next) + CATCH_BREAK_INTO_DEBUGGER(); + } + if (m_reaction.shouldThrow) { +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) + throw Catch::TestFailureException(); +#else + CATCH_ERROR( "Test failure requires aborting test!" ); +#endif } } - - auto AssertionHandler::allowThrows() const -> bool { - return getCurrentContext().getConfig()->allowThrows(); + void AssertionHandler::setCompleted() { + m_completed = true; } - auto AssertionHandler::shouldDebugBreak() const -> bool { - return m_shouldDebugBreak; + void AssertionHandler::handleUnexpectedInflightException() { + m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction ); } - void AssertionHandler::reactWithDebugBreak() const { - if (m_shouldDebugBreak) { - /////////////////////////////////////////////////////////////////// - // To inspect the state during test, you need to go one level up the callstack - // To go back to the test and change execution, jump over the reactWithoutDebugBreak() call - /////////////////////////////////////////////////////////////////// - CATCH_BREAK_INTO_DEBUGGER(); - } - reactWithoutDebugBreak(); + + void AssertionHandler::handleExceptionThrownAsExpected() { + m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); } - void AssertionHandler::reactWithoutDebugBreak() const { - if( m_shouldThrow ) - throw Catch::TestFailureException(); + void AssertionHandler::handleExceptionNotThrownAsExpected() { + m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); } - void AssertionHandler::useActiveException() { - handle( ResultWas::ThrewException, Catch::translateActiveException() ); + void AssertionHandler::handleUnexpectedExceptionNotThrown() { + m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction ); } - void AssertionHandler::setExceptionGuard() { - assert( m_inExceptionGuard == false ); - m_inExceptionGuard = true; - } - void AssertionHandler::unsetExceptionGuard() { - assert( m_inExceptionGuard == true ); - m_inExceptionGuard = false; + void AssertionHandler::handleThrowingCallSkipped() { + m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); } // This is the overload that takes a string and infers the Equals matcher from it // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp - void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ) { + void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString ) { handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString ); } @@ -4205,10 +5534,9 @@ namespace Catch { if( reconstructedExpression.empty() ) { if( lazyExpression ) { - // !TBD Use stringstream for now, but rework above to pass stream in - std::ostringstream oss; - oss << lazyExpression; - reconstructedExpression = oss.str(); + ReusableStringStream rss; + rss << lazyExpression; + reconstructedExpression = rss.str(); } } return reconstructedExpression; @@ -4243,7 +5571,7 @@ namespace Catch { std::string AssertionResult::getExpression() const { if( isFalseTest( m_info.resultDisposition ) ) - return "!(" + std::string(m_info.capturedExpression) + ")"; + return "!(" + m_info.capturedExpression + ")"; else return m_info.capturedExpression; } @@ -4280,7 +5608,7 @@ namespace Catch { return m_info.lineInfo; } - std::string AssertionResult::getTestMacroName() const { + StringRef AssertionResult::getTestMacroName() const { return m_info.macroName; } @@ -4319,12 +5647,12 @@ namespace Catch { using StringMatcher = Matchers::Impl::MatcherBase; // This is the general overload that takes a any string matcher - // There is another overload, in catch_assertinhandler.h/.cpp, that only takes a string and infers + // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers // the Equals matcher (so the header does not mention matchers) - void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ) { + void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ) { std::string exceptionMessage = Catch::translateActiveException(); MatchExpr expr( exceptionMessage, matcher, matcherString ); - handler.handle( expr ); + handler.handleExpr( expr ); } } // namespace Catch @@ -4350,8 +5678,14 @@ namespace Catch { #endif // start clara.hpp -// v1.0-develop.2 -// See https://github.com/philsquared/Clara +// Copyright 2017 Two Blue Cubes Ltd. All rights reserved. +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See https://github.com/philsquared/Clara for more details + +// Clara v1.1.4 #ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH @@ -4362,6 +5696,15 @@ namespace Catch { #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH #endif +#ifndef CLARA_CONFIG_OPTIONAL_TYPE +#ifdef __has_include +#if __has_include() && __cplusplus >= 201703L +#include +#define CLARA_CONFIG_OPTIONAL_TYPE std::optional +#endif +#endif +#endif + // ----------- #included from clara_textflow.hpp ----------- // TextFlowCpp @@ -4714,7 +6057,7 @@ namespace detail { template struct UnaryLambdaTraits { static const bool isValid = true; - using ArgType = typename std::remove_const::type>::type;; + using ArgType = typename std::remove_const::type>::type; using ReturnType = ReturnT; }; @@ -4727,11 +6070,9 @@ namespace detail { std::vector m_args; public: - Args( int argc, char *argv[] ) { - m_exeName = argv[0]; - for( int i = 1; i < argc; ++i ) - m_args.push_back( argv[i] ); - } + Args( int argc, char const* const* argv ) + : m_exeName(argv[0]), + m_args(argv + 1, argv + argc) {} Args( std::initializer_list args ) : m_exeName( *args.begin() ), @@ -4878,7 +6219,7 @@ namespace detail { return *this; } - ~ResultValueBase() { + ~ResultValueBase() override { if( m_type == Ok ) m_value.~T(); } @@ -4916,16 +6257,14 @@ namespace detail { auto errorMessage() const -> std::string { return m_errorMessage; } protected: - virtual void enforceOk() const { - // !TBD: If no exceptions, std::terminate here or something - switch( m_type ) { - case ResultBase::LogicError: - throw std::logic_error( m_errorMessage ); - case ResultBase::RuntimeError: - throw std::runtime_error( m_errorMessage ); - case ResultBase::Ok: - break; - } + void enforceOk() const override { + + // Errors shouldn't reach this point, but if they do + // the actual error message will be in m_errorMessage + assert( m_type != ResultBase::LogicError ); + assert( m_type != ResultBase::RuntimeError ); + if( m_type != ResultBase::Ok ) + std::abort(); } std::string m_errorMessage; // Only populated if resultType is an error @@ -4995,47 +6334,43 @@ namespace detail { return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" ); return ParserResult::ok( ParseResultType::Matched ); } +#ifdef CLARA_CONFIG_OPTIONAL_TYPE + template + inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE& target ) -> ParserResult { + T temp; + auto result = convertInto( source, temp ); + if( result ) + target = std::move(temp); + return result; + } +#endif // CLARA_CONFIG_OPTIONAL_TYPE - struct BoundRefBase { - BoundRefBase() = default; - BoundRefBase( BoundRefBase const & ) = delete; - BoundRefBase( BoundRefBase && ) = delete; - BoundRefBase &operator=( BoundRefBase const & ) = delete; - BoundRefBase &operator=( BoundRefBase && ) = delete; - - virtual ~BoundRefBase() = default; + struct NonCopyable { + NonCopyable() = default; + NonCopyable( NonCopyable const & ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable &operator=( NonCopyable const & ) = delete; + NonCopyable &operator=( NonCopyable && ) = delete; + }; - virtual auto isFlag() const -> bool = 0; + struct BoundRef : NonCopyable { + virtual ~BoundRef() = default; virtual auto isContainer() const -> bool { return false; } - virtual auto setValue( std::string const &arg ) -> ParserResult = 0; - virtual auto setFlag( bool flag ) -> ParserResult = 0; + virtual auto isFlag() const -> bool { return false; } }; - - struct BoundValueRefBase : BoundRefBase { - auto isFlag() const -> bool override { return false; } - - auto setFlag( bool ) -> ParserResult override { - return ParserResult::logicError( "Flags can only be set on boolean fields" ); - } + struct BoundValueRefBase : BoundRef { + virtual auto setValue( std::string const &arg ) -> ParserResult = 0; }; - - struct BoundFlagRefBase : BoundRefBase { - auto isFlag() const -> bool override { return true; } - - auto setValue( std::string const &arg ) -> ParserResult override { - bool flag; - auto result = convertInto( arg, flag ); - if( result ) - setFlag( flag ); - return result; - } + struct BoundFlagRefBase : BoundRef { + virtual auto setFlag( bool flag ) -> ParserResult = 0; + virtual auto isFlag() const -> bool { return true; } }; template - struct BoundRef : BoundValueRefBase { + struct BoundValueRef : BoundValueRefBase { T &m_ref; - explicit BoundRef( T &ref ) : m_ref( ref ) {} + explicit BoundValueRef( T &ref ) : m_ref( ref ) {} auto setValue( std::string const &arg ) -> ParserResult override { return convertInto( arg, m_ref ); @@ -5043,10 +6378,10 @@ namespace detail { }; template - struct BoundRef> : BoundValueRefBase { + struct BoundValueRef> : BoundValueRefBase { std::vector &m_ref; - explicit BoundRef( std::vector &ref ) : m_ref( ref ) {} + explicit BoundValueRef( std::vector &ref ) : m_ref( ref ) {} auto isContainer() const -> bool override { return true; } @@ -5091,12 +6426,12 @@ namespace detail { template inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult { - ArgType temp; + ArgType temp{}; auto result = convertInto( arg, temp ); return !result ? result : LambdaInvoker::ReturnType>::invoke( lambda, temp ); - }; + } template struct BoundLambda : BoundValueRefBase { @@ -5145,6 +6480,9 @@ namespace detail { public: template auto operator|( T const &other ) const -> Parser; + + template + auto operator+( T const &other ) const -> Parser; }; // Common code and state for Args and Opts @@ -5152,16 +6490,16 @@ namespace detail { class ParserRefImpl : public ComposableParserImpl { protected: Optionality m_optionality = Optionality::Optional; - std::shared_ptr m_ref; + std::shared_ptr m_ref; std::string m_hint; std::string m_description; - explicit ParserRefImpl( std::shared_ptr const &ref ) : m_ref( ref ) {} + explicit ParserRefImpl( std::shared_ptr const &ref ) : m_ref( ref ) {} public: template ParserRefImpl( T &ref, std::string const &hint ) - : m_ref( std::make_shared>( ref ) ), + : m_ref( std::make_shared>( ref ) ), m_hint( hint ) {} @@ -5202,10 +6540,10 @@ namespace detail { class ExeName : public ComposableParserImpl { std::shared_ptr m_name; - std::shared_ptr m_ref; + std::shared_ptr m_ref; template - static auto makeRef(LambdaT const &lambda) -> std::shared_ptr { + static auto makeRef(LambdaT const &lambda) -> std::shared_ptr { return std::make_shared>( lambda) ; } @@ -5213,7 +6551,7 @@ namespace detail { ExeName() : m_name( std::make_shared( "" ) ) {} explicit ExeName( std::string &ref ) : ExeName() { - m_ref = std::make_shared>( ref ); + m_ref = std::make_shared>( ref ); } template @@ -5256,7 +6594,10 @@ namespace detail { if( token.type != TokenType::Argument ) return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); - auto result = m_ref->setValue( remainingTokens->token ); + assert( !m_ref->isFlag() ); + auto valueRef = static_cast( m_ref.get() ); + + auto result = valueRef->setValue( remainingTokens->token ); if( !result ) return InternalParseResult( result ); else @@ -5330,19 +6671,21 @@ namespace detail { auto const &token = *remainingTokens; if( isMatch(token.token ) ) { if( m_ref->isFlag() ) { - auto result = m_ref->setFlag( true ); + auto flagRef = static_cast( m_ref.get() ); + auto result = flagRef->setFlag( true ); if( !result ) return InternalParseResult( result ); if( result.value() == ParseResultType::ShortCircuitAll ) return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); } else { + auto valueRef = static_cast( m_ref.get() ); ++remainingTokens; if( !remainingTokens ) return InternalParseResult::runtimeError( "Expected argument following " + token.token ); auto const &argToken = *remainingTokens; if( argToken.type != TokenType::Argument ) return InternalParseResult::runtimeError( "Expected argument following " + token.token ); - auto result = m_ref->setValue( argToken.token ); + auto result = valueRef->setValue( argToken.token ); if( !result ) return InternalParseResult( result ); if( result.value() == ParseResultType::ShortCircuitAll ) @@ -5418,6 +6761,12 @@ namespace detail { return Parser( *this ) |= other; } + // Forward deprecated interface with '+' instead of '|' + template + auto operator+=( T const &other ) -> Parser & { return operator|=( other ); } + template + auto operator+( T const &other ) const -> Parser { return operator|( other ); } + auto getHelpColumns() const -> std::vector { std::vector cols; for (auto const &o : m_options) { @@ -5457,6 +6806,8 @@ namespace detail { for( auto const &cols : rows ) optWidth = (std::max)(optWidth, cols.left.size() + 2); + optWidth = (std::min)(optWidth, consoleWidth/2); + for( auto const &cols : rows ) { auto row = TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) + @@ -5596,9 +6947,19 @@ namespace Catch { using namespace clara; auto const setWarning = [&]( std::string const& warning ) { - if( warning != "NoAssertions" ) + auto warningSet = [&]() { + if( warning == "NoAssertions" ) + return WarnAbout::NoAssertions; + + if ( warning == "NoTests" ) + return WarnAbout::NoTests; + + return WarnAbout::Nothing; + }(); + + if (warningSet == WarnAbout::Nothing) return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" ); - config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); + config.warnings = static_cast( config.warnings | warningSet ); return ParserResult::ok( ParseResultType::Matched ); }; auto const loadTestNamesFromFile = [&]( std::string const& filename ) { @@ -5696,7 +7057,7 @@ namespace Catch { | Opt( config.outputFilename, "filename" ) ["-o"]["--out"] ( "output filename" ) - | Opt( config.reporterNames, "name" ) + | Opt( config.reporterName, "name" ) ["-r"]["--reporter"] ( "reporter to use (defaults to console)" ) | Opt( config.name, "name" ) @@ -5766,10 +7127,6 @@ namespace Catch { namespace Catch { - SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) noexcept - : file( _file ), - line( _line ) - {} bool SourceLineInfo::empty() const noexcept { return file[0] == '\0'; } @@ -5777,7 +7134,9 @@ namespace Catch { return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); } bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept { - return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0)); + // We can assume that the same file will usually have the same pointer. + // Thus, if the pointers are the same, there is no point in calling the strcmp + return line < other.line || ( line == other.line && file != other.file && (std::strcmp(file, other.file) < 0)); } std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { @@ -5789,10 +7148,6 @@ namespace Catch { return os; } - bool isTrue( bool value ){ return value; } - bool alwaysTrue() { return true; } - bool alwaysFalse() { return false; } - std::string StreamEndStop::operator+() const { return std::string(); } @@ -5810,12 +7165,16 @@ namespace Catch { : m_data( data ), m_stream( openStream() ) { - if( !data.testsOrTags.empty() ) { - TestSpecParser parser( ITagAliasRegistry::get() ); + TestSpecParser parser(ITagAliasRegistry::get()); + if (data.testsOrTags.empty()) { + parser.parse("~[.]"); // All not hidden tests + } + else { + m_hasTestFilters = true; for( auto const& testOrTags : data.testsOrTags ) parser.parse( testOrTags ); - m_testSpec = parser.testSpec(); } + m_testSpec = parser.testSpec(); } std::string const& Config::getFilename() const { @@ -5828,11 +7187,13 @@ namespace Catch { bool Config::listReporters() const { return m_data.listReporters; } std::string Config::getProcessName() const { return m_data.processName; } + std::string const& Config::getReporterName() const { return m_data.reporterName; } - std::vector const& Config::getReporterNames() const { return m_data.reporterNames; } + std::vector const& Config::getTestsOrTags() const { return m_data.testsOrTags; } std::vector const& Config::getSectionsToRun() const { return m_data.sectionsToRun; } TestSpec const& Config::testSpec() const { return m_testSpec; } + bool Config::hasTestFilters() const { return m_hasTestFilters; } bool Config::showHelp() const { return m_data.showHelp; } @@ -5841,7 +7202,8 @@ namespace Catch { std::ostream& Config::stream() const { return m_stream->stream(); } std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; } - bool Config::warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } + bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); } + bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); } ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; } RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } unsigned int Config::rngSeed() const { return m_data.rngSeed; } @@ -5853,16 +7215,7 @@ namespace Catch { Verbosity Config::verbosity() const { return m_data.verbosity; } IStream const* Config::openStream() { - if( m_data.outputFilename.empty() ) - return new CoutStream(); - else if( m_data.outputFilename[0] == '%' ) { - if( m_data.outputFilename == "%debug" ) - return new DebugOutStream(); - else - CATCH_ERROR( "Unrecognised stream: '" << m_data.outputFilename << "'" ); - } - else - return new FileStream( m_data.outputFilename ); + return Catch::makeStream(m_data.outputFilename); } } // end namespace Catch @@ -5882,43 +7235,15 @@ namespace Catch { public: ErrnoGuard(); ~ErrnoGuard(); - private: - int m_oldErrno; - }; - -} - -// end catch_errno_guard.h -// start catch_windows_h_proxy.h - - -#if defined(CATCH_PLATFORM_WINDOWS) - -#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) -# define CATCH_DEFINED_NOMINMAX -# define NOMINMAX -#endif -#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) -# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -#endif - -#ifdef __AFXDLL -#include -#else -#include -#endif - -#ifdef CATCH_DEFINED_NOMINMAX -# undef NOMINMAX -#endif -#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN -# undef WIN32_LEAN_AND_MEAN -#endif + private: + int m_oldErrno; + }; -#endif // defined(CATCH_PLATFORM_WINDOWS) +} + +// end catch_errno_guard.h +#include -// end catch_windows_h_proxy.h namespace Catch { namespace { @@ -5977,8 +7302,12 @@ namespace { case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN ); case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); + + default: + CATCH_ERROR( "Unknown colour requested" ); } } @@ -6036,8 +7365,10 @@ namespace { case Colour::BrightRed: return setColour( "[1;31m" ); case Colour::BrightGreen: return setColour( "[1;32m" ); case Colour::BrightWhite: return setColour( "[1;37m" ); + case Colour::BrightYellow: return setColour( "[1;33m" ); case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); + default: CATCH_INTERNAL_ERROR( "Unknown colour requested" ); } } static IColourImpl* instance() { @@ -6056,7 +7387,12 @@ namespace { #ifdef CATCH_PLATFORM_MAC !isDebuggerActive() && #endif - isatty(STDOUT_FILENO); +#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__)) + isatty(STDOUT_FILENO) +#else + false +#endif + ; } IColourImpl* platformColourInstance() { ErrnoGuard guard; @@ -6131,7 +7467,7 @@ namespace Catch { return m_runner; } - virtual IConfigPtr getConfig() const override { + virtual IConfigPtr const& getConfig() const override { return m_config; } @@ -6156,21 +7492,16 @@ namespace Catch { IResultCapture* m_resultCapture = nullptr; }; - namespace { - Context* currentContext = nullptr; - } - IMutableContext& getCurrentMutableContext() { - if( !currentContext ) - currentContext = new Context(); - return *currentContext; - } - IContext& getCurrentContext() { - return getCurrentMutableContext(); + IMutableContext *IMutableContext::currentContext = nullptr; + + void IMutableContext::createContext() + { + currentContext = new Context(); } void cleanUpContext() { - delete currentContext; - currentContext = nullptr; + delete IMutableContext::currentContext; + IMutableContext::currentContext = nullptr; } IContext::~IContext() = default; IMutableContext::~IMutableContext() = default; @@ -6195,26 +7526,31 @@ namespace Catch { ::OutputDebugStringA( text.c_str() ); } } + #else + namespace Catch { void writeToDebugConsole( std::string const& text ) { // !TBD: Need a version for Mac/ XCode and other IDEs Catch::cout() << text; } } + #endif // Platform // end catch_debug_console.cpp // start catch_debugger.cpp #ifdef CATCH_PLATFORM_MAC - #include - #include - #include - #include - #include +# include +# include +# include +# include +# include +# include +# include - namespace Catch { +namespace Catch { // The following function is taken directly from the following technical note: // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html @@ -6320,6 +7656,19 @@ namespace Catch { } } // end catch_decomposer.cpp +// start catch_enforce.cpp + +namespace Catch { +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER) + [[noreturn]] + void throw_exception(std::exception const& e) { + Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n" + << "The message was: " << e.what() << '\n'; + std::terminate(); + } +#endif +} // namespace Catch; +// end catch_enforce.cpp // start catch_errno_guard.cpp #include @@ -6365,6 +7714,7 @@ namespace Catch { m_translators.push_back( std::unique_ptr( translator ) ); } +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) std::string ExceptionTranslatorRegistry::translateActiveException() const { try { #ifdef __OBJC__ @@ -6376,6 +7726,17 @@ namespace Catch { return Catch::Detail::stringify( [exception description] ); } #else + // Compiling a mixed mode project with MSVC means that CLR + // exceptions will be caught in (...) as well. However, these + // do not fill-in std::current_exception and thus lead to crash + // when attempting rethrow. + // /EHa switch also causes structured exceptions to be caught + // here, but they fill-in current_exception properly, so + // at worst the output should be a little weird, instead of + // causing a crash. + if (std::current_exception() == nullptr) { + return "Non C++ exception. Possibly a CLR exception."; + } return tryTranslators(); #endif } @@ -6396,6 +7757,12 @@ namespace Catch { } } +#else // ^^ Exceptions are enabled // Exceptions are disabled vv + std::string ExceptionTranslatorRegistry::translateActiveException() const { + CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); + } +#endif + std::string ExceptionTranslatorRegistry::tryTranslators() const { if( m_translators.empty() ) std::rethrow_exception(std::current_exception()); @@ -6406,78 +7773,13 @@ namespace Catch { // end catch_exception_translator_registry.cpp // start catch_fatal_condition.cpp -// start catch_fatal_condition.h - -#include - -#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// - -# if !defined ( CATCH_CONFIG_WINDOWS_SEH ) - -namespace Catch { - struct FatalConditionHandler { - void reset(); - }; -} - -# else // CATCH_CONFIG_WINDOWS_SEH is defined - -namespace Catch { - - struct FatalConditionHandler { - - static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo); - FatalConditionHandler(); - static void reset(); - ~FatalConditionHandler(); - - private: - static bool isSet; - static ULONG guaranteeSize; - static PVOID exceptionHandlerHandle; - }; - -} // namespace Catch - -# endif // CATCH_CONFIG_WINDOWS_SEH - -#else // Not Windows - assumed to be POSIX compatible ////////////////////////// - -# if !defined(CATCH_CONFIG_POSIX_SIGNALS) - -namespace Catch { - struct FatalConditionHandler { - void reset(); - }; -} - -# else // CATCH_CONFIG_POSIX_SIGNALS is defined - -#include - -namespace Catch { - - struct FatalConditionHandler { - - static bool isSet; - static struct sigaction oldSigActions[];// [sizeof(signalDefs) / sizeof(SignalDefs)]; - static stack_t oldSigStack; - static char altStackMem[]; - - static void handleSignal( int sig ); - - FatalConditionHandler(); - ~FatalConditionHandler(); - static void reset(); - }; - -} // namespace Catch - -# endif // CATCH_CONFIG_POSIX_SIGNALS +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif -#endif // not Windows +#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS ) -// end catch_fatal_condition.h namespace { // Report the error condition void reportFatal( char const * const message ) { @@ -6485,15 +7787,9 @@ namespace { } } -#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// - -# if !defined ( CATCH_CONFIG_WINDOWS_SEH ) +#endif // signals/SEH handling -namespace Catch { - void FatalConditionHandler::reset() {} -} - -# else // CATCH_CONFIG_WINDOWS_SEH is defined +#if defined( CATCH_CONFIG_WINDOWS_SEH ) namespace Catch { struct SignalDefs { DWORD id; const char* name; }; @@ -6533,7 +7829,6 @@ namespace Catch { void FatalConditionHandler::reset() { if (isSet) { - // Unregister handler and restore the old guarantee RemoveVectoredExceptionHandler(exceptionHandlerHandle); SetThreadStackGuarantee(&guaranteeSize); exceptionHandlerHandle = nullptr; @@ -6551,19 +7846,7 @@ PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr; } // namespace Catch -# endif // CATCH_CONFIG_WINDOWS_SEH - -#else // Not Windows - assumed to be POSIX compatible ////////////////////////// - -# if !defined(CATCH_CONFIG_POSIX_SIGNALS) - -namespace Catch { - void FatalConditionHandler::reset() {} -} - -# else // CATCH_CONFIG_POSIX_SIGNALS is defined - -#include +#elif defined( CATCH_CONFIG_POSIX_SIGNALS ) namespace Catch { @@ -6571,6 +7854,11 @@ namespace Catch { int id; const char* name; }; + + // 32kb for the alternate stack seems to be sufficient. However, this value + // is experimentally determined, so that's not guaranteed. + constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ; + static SignalDefs signalDefs[] = { { SIGINT, "SIGINT - Terminal interrupt signal" }, { SIGILL, "SIGILL - Illegal instruction signal" }, @@ -6597,7 +7885,7 @@ namespace Catch { isSet = true; stack_t sigStack; sigStack.ss_sp = altStackMem; - sigStack.ss_size = SIGSTKSZ; + sigStack.ss_size = sigStackSize; sigStack.ss_flags = 0; sigaltstack(&sigStack, &oldSigStack); struct sigaction sa = { }; @@ -6628,14 +7916,80 @@ namespace Catch { bool FatalConditionHandler::isSet = false; struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; stack_t FatalConditionHandler::oldSigStack = {}; - char FatalConditionHandler::altStackMem[SIGSTKSZ] = {}; + char FatalConditionHandler::altStackMem[sigStackSize] = {}; } // namespace Catch -# endif // CATCH_CONFIG_POSIX_SIGNALS +#else + +namespace Catch { + void FatalConditionHandler::reset() {} +} + +#endif // signals/SEH handling -#endif // not Windows +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#endif // end catch_fatal_condition.cpp +// start catch_generators.cpp + +// start catch_random_number_generator.h + +#include +#include + +namespace Catch { + + struct IConfig; + + std::mt19937& rng(); + void seedRng( IConfig const& config ); + unsigned int rngSeed(); + +} + +// end catch_random_number_generator.h +#include +#include + +namespace Catch { + +IGeneratorTracker::~IGeneratorTracker() {} + +namespace Generators { + + GeneratorBase::~GeneratorBase() {} + + std::vector randomiseIndices( size_t selectionSize, size_t sourceSize ) { + + assert( selectionSize <= sourceSize ); + std::vector indices; + indices.reserve( selectionSize ); + std::uniform_int_distribution uid( 0, sourceSize-1 ); + + std::set seen; + // !TBD: improve this algorithm + while( indices.size() < selectionSize ) { + auto index = uid( rng() ); + if( seen.insert( index ).second ) + indices.push_back( index ); + } + return indices; + } + + auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { + return getResultCapture().acquireGeneratorTracker( lineInfo ); + } + + template<> + auto all() -> Generator { + return range( std::numeric_limits::min(), std::numeric_limits::max() ); + } + +} // namespace Generators +} // namespace Catch +// end catch_generators.cpp // start catch_interfaces_capture.cpp namespace Catch { @@ -6664,16 +8018,21 @@ namespace Catch { // end catch_interfaces_registry_hub.cpp // start catch_interfaces_reporter.cpp -// start catch_reporter_multi.h +// start catch_reporter_listening.h namespace Catch { - class MultipleReporters : public IStreamingReporter { + class ListeningReporter : public IStreamingReporter { using Reporters = std::vector; - Reporters m_reporters; + Reporters m_listeners; + IStreamingReporterPtr m_reporter = nullptr; + ReporterPreferences m_preferences; public: - void add( IStreamingReporterPtr&& reporter ); + ListeningReporter(); + + void addListener( IStreamingReporterPtr&& listener ); + void addReporter( IStreamingReporterPtr&& reporter ); public: // IStreamingReporter @@ -6706,7 +8065,7 @@ namespace Catch { } // end namespace Catch -// end catch_reporter_multi.h +// end catch_reporter_listening.h namespace Catch { ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig ) @@ -6807,27 +8166,6 @@ namespace Catch { IReporterFactory::~IReporterFactory() = default; IReporterRegistry::~IReporterRegistry() = default; - void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter ) { - - if( !existingReporter ) { - existingReporter = std::move( additionalReporter ); - return; - } - - MultipleReporters* multi = nullptr; - - if( existingReporter->isMulti() ) { - multi = static_cast( existingReporter.get() ); - } - else { - auto newMulti = std::unique_ptr( new MultipleReporters ); - newMulti->add( std::move( existingReporter ) ); - multi = newMulti.get(); - existingReporter = std::move( newMulti ); - } - multi->add( std::move( additionalReporter ) ); - } - } // end namespace Catch // end catch_interfaces_reporter.cpp // start catch_interfaces_runner.cpp @@ -6845,29 +8183,28 @@ namespace Catch { // end catch_interfaces_testcase.cpp // start catch_leak_detector.cpp -namespace Catch { - #ifdef CATCH_CONFIG_WINDOWS_CRTDBG #include - LeakDetector::LeakDetector() { - int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); - flag |= _CRTDBG_LEAK_CHECK_DF; - flag |= _CRTDBG_ALLOC_MEM_DF; - _CrtSetDbgFlag(flag); - _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); - _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); - // Change this to leaking allocation's number to break there - _CrtSetBreakAlloc(-1); - } +namespace Catch { + + LeakDetector::LeakDetector() { + int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + flag |= _CRTDBG_LEAK_CHECK_DF; + flag |= _CRTDBG_ALLOC_MEM_DF; + _CrtSetDbgFlag(flag); + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); + // Change this to leaking allocation's number to break there + _CrtSetBreakAlloc(-1); + } +} #else - LeakDetector::LeakDetector(){} + Catch::LeakDetector::LeakDetector() {} #endif - -} // end catch_leak_detector.cpp // start catch_list.cpp @@ -6913,11 +8250,10 @@ namespace Catch { std::size_t listTests( Config const& config ) { TestSpec testSpec = config.testSpec(); - if( config.testSpec().hasFilters() ) + if( config.hasTestFilters() ) Catch::cout() << "Matching test cases:\n"; else { Catch::cout() << "All available test cases:\n"; - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); } auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); @@ -6939,7 +8275,7 @@ namespace Catch { Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n"; } - if( !config.testSpec().hasFilters() ) + if( !config.hasTestFilters() ) Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl; else Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl; @@ -6948,8 +8284,6 @@ namespace Catch { std::size_t listTestsNamesOnly( Config const& config ) { TestSpec testSpec = config.testSpec(); - if( !config.testSpec().hasFilters() ) - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); std::size_t matchedTests = 0; std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( auto const& testCaseInfo : matchedTestCases ) { @@ -6979,11 +8313,10 @@ namespace Catch { std::size_t listTags( Config const& config ) { TestSpec testSpec = config.testSpec(); - if( config.testSpec().hasFilters() ) + if( config.hasTestFilters() ) Catch::cout() << "Tags for matching test cases:\n"; else { Catch::cout() << "All available tags:\n"; - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); } std::map tagCounts; @@ -7000,13 +8333,14 @@ namespace Catch { } for( auto const& tagCount : tagCounts ) { - std::ostringstream oss; - oss << " " << std::setw(2) << tagCount.second.count << " "; + ReusableStringStream rss; + rss << " " << std::setw(2) << tagCount.second.count << " "; + auto str = rss.str(); auto wrapper = Column( tagCount.second.all() ) .initialIndent( 0 ) - .indent( oss.str().size() ) + .indent( str.size() ) .width( CATCH_CONFIG_CONSOLE_WIDTH-10 ); - Catch::cout() << oss.str() << wrapper << '\n'; + Catch::cout() << str << wrapper << '\n'; } Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; return tagCounts.size(); @@ -7047,32 +8381,197 @@ namespace Catch { return listedCount; } -} // end namespace Catch -// end catch_list.cpp -// start catch_matchers.cpp +} // end namespace Catch +// end catch_list.cpp +// start catch_matchers.cpp + +namespace Catch { +namespace Matchers { + namespace Impl { + + std::string MatcherUntypedBase::toString() const { + if( m_cachedToString.empty() ) + m_cachedToString = describe(); + return m_cachedToString; + } + + MatcherUntypedBase::~MatcherUntypedBase() = default; + + } // namespace Impl +} // namespace Matchers + +using namespace Matchers; +using Matchers::Impl::MatcherBase; + +} // namespace Catch +// end catch_matchers.cpp +// start catch_matchers_floating.cpp + +// start catch_to_string.hpp + +#include + +namespace Catch { + template + std::string to_string(T const& t) { +#if defined(CATCH_CONFIG_CPP11_TO_STRING) + return std::to_string(t); +#else + ReusableStringStream rss; + rss << t; + return rss.str(); +#endif + } +} // end namespace Catch + +// end catch_to_string.hpp +#include +#include +#include + +namespace Catch { +namespace Matchers { +namespace Floating { +enum class FloatingPointKind : uint8_t { + Float, + Double +}; +} +} +} + +namespace { + +template +struct Converter; + +template <> +struct Converter { + static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated"); + Converter(float f) { + std::memcpy(&i, &f, sizeof(f)); + } + int32_t i; +}; + +template <> +struct Converter { + static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated"); + Converter(double d) { + std::memcpy(&i, &d, sizeof(d)); + } + int64_t i; +}; + +template +auto convert(T t) -> Converter { + return Converter(t); +} + +template +bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) { + // Comparison with NaN should always be false. + // This way we can rule it out before getting into the ugly details + if (std::isnan(lhs) || std::isnan(rhs)) { + return false; + } + + auto lc = convert(lhs); + auto rc = convert(rhs); + + if ((lc.i < 0) != (rc.i < 0)) { + // Potentially we can have +0 and -0 + return lhs == rhs; + } + + auto ulpDiff = std::abs(lc.i - rc.i); + return ulpDiff <= maxUlpDiff; +} + +} + +namespace Catch { +namespace Matchers { +namespace Floating { + WithinAbsMatcher::WithinAbsMatcher(double target, double margin) + :m_target{ target }, m_margin{ margin } { + CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.' + << " Margin has to be non-negative."); + } + + // Performs equivalent check of std::fabs(lhs - rhs) <= margin + // But without the subtraction to allow for INFINITY in comparison + bool WithinAbsMatcher::match(double const& matchee) const { + return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee); + } + + std::string WithinAbsMatcher::describe() const { + return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target); + } + + WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType) + :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } { + CATCH_ENFORCE(ulps >= 0, "Invalid ULP setting: " << ulps << '.' + << " ULPs have to be non-negative."); + } + +#if defined(__clang__) +#pragma clang diagnostic push +// Clang <3.5 reports on the default branch in the switch below +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + + bool WithinUlpsMatcher::match(double const& matchee) const { + switch (m_type) { + case FloatingPointKind::Float: + return almostEqualUlps(static_cast(matchee), static_cast(m_target), m_ulps); + case FloatingPointKind::Double: + return almostEqualUlps(matchee, m_target, m_ulps); + default: + CATCH_INTERNAL_ERROR( "Unknown FloatingPointKind value" ); + } + } + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif -namespace Catch { -namespace Matchers { - namespace Impl { + std::string WithinUlpsMatcher::describe() const { + return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : ""); + } - std::string MatcherUntypedBase::toString() const { - if( m_cachedToString.empty() ) - m_cachedToString = describe(); - return m_cachedToString; - } +}// namespace Floating - MatcherUntypedBase::~MatcherUntypedBase() = default; +Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff) { + return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double); +} - } // namespace Impl -} // namespace Matchers +Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff) { + return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float); +} -using namespace Matchers; -using Matchers::Impl::MatcherBase; +Floating::WithinAbsMatcher WithinAbs(double target, double margin) { + return Floating::WithinAbsMatcher(target, margin); +} +} // namespace Matchers } // namespace Catch -// end catch_matchers.cpp + +// end catch_matchers_floating.cpp +// start catch_matchers_generic.cpp + +std::string Catch::Matchers::Generic::Detail::finalizeDescription(const std::string& desc) { + if (desc.empty()) { + return "matches undescribed predicate"; + } else { + return "matches predicate: \"" + desc + '"'; + } +} +// end catch_matchers_generic.cpp // start catch_matchers_string.cpp +#include + namespace Catch { namespace Matchers { @@ -7134,6 +8633,21 @@ namespace Matchers { return endsWith( m_comparator.adjustString( source ), m_comparator.m_str ); } + RegexMatcher::RegexMatcher(std::string regex, CaseSensitive::Choice caseSensitivity): m_regex(std::move(regex)), m_caseSensitivity(caseSensitivity) {} + + bool RegexMatcher::match(std::string const& matchee) const { + auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway + if (m_caseSensitivity == CaseSensitive::Choice::No) { + flags |= std::regex::icase; + } + auto reg = std::regex(m_regex, flags); + return std::regex_match(matchee, reg); + } + + std::string RegexMatcher::describe() const { + return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Choice::Yes)? " case sensitively" : " case insensitively"); + } + } // namespace StdString StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) { @@ -7149,14 +8663,27 @@ namespace Matchers { return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) ); } + StdString::RegexMatcher Matches(std::string const& regex, CaseSensitive::Choice caseSensitivity) { + return StdString::RegexMatcher(regex, caseSensitivity); + } + } // namespace Matchers } // namespace Catch // end catch_matchers_string.cpp // start catch_message.cpp +// start catch_uncaught_exceptions.h + +namespace Catch { + bool uncaught_exceptions(); +} // end namespace Catch + +// end catch_uncaught_exceptions.h +#include + namespace Catch { - MessageInfo::MessageInfo( std::string const& _macroName, + MessageInfo::MessageInfo( StringRef const& _macroName, SourceLineInfo const& _lineInfo, ResultWas::OfType _type ) : macroName( _macroName ), @@ -7178,7 +8705,7 @@ namespace Catch { //////////////////////////////////////////////////////////////////////////// - Catch::MessageBuilder::MessageBuilder( std::string const& macroName, + Catch::MessageBuilder::MessageBuilder( StringRef const& macroName, SourceLineInfo const& lineInfo, ResultWas::OfType type ) :m_info(macroName, lineInfo, type) {} @@ -7193,65 +8720,281 @@ namespace Catch { } ScopedMessage::~ScopedMessage() { - if ( !std::uncaught_exception() ){ + if ( !uncaught_exceptions() ){ getResultCapture().popScopedMessage(m_info); } } + Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) { + auto start = std::string::npos; + for( size_t pos = 0; pos <= names.size(); ++pos ) { + char c = names[pos]; + if( pos == names.size() || c == ' ' || c == '\t' || c == ',' || c == ']' ) { + if( start != std::string::npos ) { + m_messages.push_back( MessageInfo( macroName, lineInfo, resultType ) ); + m_messages.back().message = names.substr( start, pos-start) + " := "; + start = std::string::npos; + } + } + else if( c != '[' && c != ']' && start == std::string::npos ) + start = pos; + } + } + Capturer::~Capturer() { + if ( !uncaught_exceptions() ){ + assert( m_captured == m_messages.size() ); + for( size_t i = 0; i < m_captured; ++i ) + m_resultCapture.popScopedMessage( m_messages[i] ); + } + } + + void Capturer::captureValue( size_t index, StringRef value ) { + assert( index < m_messages.size() ); + m_messages[index].message += value; + m_resultCapture.pushScopedMessage( m_messages[index] ); + m_captured++; + } + } // end namespace Catch // end catch_message.cpp -// start catch_random_number_generator.cpp +// start catch_output_redirect.cpp -// start catch_random_number_generator.h +// start catch_output_redirect.h +#ifndef TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H +#define TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H -#include +#include +#include +#include namespace Catch { - struct IConfig; + class RedirectedStream { + std::ostream& m_originalStream; + std::ostream& m_redirectionStream; + std::streambuf* m_prevBuf; - void seedRng( IConfig const& config ); + public: + RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ); + ~RedirectedStream(); + }; - unsigned int rngSeed(); + class RedirectedStdOut { + ReusableStringStream m_rss; + RedirectedStream m_cout; + public: + RedirectedStdOut(); + auto str() const -> std::string; + }; - struct RandomNumberGenerator { - using result_type = unsigned int; + // StdErr has two constituent streams in C++, std::cerr and std::clog + // This means that we need to redirect 2 streams into 1 to keep proper + // order of writes + class RedirectedStdErr { + ReusableStringStream m_rss; + RedirectedStream m_cerr; + RedirectedStream m_clog; + public: + RedirectedStdErr(); + auto str() const -> std::string; + }; - static constexpr result_type (min)() { return 0; } - static constexpr result_type (max)() { return 1000000; } +#if defined(CATCH_CONFIG_NEW_CAPTURE) - result_type operator()( result_type n ) const; - result_type operator()() const; + // Windows's implementation of std::tmpfile is terrible (it tries + // to create a file inside system folder, thus requiring elevated + // privileges for the binary), so we have to use tmpnam(_s) and + // create the file ourselves there. + class TempFile { + public: + TempFile(TempFile const&) = delete; + TempFile& operator=(TempFile const&) = delete; + TempFile(TempFile&&) = delete; + TempFile& operator=(TempFile&&) = delete; - template - static void shuffle( V& vector ) { - RandomNumberGenerator rng; - std::shuffle( vector.begin(), vector.end(), rng ); - } + TempFile(); + ~TempFile(); + + std::FILE* getFile(); + std::string getContents(); + + private: + std::FILE* m_file = nullptr; + #if defined(_MSC_VER) + char m_buffer[L_tmpnam] = { 0 }; + #endif }; -} + class OutputRedirect { + public: + OutputRedirect(OutputRedirect const&) = delete; + OutputRedirect& operator=(OutputRedirect const&) = delete; + OutputRedirect(OutputRedirect&&) = delete; + OutputRedirect& operator=(OutputRedirect&&) = delete; -// end catch_random_number_generator.h -#include + OutputRedirect(std::string& stdout_dest, std::string& stderr_dest); + ~OutputRedirect(); + + private: + int m_originalStdout = -1; + int m_originalStderr = -1; + TempFile m_stdoutFile; + TempFile m_stderrFile; + std::string& m_stdoutDest; + std::string& m_stderrDest; + }; + +#endif + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H +// end catch_output_redirect.h +#include +#include +#include +#include +#include + +#if defined(CATCH_CONFIG_NEW_CAPTURE) + #if defined(_MSC_VER) + #include //_dup and _dup2 + #define dup _dup + #define dup2 _dup2 + #define fileno _fileno + #else + #include // dup and dup2 + #endif +#endif namespace Catch { - void seedRng( IConfig const& config ) { - if( config.rngSeed() != 0 ) - std::srand( config.rngSeed() ); + RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ) + : m_originalStream( originalStream ), + m_redirectionStream( redirectionStream ), + m_prevBuf( m_originalStream.rdbuf() ) + { + m_originalStream.rdbuf( m_redirectionStream.rdbuf() ); } - unsigned int rngSeed() { - return getCurrentContext().getConfig()->rngSeed(); + + RedirectedStream::~RedirectedStream() { + m_originalStream.rdbuf( m_prevBuf ); + } + + RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {} + auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); } + + RedirectedStdErr::RedirectedStdErr() + : m_cerr( Catch::cerr(), m_rss.get() ), + m_clog( Catch::clog(), m_rss.get() ) + {} + auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); } + +#if defined(CATCH_CONFIG_NEW_CAPTURE) + +#if defined(_MSC_VER) + TempFile::TempFile() { + if (tmpnam_s(m_buffer)) { + CATCH_RUNTIME_ERROR("Could not get a temp filename"); + } + if (fopen_s(&m_file, m_buffer, "w")) { + char buffer[100]; + if (strerror_s(buffer, errno)) { + CATCH_RUNTIME_ERROR("Could not translate errno to a string"); + } + CATCH_RUNTIME_ERROR("Coul dnot open the temp file: '" << m_buffer << "' because: " << buffer); + } + } +#else + TempFile::TempFile() { + m_file = std::tmpfile(); + if (!m_file) { + CATCH_RUNTIME_ERROR("Could not create a temp file."); + } + } + +#endif + + TempFile::~TempFile() { + // TBD: What to do about errors here? + std::fclose(m_file); + // We manually create the file on Windows only, on Linux + // it will be autodeleted +#if defined(_MSC_VER) + std::remove(m_buffer); +#endif + } + + FILE* TempFile::getFile() { + return m_file; + } + + std::string TempFile::getContents() { + std::stringstream sstr; + char buffer[100] = {}; + std::rewind(m_file); + while (std::fgets(buffer, sizeof(buffer), m_file)) { + sstr << buffer; + } + return sstr.str(); + } + + OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) : + m_originalStdout(dup(1)), + m_originalStderr(dup(2)), + m_stdoutDest(stdout_dest), + m_stderrDest(stderr_dest) { + dup2(fileno(m_stdoutFile.getFile()), 1); + dup2(fileno(m_stderrFile.getFile()), 2); + } + + OutputRedirect::~OutputRedirect() { + Catch::cout() << std::flush; + fflush(stdout); + // Since we support overriding these streams, we flush cerr + // even though std::cerr is unbuffered + Catch::cerr() << std::flush; + Catch::clog() << std::flush; + fflush(stderr); + + dup2(m_originalStdout, 1); + dup2(m_originalStderr, 2); + + m_stdoutDest += m_stdoutFile.getContents(); + m_stderrDest += m_stderrFile.getContents(); } - RandomNumberGenerator::result_type RandomNumberGenerator::operator()( result_type n ) const { - return std::rand() % n; +#endif // CATCH_CONFIG_NEW_CAPTURE + +} // namespace Catch + +#if defined(CATCH_CONFIG_NEW_CAPTURE) + #if defined(_MSC_VER) + #undef dup + #undef dup2 + #undef fileno + #endif +#endif +// end catch_output_redirect.cpp +// start catch_random_number_generator.cpp + +namespace Catch { + + std::mt19937& rng() { + static std::mt19937 s_rng; + return s_rng; } - RandomNumberGenerator::result_type RandomNumberGenerator::operator()() const { - return std::rand() % (max)(); + + void seedRng( IConfig const& config ) { + if( config.rngSeed() != 0 ) { + std::srand( config.rngSeed() ); + rng().seed( config.rngSeed() ); + } } + unsigned int rngSeed() { + return getCurrentContext().getConfig()->rngSeed(); + } } // end catch_random_number_generator.cpp // start catch_registry_hub.cpp @@ -7303,7 +9046,7 @@ namespace Catch { void invoke() const override; }; - std::string extractClassName( std::string const& classOrQualifiedMethodName ); + std::string extractClassName( StringRef const& classOrQualifiedMethodName ); /////////////////////////////////////////////////////////////////////////// @@ -7391,6 +9134,41 @@ namespace Catch { } // end namespace Catch // end catch_startup_exception_registry.h +// start catch_singletons.hpp + +namespace Catch { + + struct ISingleton { + virtual ~ISingleton(); + }; + + void addSingleton( ISingleton* singleton ); + void cleanupSingletons(); + + template + class Singleton : SingletonImplT, public ISingleton { + + static auto getInternal() -> Singleton* { + static Singleton* s_instance = nullptr; + if( !s_instance ) { + s_instance = new Singleton; + addSingleton( s_instance ); + } + return s_instance; + } + + public: + static auto get() -> InterfaceT const& { + return *getInternal(); + } + static auto getMutable() -> MutableInterfaceT& { + return *getInternal(); + } + }; + +} // namespace Catch + +// end catch_singletons.hpp namespace Catch { namespace { @@ -7406,7 +9184,7 @@ namespace Catch { ITestCaseRegistry const& getTestCaseRegistry() const override { return m_testCaseRegistry; } - IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() override { + IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override { return m_exceptionTranslatorRegistry; } ITagAliasRegistry const& getTagAliasRegistry() const override { @@ -7443,25 +9221,18 @@ namespace Catch { TagAliasRegistry m_tagAliasRegistry; StartupExceptionRegistry m_exceptionRegistry; }; - - // Single, global, instance - RegistryHub*& getTheRegistryHub() { - static RegistryHub* theRegistryHub = nullptr; - if( !theRegistryHub ) - theRegistryHub = new RegistryHub(); - return theRegistryHub; - } } - IRegistryHub& getRegistryHub() { - return *getTheRegistryHub(); + using RegistryHubSingleton = Singleton; + + IRegistryHub const& getRegistryHub() { + return RegistryHubSingleton::get(); } IMutableRegistryHub& getMutableRegistryHub() { - return *getTheRegistryHub(); + return RegistryHubSingleton::getMutable(); } void cleanUp() { - delete getTheRegistryHub(); - getTheRegistryHub() = nullptr; + cleanupSingletons(); cleanUpContext(); } std::string translateActiveException() { @@ -7497,182 +9268,97 @@ namespace Catch { return m_listeners; } -} -// end catch_reporter_registry.cpp -// start catch_result_type.cpp - -namespace Catch { - - bool isOk( ResultWas::OfType resultType ) { - return ( resultType & ResultWas::FailureBit ) == 0; - } - bool isJustInfo( int flags ) { - return flags == ResultWas::Info; - } - - ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { - return static_cast( static_cast( lhs ) | static_cast( rhs ) ); - } - - bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } - bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } - bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } - -} // end namespace Catch -// end catch_result_type.cpp -// start catch_run_context.cpp -// start catch_run_context.h - -#include - -namespace Catch { - - struct IMutableContext; - - class StreamRedirect { - - public: - StreamRedirect(std::ostream& stream, std::string& targetString); - - ~StreamRedirect(); - - private: - std::ostream& m_stream; - std::streambuf* m_prevBuf; - std::ostringstream m_oss; - std::string& m_targetString; - }; - - // StdErr has two constituent streams in C++, std::cerr and std::clog - // This means that we need to redirect 2 streams into 1 to keep proper - // order of writes and cannot use StreamRedirect on its own - class StdErrRedirect { - public: - StdErrRedirect(std::string& targetString); - ~StdErrRedirect(); - private: - std::streambuf* m_cerrBuf; - std::streambuf* m_clogBuf; - std::ostringstream m_oss; - std::string& m_targetString; - }; - - /////////////////////////////////////////////////////////////////////////// - - class RunContext : public IResultCapture, public IRunner { - - public: - RunContext( RunContext const& ) = delete; - RunContext& operator =( RunContext const& ) = delete; - - explicit RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter); - - virtual ~RunContext(); - - void testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount); - void testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount); - - Totals runTest(TestCase const& testCase); - - IConfigPtr config() const; - IStreamingReporter& reporter() const; - - private: // IResultCapture - - void assertionStarting(AssertionInfo const& info) override; - void assertionEnded(AssertionResult const& result) override; - - bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override; - bool testForMissingAssertions(Counts& assertions); - - void sectionEnded(SectionEndInfo const& endInfo) override; - void sectionEndedEarly(SectionEndInfo const& endInfo) override; - - void benchmarkStarting( BenchmarkInfo const& info ) override; - void benchmarkEnded( BenchmarkStats const& stats ) override; - - void pushScopedMessage(MessageInfo const& message) override; - void popScopedMessage(MessageInfo const& message) override; - - std::string getCurrentTestName() const override; - - const AssertionResult* getLastResult() const override; - - void exceptionEarlyReported() override; - - void handleFatalErrorCondition( StringRef message ) override; - - bool lastAssertionPassed() override; - - void assertionPassed() override; - - void assertionRun() override; +} +// end catch_reporter_registry.cpp +// start catch_result_type.cpp - public: - // !TBD We need to do this another way! - bool aborting() const override; +namespace Catch { - private: + bool isOk( ResultWas::OfType resultType ) { + return ( resultType & ResultWas::FailureBit ) == 0; + } + bool isJustInfo( int flags ) { + return flags == ResultWas::Info; + } - void runCurrentTest(std::string& redirectedCout, std::string& redirectedCerr); - void invokeActiveTestCase(); + ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { + return static_cast( static_cast( lhs ) | static_cast( rhs ) ); + } - private: + bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } + bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } - void handleUnfinishedSections(); +} // end namespace Catch +// end catch_result_type.cpp +// start catch_run_context.cpp - TestRunInfo m_runInfo; - IMutableContext& m_context; - TestCase const* m_activeTestCase = nullptr; - ITracker* m_testCaseTracker; - Option m_lastResult; +#include +#include +#include - IConfigPtr m_config; - Totals m_totals; - IStreamingReporterPtr m_reporter; - std::vector m_messages; - AssertionInfo m_lastAssertionInfo; - std::vector m_unfinishedSections; - std::vector m_activeSections; - TrackerContext m_trackerContext; - std::size_t m_prevPassed = 0; - bool m_shouldReportUnexpected = true; - }; +namespace Catch { - IResultCapture& getResultCapture(); + namespace Generators { + struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker { + size_t m_index = static_cast( -1 ); + GeneratorBasePtr m_generator; -} // end namespace Catch + GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( nameAndLocation, ctx, parent ) + {} + ~GeneratorTracker(); -// end catch_run_context.h + static GeneratorTracker& acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) { + std::shared_ptr tracker; -#include -#include + ITracker& currentTracker = ctx.currentTracker(); + if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { + assert( childTracker ); + assert( childTracker->isIndexTracker() ); + tracker = std::static_pointer_cast( childTracker ); + } + else { + tracker = std::make_shared( nameAndLocation, ctx, ¤tTracker ); + currentTracker.addChild( tracker ); + } -namespace Catch { + if( !ctx.completedCycle() && !tracker->isComplete() ) { + if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) + tracker->moveNext(); + tracker->open(); + } - StreamRedirect::StreamRedirect(std::ostream& stream, std::string& targetString) - : m_stream(stream), - m_prevBuf(stream.rdbuf()), - m_targetString(targetString) { - stream.rdbuf(m_oss.rdbuf()); - } + return *tracker; + } - StreamRedirect::~StreamRedirect() { - m_targetString += m_oss.str(); - m_stream.rdbuf(m_prevBuf); - } + void moveNext() { + m_index++; + m_children.clear(); + } - StdErrRedirect::StdErrRedirect(std::string & targetString) - :m_cerrBuf(cerr().rdbuf()), m_clogBuf(clog().rdbuf()), - m_targetString(targetString) { - cerr().rdbuf(m_oss.rdbuf()); - clog().rdbuf(m_oss.rdbuf()); - } + // TrackerBase interface + bool isIndexTracker() const override { return true; } + auto hasGenerator() const -> bool override { + return !!m_generator; + } + void close() override { + TrackerBase::close(); + if( m_runState == CompletedSuccessfully && m_index < m_generator->size()-1 ) + m_runState = Executing; + } - StdErrRedirect::~StdErrRedirect() { - m_targetString += m_oss.str(); - cerr().rdbuf(m_cerrBuf); - clog().rdbuf(m_clogBuf); + // IGeneratorTracker interface + auto getGenerator() const -> GeneratorBasePtr const& override { + return m_generator; + } + void setGenerator( GeneratorBasePtr&& generator ) override { + m_generator = std::move( generator ); + } + auto getIndex() const -> size_t override { + return m_index; + } + }; + GeneratorTracker::~GeneratorTracker() {} } RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter) @@ -7680,7 +9366,8 @@ namespace Catch { m_context(getCurrentMutableContext()), m_config(_config), m_reporter(std::move(reporter)), - m_lastAssertionInfo{ "", SourceLineInfo("",0), "", ResultDisposition::Normal } + m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal }, + m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions ) { m_context.setRunner(this); m_context.setConfig(m_config); @@ -7706,7 +9393,7 @@ namespace Catch { std::string redirectedCout; std::string redirectedCerr; - TestCaseInfo testInfo = testCase.getTestCaseInfo(); + auto const& testInfo = testCase.getTestCaseInfo(); m_reporter->testCaseStarting(testInfo); @@ -7748,27 +9435,33 @@ namespace Catch { return *m_reporter; } - void RunContext::assertionStarting(AssertionInfo const& info) { - m_reporter->assertionStarting( info ); - } void RunContext::assertionEnded(AssertionResult const & result) { if (result.getResultType() == ResultWas::Ok) { m_totals.assertions.passed++; + m_lastAssertionPassed = true; } else if (!result.isOk()) { + m_lastAssertionPassed = false; if( m_activeTestCase->getTestCaseInfo().okToFail() ) m_totals.assertions.failedButOk++; else m_totals.assertions.failed++; } + else { + m_lastAssertionPassed = true; + } // We have no use for the return value (whether messages should be cleared), because messages were made scoped // and should be let to clear themselves out. static_cast(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); // Reset working state - m_lastAssertionInfo = { "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}", m_lastAssertionInfo.resultDisposition }; + resetAssertionInfo(); m_lastResult = result; } + void RunContext::resetAssertionInfo() { + m_lastAssertionInfo.macroName = StringRef(); + m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr; + } bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) { ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo)); @@ -7784,6 +9477,13 @@ namespace Catch { return true; } + auto RunContext::acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { + using namespace Generators; + GeneratorTracker& tracker = GeneratorTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( "generator", lineInfo ) ); + assert( tracker.isOpen() ); + m_lastAssertionInfo.lineInfo = lineInfo; + return tracker; + } bool RunContext::testForMissingAssertions(Counts& assertions) { if (assertions.total() != 0) @@ -7858,13 +9558,13 @@ namespace Catch { tempResult.message = message; AssertionResult result(m_lastAssertionInfo, tempResult); - getResultCapture().assertionEnded(result); + assertionEnded(result); handleUnfinishedSections(); // Recreate section for test case (as we will lose the one that was in scope) auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); - SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description); + SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); Counts assertions; assertions.failed = 1; @@ -7887,17 +9587,13 @@ namespace Catch { } bool RunContext::lastAssertionPassed() { - return m_totals.assertions.passed == (m_prevPassed + 1); + return m_lastAssertionPassed; } void RunContext::assertionPassed() { + m_lastAssertionPassed = true; ++m_totals.assertions.passed; - m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"; - m_lastAssertionInfo.macroName = ""; - } - - void RunContext::assertionRun() { - m_prevPassed = m_totals.assertions.passed; + resetAssertionInfo(); } bool RunContext::aborting() const { @@ -7906,45 +9602,53 @@ namespace Catch { void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) { auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); - SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description); + SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); m_reporter->sectionStarting(testCaseSection); Counts prevAssertions = m_totals.assertions; double duration = 0; m_shouldReportUnexpected = true; - try { - m_lastAssertionInfo = { "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal }; + m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal }; - seedRng(*m_config); + seedRng(*m_config); - Timer timer; - timer.start(); + Timer timer; + CATCH_TRY { if (m_reporter->getPreferences().shouldRedirectStdOut) { - StreamRedirect coutRedir(cout(), redirectedCout); - StdErrRedirect errRedir(redirectedCerr); +#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) + RedirectedStdOut redirectedStdOut; + RedirectedStdErr redirectedStdErr; + + timer.start(); + invokeActiveTestCase(); + redirectedCout += redirectedStdOut.str(); + redirectedCerr += redirectedStdErr.str(); +#else + OutputRedirect r(redirectedCout, redirectedCerr); + timer.start(); invokeActiveTestCase(); +#endif } else { + timer.start(); invokeActiveTestCase(); } duration = timer.getElapsedSeconds(); - } catch (TestFailureException&) { + } CATCH_CATCH_ANON (TestFailureException&) { // This just means the test was aborted due to failure - } catch (...) { + } CATCH_CATCH_ALL { // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions // are reported without translation at the point of origin. - if (m_shouldReportUnexpected) { - AssertionHandler - ( m_lastAssertionInfo.macroName, - m_lastAssertionInfo.lineInfo, - m_lastAssertionInfo.capturedExpression, - m_lastAssertionInfo.resultDisposition ).useActiveException(); + if( m_shouldReportUnexpected ) { + AssertionReaction dummyReaction; + handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction ); } } + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions(assertions); + m_testCaseTracker->close(); handleUnfinishedSections(); m_messages.clear(); - Counts assertions = m_totals.assertions - prevAssertions; - bool missingAssertions = testForMissingAssertions(assertions); SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); m_reporter->sectionEnded(testCaseSectionStats); } @@ -7966,6 +9670,112 @@ namespace Catch { m_unfinishedSections.clear(); } + void RunContext::handleExpr( + AssertionInfo const& info, + ITransientExpression const& expr, + AssertionReaction& reaction + ) { + m_reporter->assertionStarting( info ); + + bool negated = isFalseTest( info.resultDisposition ); + bool result = expr.getResult() != negated; + + if( result ) { + if (!m_includeSuccessfulResults) { + assertionPassed(); + } + else { + reportExpr(info, ResultWas::Ok, &expr, negated); + } + } + else { + reportExpr(info, ResultWas::ExpressionFailed, &expr, negated ); + populateReaction( reaction ); + } + } + void RunContext::reportExpr( + AssertionInfo const &info, + ResultWas::OfType resultType, + ITransientExpression const *expr, + bool negated ) { + + m_lastAssertionInfo = info; + AssertionResultData data( resultType, LazyExpression( negated ) ); + + AssertionResult assertionResult{ info, data }; + assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; + + assertionEnded( assertionResult ); + } + + void RunContext::handleMessage( + AssertionInfo const& info, + ResultWas::OfType resultType, + StringRef const& message, + AssertionReaction& reaction + ) { + m_reporter->assertionStarting( info ); + + m_lastAssertionInfo = info; + + AssertionResultData data( resultType, LazyExpression( false ) ); + data.message = message; + AssertionResult assertionResult{ m_lastAssertionInfo, data }; + assertionEnded( assertionResult ); + if( !assertionResult.isOk() ) + populateReaction( reaction ); + } + void RunContext::handleUnexpectedExceptionNotThrown( + AssertionInfo const& info, + AssertionReaction& reaction + ) { + handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction); + } + + void RunContext::handleUnexpectedInflightException( + AssertionInfo const& info, + std::string const& message, + AssertionReaction& reaction + ) { + m_lastAssertionInfo = info; + + AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); + data.message = message; + AssertionResult assertionResult{ info, data }; + assertionEnded( assertionResult ); + populateReaction( reaction ); + } + + void RunContext::populateReaction( AssertionReaction& reaction ) { + reaction.shouldDebugBreak = m_config->shouldDebugBreak(); + reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal); + } + + void RunContext::handleIncomplete( + AssertionInfo const& info + ) { + m_lastAssertionInfo = info; + + AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); + data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; + AssertionResult assertionResult{ info, data }; + assertionEnded( assertionResult ); + } + void RunContext::handleNonExpr( + AssertionInfo const &info, + ResultWas::OfType resultType, + AssertionReaction &reaction + ) { + m_lastAssertionInfo = info; + + AssertionResultData data( resultType, LazyExpression( false ) ); + AssertionResult assertionResult{ info, data }; + assertionEnded( assertionResult ); + + if( !assertionResult.isOk() ) + populateReaction( reaction ); + } + IResultCapture& getResultCapture() { if (auto* capture = getCurrentContext().getResultCapture()) return *capture; @@ -7985,22 +9795,15 @@ namespace Catch { m_timer.start(); } -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable:4996) // std::uncaught_exception is deprecated in C++17 -#endif Section::~Section() { if( m_sectionIncluded ) { - SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); - if( std::uncaught_exception() ) + SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() }; + if( uncaught_exceptions() ) getResultCapture().sectionEndedEarly( endInfo ); else getResultCapture().sectionEnded( endInfo ); } } -#if defined(_MSC_VER) -#pragma warning(pop) -#endif // This indicates whether the section should be executed or not Section::operator bool() const { @@ -8015,17 +9818,11 @@ namespace Catch { SectionInfo::SectionInfo ( SourceLineInfo const& _lineInfo, - std::string const& _name, - std::string const& _description ) + std::string const& _name ) : name( _name ), - description( _description ), lineInfo( _lineInfo ) {} - SectionEndInfo::SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) - : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) - {} - } // end namespace Catch // end catch_section_info.cpp // start catch_session.cpp @@ -8045,12 +9842,12 @@ namespace Catch { void showHelp() const; void libIdentify(); - int applyCommandLine( int argc, char* argv[] ); + int applyCommandLine( int argc, char const * const * argv ); void useConfigData( ConfigData const& configData ); int run( int argc, char* argv[] ); - #if defined(WIN32) && defined(UNICODE) + #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) int run( int argc, wchar_t* const argv[] ); #endif int run(); @@ -8105,108 +9902,110 @@ namespace Catch { #include #include -namespace { - const int MaxExitCode = 255; - using Catch::IStreamingReporterPtr; - using Catch::IConfigPtr; - using Catch::Config; - - IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) { - auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config); - CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'"); +namespace Catch { - return reporter; - } + namespace { + const int MaxExitCode = 255; -#ifndef CATCH_CONFIG_DEFAULT_REPORTER -#define CATCH_CONFIG_DEFAULT_REPORTER "console" -#endif + IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) { + auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config); + CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'"); - IStreamingReporterPtr makeReporter(std::shared_ptr const& config) { - auto const& reporterNames = config->getReporterNames(); - if (reporterNames.empty()) - return createReporter(CATCH_CONFIG_DEFAULT_REPORTER, config); + return reporter; + } - IStreamingReporterPtr reporter; - for (auto const& name : reporterNames) - addReporter(reporter, createReporter(name, config)); - return reporter; - } + IStreamingReporterPtr makeReporter(std::shared_ptr const& config) { + if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) { + return createReporter(config->getReporterName(), config); + } -#undef CATCH_CONFIG_DEFAULT_REPORTER + auto multi = std::unique_ptr(new ListeningReporter); - void addListeners(IStreamingReporterPtr& reporters, IConfigPtr const& config) { - auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); - for (auto const& listener : listeners) - addReporter(reporters, listener->create(Catch::ReporterConfig(config))); - } + auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); + for (auto const& listener : listeners) { + multi->addListener(listener->create(Catch::ReporterConfig(config))); + } + multi->addReporter(createReporter(config->getReporterName(), config)); + return std::move(multi); + } - Catch::Totals runTests(std::shared_ptr const& config) { - using namespace Catch; - IStreamingReporterPtr reporter = makeReporter(config); - addListeners(reporter, config); + Catch::Totals runTests(std::shared_ptr const& config) { + // FixMe: Add listeners in order first, then add reporters. - RunContext context(config, std::move(reporter)); + auto reporter = makeReporter(config); - Totals totals; + RunContext context(config, std::move(reporter)); - context.testGroupStarting(config->name(), 1, 1); + Totals totals; - TestSpec testSpec = config->testSpec(); - if (!testSpec.hasFilters()) - testSpec = TestSpecParser(ITagAliasRegistry::get()).parse("~[.]").testSpec(); // All not hidden tests + context.testGroupStarting(config->name(), 1, 1); - auto const& allTestCases = getAllTestCasesSorted(*config); - for (auto const& testCase : allTestCases) { - if (!context.aborting() && matchTest(testCase, testSpec, *config)) - totals += context.runTest(testCase); - else - context.reporter().skipTest(testCase); - } + TestSpec testSpec = config->testSpec(); - context.testGroupEnded(config->name(), totals, 1, 1); - return totals; - } + auto const& allTestCases = getAllTestCasesSorted(*config); + for (auto const& testCase : allTestCases) { + if (!context.aborting() && matchTest(testCase, testSpec, *config)) + totals += context.runTest(testCase); + else + context.reporter().skipTest(testCase); + } - void applyFilenamesAsTags(Catch::IConfig const& config) { - using namespace Catch; - auto& tests = const_cast&>(getAllTestCasesSorted(config)); - for (auto& testCase : tests) { - auto tags = testCase.tags; + if (config->warnAboutNoTests() && totals.testCases.total() == 0) { + ReusableStringStream testConfig; - std::string filename = testCase.lineInfo.file; - auto lastSlash = filename.find_last_of("\\/"); - if (lastSlash != std::string::npos) { - filename.erase(0, lastSlash); - filename[0] = '#'; - } + bool first = true; + for (const auto& input : config->getTestsOrTags()) { + if (!first) { testConfig << ' '; } + first = false; + testConfig << input; + } - auto lastDot = filename.find_last_of('.'); - if (lastDot != std::string::npos) { - filename.erase(lastDot); + context.reporter().noMatchingTestCases(testConfig.str()); + totals.error = -1; } - tags.push_back(std::move(filename)); - setTags(testCase, tags); + context.testGroupEnded(config->name(), totals, 1, 1); + return totals; } - } -} + void applyFilenamesAsTags(Catch::IConfig const& config) { + auto& tests = const_cast&>(getAllTestCasesSorted(config)); + for (auto& testCase : tests) { + auto tags = testCase.tags; -namespace Catch { + std::string filename = testCase.lineInfo.file; + auto lastSlash = filename.find_last_of("\\/"); + if (lastSlash != std::string::npos) { + filename.erase(0, lastSlash); + filename[0] = '#'; + } + + auto lastDot = filename.find_last_of('.'); + if (lastDot != std::string::npos) { + filename.erase(lastDot); + } + + tags.push_back(std::move(filename)); + setTags(testCase, tags); + } + } + + } // anon namespace Session::Session() { static bool alreadyInstantiated = false; if( alreadyInstantiated ) { - try { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); } - catch(...) { getMutableRegistryHub().registerStartupException(); } + CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); } + CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); } } + // There cannot be exceptions at startup in no-exception mode. +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions(); if ( !exceptions.empty() ) { m_startupExceptions = true; Colour colourGuard( Colour::Red ); - Catch::cerr() << "Errors occured during startup!" << '\n'; + Catch::cerr() << "Errors occurred during startup!" << '\n'; // iterate over all exceptions and notify user for ( const auto& ex_ptr : exceptions ) { try { @@ -8216,6 +10015,7 @@ namespace Catch { } } } +#endif alreadyInstantiated = true; m_cli = makeCommandLineParser( m_configData ); @@ -8238,7 +10038,7 @@ namespace Catch { << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; } - int Session::applyCommandLine( int argc, char* argv[] ) { + int Session::applyCommandLine( int argc, char const * const * argv ) { if( m_startupExceptions ) return 1; @@ -8275,7 +10075,7 @@ namespace Catch { return returnCode; } -#if defined(WIN32) && defined(UNICODE) +#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) int Session::run( int argc, wchar_t* const argv[] ) { char **utf8Argv = new char *[ argc ]; @@ -8330,11 +10130,11 @@ namespace Catch { if( m_startupExceptions ) return 1; - if( m_configData.showHelp || m_configData.libIdentify ) + if (m_configData.showHelp || m_configData.libIdentify) { return 0; + } - try - { + CATCH_TRY { config(); // Force config to be constructed seedRng( *m_config ); @@ -8346,24 +10146,59 @@ namespace Catch { if( Option listed = list( config() ) ) return static_cast( *listed ); - return (std::min)( MaxExitCode, static_cast( runTests( m_config ).assertions.failed ) ); + auto totals = runTests( m_config ); + // Note that on unices only the lower 8 bits are usually used, clamping + // the return value to 255 prevents false negative when some multiple + // of 256 tests has failed + return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast(totals.assertions.failed))); } +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) catch( std::exception& ex ) { Catch::cerr() << ex.what() << std::endl; return MaxExitCode; } +#endif } } // end namespace Catch // end catch_session.cpp +// start catch_singletons.cpp + +#include + +namespace Catch { + + namespace { + static auto getSingletons() -> std::vector*& { + static std::vector* g_singletons = nullptr; + if( !g_singletons ) + g_singletons = new std::vector(); + return g_singletons; + } + } + + ISingleton::~ISingleton() {} + + void addSingleton(ISingleton* singleton ) { + getSingletons()->push_back( singleton ); + } + void cleanupSingletons() { + auto& singletons = getSingletons(); + for( auto singleton : *singletons ) + delete singleton; + delete singletons; + singletons = nullptr; + } + +} // namespace Catch +// end catch_singletons.cpp // start catch_startup_exception_registry.cpp namespace Catch { - void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { - try { +void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { + CATCH_TRY { m_exceptions.push_back(exception); - } - catch(...) { + } CATCH_CATCH_ALL { // If we run out of memory during start-up there's really not a lot more we can do about it std::terminate(); } @@ -8377,106 +10212,175 @@ namespace Catch { // end catch_startup_exception_registry.cpp // start catch_stream.cpp -#include #include #include +#include +#include +#include +#include namespace Catch { - template - class StreamBufImpl : public StreamBufBase { - char data[bufferSize]; - WriterF m_writer; + Catch::IStream::~IStream() = default; - public: - StreamBufImpl() { - setp( data, data + sizeof(data) ); - } + namespace detail { namespace { + template + class StreamBufImpl : public std::streambuf { + char data[bufferSize]; + WriterF m_writer; - ~StreamBufImpl() noexcept { - StreamBufImpl::sync(); - } + public: + StreamBufImpl() { + setp( data, data + sizeof(data) ); + } - private: - int overflow( int c ) override { - sync(); + ~StreamBufImpl() noexcept { + StreamBufImpl::sync(); + } - if( c != EOF ) { - if( pbase() == epptr() ) - m_writer( std::string( 1, static_cast( c ) ) ); - else - sputc( static_cast( c ) ); + private: + int overflow( int c ) override { + sync(); + + if( c != EOF ) { + if( pbase() == epptr() ) + m_writer( std::string( 1, static_cast( c ) ) ); + else + sputc( static_cast( c ) ); + } + return 0; } - return 0; - } - int sync() override { - if( pbase() != pptr() ) { - m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); - setp( pbase(), epptr() ); + int sync() override { + if( pbase() != pptr() ) { + m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); + setp( pbase(), epptr() ); + } + return 0; } - return 0; - } - }; + }; - /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// - Catch::IStream::~IStream() = default; + struct OutputDebugWriter { - FileStream::FileStream( std::string const& filename ) { - m_ofs.open( filename.c_str() ); - CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << "'" ); - } + void operator()( std::string const&str ) { + writeToDebugConsole( str ); + } + }; + + /////////////////////////////////////////////////////////////////////////// + + class FileStream : public IStream { + mutable std::ofstream m_ofs; + public: + FileStream( StringRef filename ) { + m_ofs.open( filename.c_str() ); + CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << "'" ); + } + ~FileStream() override = default; + public: // IStream + std::ostream& stream() const override { + return m_ofs; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + class CoutStream : public IStream { + mutable std::ostream m_os; + public: + // Store the streambuf from cout up-front because + // cout may get redirected when running tests + CoutStream() : m_os( Catch::cout().rdbuf() ) {} + ~CoutStream() override = default; + + public: // IStream + std::ostream& stream() const override { return m_os; } + }; + + /////////////////////////////////////////////////////////////////////////// + + class DebugOutStream : public IStream { + std::unique_ptr> m_streamBuf; + mutable std::ostream m_os; + public: + DebugOutStream() + : m_streamBuf( new StreamBufImpl() ), + m_os( m_streamBuf.get() ) + {} + + ~DebugOutStream() override = default; - std::ostream& FileStream::stream() const { - return m_ofs; + public: // IStream + std::ostream& stream() const override { return m_os; } + }; + + }} // namespace anon::detail + + /////////////////////////////////////////////////////////////////////////// + + auto makeStream( StringRef const &filename ) -> IStream const* { + if( filename.empty() ) + return new detail::CoutStream(); + else if( filename[0] == '%' ) { + if( filename == "%debug" ) + return new detail::DebugOutStream(); + else + CATCH_ERROR( "Unrecognised stream: '" << filename << "'" ); + } + else + return new detail::FileStream( filename ); } - struct OutputDebugWriter { + // This class encapsulates the idea of a pool of ostringstreams that can be reused. + struct StringStreams { + std::vector> m_streams; + std::vector m_unused; + std::ostringstream m_referenceStream; // Used for copy state/ flags from - void operator()( std::string const&str ) { - writeToDebugConsole( str ); + auto add() -> std::size_t { + if( m_unused.empty() ) { + m_streams.push_back( std::unique_ptr( new std::ostringstream ) ); + return m_streams.size()-1; + } + else { + auto index = m_unused.back(); + m_unused.pop_back(); + return index; + } + } + + void release( std::size_t index ) { + m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state + m_unused.push_back(index); } }; - DebugOutStream::DebugOutStream() - : m_streamBuf( new StreamBufImpl() ), - m_os( m_streamBuf.get() ) + ReusableStringStream::ReusableStringStream() + : m_index( Singleton::getMutable().add() ), + m_oss( Singleton::getMutable().m_streams[m_index].get() ) {} - std::ostream& DebugOutStream::stream() const { - return m_os; + ReusableStringStream::~ReusableStringStream() { + static_cast( m_oss )->str(""); + m_oss->clear(); + Singleton::getMutable().release( m_index ); } - // Store the streambuf from cout up-front because - // cout may get redirected when running tests - CoutStream::CoutStream() - : m_os( Catch::cout().rdbuf() ) - {} - - std::ostream& CoutStream::stream() const { - return m_os; + auto ReusableStringStream::str() const -> std::string { + return static_cast( m_oss )->str(); } + /////////////////////////////////////////////////////////////////////////// + #ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions - std::ostream& cout() { - return std::cout; - } - std::ostream& cerr() { - return std::cerr; - } - std::ostream& clog() { - return std::clog; - } + std::ostream& cout() { return std::cout; } + std::ostream& cerr() { return std::cerr; } + std::ostream& clog() { return std::clog; } #endif } // end catch_stream.cpp -// start catch_streambuf.cpp - -namespace Catch { - StreamBufBase::~StreamBufBase() = default; -} -// end catch_streambuf.cpp // start catch_string_manip.cpp #include @@ -8486,6 +10390,12 @@ namespace Catch { namespace Catch { + namespace { + char toLowerCh(char c) { + return static_cast( std::tolower( c ) ); + } + } + bool startsWith( std::string const& s, std::string const& prefix ) { return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); } @@ -8501,9 +10411,6 @@ namespace Catch { bool contains( std::string const& s, std::string const& infix ) { return s.find( infix ) != std::string::npos; } - char toLowerCh(char c) { - return static_cast( std::tolower( c ) ); - } void toLowerInPlace( std::string& s ) { std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); } @@ -8556,62 +10463,20 @@ namespace Catch { #endif #include -#include #include +#include -namespace Catch { - - auto getEmptyStringRef() -> StringRef { - static StringRef s_emptyStringRef(""); - return s_emptyStringRef; - } - - StringRef::StringRef() noexcept - : StringRef( getEmptyStringRef() ) - {} - - StringRef::StringRef( StringRef const& other ) noexcept - : m_start( other.m_start ), - m_size( other.m_size ) - {} - - StringRef::StringRef( StringRef&& other ) noexcept - : m_start( other.m_start ), - m_size( other.m_size ), - m_data( other.m_data ) - { - other.m_data = nullptr; - } +namespace { + const uint32_t byte_2_lead = 0xC0; + const uint32_t byte_3_lead = 0xE0; + const uint32_t byte_4_lead = 0xF0; +} +namespace Catch { StringRef::StringRef( char const* rawChars ) noexcept - : m_start( rawChars ), - m_size( static_cast( std::strlen( rawChars ) ) ) - { - assert( rawChars != nullptr ); - } - - StringRef::StringRef( char const* rawChars, size_type size ) noexcept - : m_start( rawChars ), - m_size( size ) - { - size_type rawSize = rawChars == nullptr ? 0 : static_cast( std::strlen( rawChars ) ); - if( rawSize < size ) - m_size = rawSize; - } - - StringRef::StringRef( std::string const& stdString ) noexcept - : m_start( stdString.c_str() ), - m_size( stdString.size() ) + : StringRef( rawChars, static_cast(std::strlen(rawChars) ) ) {} - StringRef::~StringRef() noexcept { - delete[] m_data; - } - - auto StringRef::operator = ( StringRef other ) noexcept -> StringRef& { - swap( other ); - return *this; - } StringRef::operator std::string() const { return std::string( m_start, m_size ); } @@ -8627,7 +10492,7 @@ namespace Catch { const_cast( this )->takeOwnership(); return m_start; } - auto StringRef::data() const noexcept -> char const* { + auto StringRef::currentData() const noexcept -> char const* { return m_start; } @@ -8665,25 +10530,17 @@ namespace Catch { return m_start[index]; } - auto StringRef::empty() const noexcept -> bool { - return m_size == 0; - } - - auto StringRef::size() const noexcept -> size_type { - return m_size; - } auto StringRef::numberOfCharacters() const noexcept -> size_type { size_type noChars = m_size; // Make adjustments for uft encodings for( size_type i=0; i < m_size; ++i ) { char c = m_start[i]; - if( ( c & 0b11000000 ) == 0b11000000 ) { - if( ( c & 0b11100000 ) == 0b11000000 ) + if( ( c & byte_2_lead ) == byte_2_lead ) { + noChars--; + if (( c & byte_3_lead ) == byte_3_lead ) + noChars--; + if( ( c & byte_4_lead ) == byte_4_lead ) noChars--; - else if( ( c & 0b11110000 ) == 0b11100000 ) - noChars-=2; - else if( ( c & 0b11111000 ) == 0b11110000 ) - noChars-=3; } } return noChars; @@ -8704,7 +10561,12 @@ namespace Catch { } auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& { - return os << str.c_str(); + return os.write(str.currentData(), str.size()); + } + + auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& { + lhs.append(rhs.currentData(), rhs.size()); + return lhs; } } // namespace Catch @@ -8724,9 +10586,9 @@ namespace Catch { namespace Catch { RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) { - try { + CATCH_TRY { getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo); - } catch (...) { + } CATCH_CATCH_ALL { // Do not throw when constructing global objects, instead register the exception to be processed later getMutableRegistryHub().registerStartupException(); } @@ -8736,6 +10598,8 @@ namespace Catch { // end catch_tag_alias_autoregistrar.cpp // start catch_tag_alias_registry.cpp +#include + namespace Catch { TagAliasRegistry::~TagAliasRegistry() {} @@ -8784,40 +10648,42 @@ namespace Catch { #include #include #include +#include namespace Catch { - TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { - if( startsWith( tag, '.' ) || - tag == "!hide" ) - return TestCaseInfo::IsHidden; - else if( tag == "!throws" ) - return TestCaseInfo::Throws; - else if( tag == "!shouldfail" ) - return TestCaseInfo::ShouldFail; - else if( tag == "!mayfail" ) - return TestCaseInfo::MayFail; - else if( tag == "!nonportable" ) - return TestCaseInfo::NonPortable; - else if( tag == "!benchmark" ) - return static_cast( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden ); - else - return TestCaseInfo::None; - } - bool isReservedTag( std::string const& tag ) { - return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( tag[0] ); - } - void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { - CATCH_ENFORCE( !isReservedTag(tag), - "Tag name: [" << tag << "] is not allowed.\n" - << "Tag names starting with non alpha-numeric characters are reserved\n" - << _lineInfo ); + namespace { + TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { + if( startsWith( tag, '.' ) || + tag == "!hide" ) + return TestCaseInfo::IsHidden; + else if( tag == "!throws" ) + return TestCaseInfo::Throws; + else if( tag == "!shouldfail" ) + return TestCaseInfo::ShouldFail; + else if( tag == "!mayfail" ) + return TestCaseInfo::MayFail; + else if( tag == "!nonportable" ) + return TestCaseInfo::NonPortable; + else if( tag == "!benchmark" ) + return static_cast( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden ); + else + return TestCaseInfo::None; + } + bool isReservedTag( std::string const& tag ) { + return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast(tag[0]) ); + } + void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { + CATCH_ENFORCE( !isReservedTag(tag), + "Tag name: [" << tag << "] is not allowed.\n" + << "Tag names starting with non alpha-numeric characters are reserved\n" + << _lineInfo ); + } } TestCase makeTestCase( ITestInvoker* _testCase, std::string const& _className, - std::string const& _name, - std::string const& _descOrTags, + NameAndTags const& nameAndTags, SourceLineInfo const& _lineInfo ) { bool isHidden = false; @@ -8826,6 +10692,7 @@ namespace Catch { std::vector tags; std::string desc, tag; bool inTag = false; + std::string _descOrTags = nameAndTags.tags; for (char c : _descOrTags) { if( !inTag ) { if( c == '[' ) @@ -8853,8 +10720,8 @@ namespace Catch { tags.push_back( "." ); } - TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); - return TestCase( _testCase, info ); + TestCaseInfo info( nameAndTags.name, _className, desc, tags, _lineInfo ); + return TestCase( _testCase, std::move(info) ); } void setTags( TestCaseInfo& testCaseInfo, std::vector tags ) { @@ -8914,7 +10781,7 @@ namespace Catch { return ret; } - TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} + TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo&& info ) : TestCaseInfo( std::move(info) ), test( testCase ) {} TestCase TestCase::withName( std::string const& _newName ) const { TestCase other( *this ); @@ -8959,7 +10826,7 @@ namespace Catch { break; case RunTests::InRandomOrder: seedRng( config ); - RandomNumberGenerator::shuffle( sorted ); + std::shuffle( sorted.begin(), sorted.end(), rng() ); break; case RunTests::InDeclarationOrder: // already in declaration order @@ -8997,9 +10864,9 @@ namespace Catch { void TestRegistry::registerTest( TestCase const& testCase ) { std::string name = testCase.getTestCaseInfo().name; if( name.empty() ) { - std::ostringstream oss; - oss << "Anonymous test case " << ++m_unnamedCount; - return registerTest( testCase.withName( oss.str() ) ); + ReusableStringStream rss; + rss << "Anonymous test case " << ++m_unnamedCount; + return registerTest( testCase.withName( rss.str() ) ); } m_functions.push_back( testCase ); } @@ -9025,7 +10892,7 @@ namespace Catch { m_testAsFunction(); } - std::string extractClassName( std::string const& classOrQualifiedMethodName ) { + std::string extractClassName( StringRef const& classOrQualifiedMethodName ) { std::string className = classOrQualifiedMethodName; if( startsWith( className, '&' ) ) { @@ -9043,9 +10910,10 @@ namespace Catch { // start catch_test_case_tracker.cpp #include -#include +#include #include #include +#include #if defined(__clang__) # pragma clang diagnostic push @@ -9098,13 +10966,6 @@ namespace TestCaseTracking { m_currentTracker = tracker; } - TrackerBase::TrackerHasName::TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {} - bool TrackerBase::TrackerHasName::operator ()( ITrackerPtr const& tracker ) const { - return - tracker->nameAndLocation().name == m_nameAndLocation.name && - tracker->nameAndLocation().location == m_nameAndLocation.location; - } - TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) : m_nameAndLocation( nameAndLocation ), m_ctx( ctx ), @@ -9132,7 +10993,12 @@ namespace TestCaseTracking { } ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) { - auto it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) ); + auto it = std::find_if( m_children.begin(), m_children.end(), + [&nameAndLocation]( ITrackerPtr const& tracker ){ + return + tracker->nameAndLocation().location == nameAndLocation.location && + tracker->nameAndLocation().name == nameAndLocation.name; + } ); return( it != m_children.end() ) ? *it : nullptr; @@ -9321,19 +11187,18 @@ namespace Catch { return new(std::nothrow) TestInvokerAsFunction( testAsFunction ); } - NameAndTags::NameAndTags( StringRef name_ , StringRef tags_ ) noexcept : name( name_ ), tags( tags_ ) {} + NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {} - AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept { - try { + AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept { + CATCH_TRY { getMutableRegistryHub() .registerTest( makeTestCase( invoker, extractClassName( classOrMethod ), - nameAndTags.name, - nameAndTags.tags, + nameAndTags, lineInfo)); - } catch (...) { + } CATCH_CATCH_ALL { // Do not throw when constructing global objects, instead register the exception to be processed later getMutableRegistryHub().registerStartupException(); } @@ -9479,32 +11344,44 @@ namespace Catch { #include +static const uint64_t nanosecondsInSecond = 1000000000; + namespace Catch { auto getCurrentNanosecondsSinceEpoch() -> uint64_t { return std::chrono::duration_cast( std::chrono::high_resolution_clock::now().time_since_epoch() ).count(); } - auto estimateClockResolution() -> uint64_t { - uint64_t sum = 0; - static const uint64_t iterations = 1000000; + namespace { + auto estimateClockResolution() -> uint64_t { + uint64_t sum = 0; + static const uint64_t iterations = 1000000; + + auto startTime = getCurrentNanosecondsSinceEpoch(); + + for( std::size_t i = 0; i < iterations; ++i ) { - for( std::size_t i = 0; i < iterations; ++i ) { + uint64_t ticks; + uint64_t baseTicks = getCurrentNanosecondsSinceEpoch(); + do { + ticks = getCurrentNanosecondsSinceEpoch(); + } while( ticks == baseTicks ); - uint64_t ticks; - uint64_t baseTicks = getCurrentNanosecondsSinceEpoch(); - do { - ticks = getCurrentNanosecondsSinceEpoch(); + auto delta = ticks - baseTicks; + sum += delta; + + // If we have been calibrating for over 3 seconds -- the clock + // is terrible and we should move on. + // TBD: How to signal that the measured resolution is probably wrong? + if (ticks > startTime + 3 * nanosecondsInSecond) { + return sum / i; + } } - while( ticks == baseTicks ); - auto delta = ticks - baseTicks; - sum += delta; + // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers + // - and potentially do more iterations if there's a high variance. + return sum/iterations; } - - // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers - // - and potentially do more iterations if there's a high variance. - return sum/iterations; } auto getEstimatedClockResolution() -> uint64_t { static auto s_resolution = estimateClockResolution(); @@ -9514,11 +11391,11 @@ namespace Catch { void Timer::start() { m_nanoseconds = getCurrentNanosecondsSinceEpoch(); } - auto Timer::getElapsedNanoseconds() const -> unsigned int { - return static_cast(getCurrentNanosecondsSinceEpoch() - m_nanoseconds); + auto Timer::getElapsedNanoseconds() const -> uint64_t { + return getCurrentNanosecondsSinceEpoch() - m_nanoseconds; } - auto Timer::getElapsedMicroseconds() const -> unsigned int { - return static_cast(getElapsedNanoseconds()/1000); + auto Timer::getElapsedMicroseconds() const -> uint64_t { + return getElapsedNanoseconds()/1000; } auto Timer::getElapsedMilliseconds() const -> unsigned int { return static_cast(getElapsedMicroseconds()/1000); @@ -9537,6 +11414,12 @@ namespace Catch { # pragma clang diagnostic ignored "-Wglobal-constructors" #endif +// Enable specific decls locally +#if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +#define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +#endif + +#include #include namespace Catch { @@ -9572,21 +11455,25 @@ namespace Detail { } unsigned char const *bytes = static_cast(object); - std::ostringstream os; - os << "0x" << std::setfill('0') << std::hex; + ReusableStringStream rss; + rss << "0x" << std::setfill('0') << std::hex; for( ; i != end; i += inc ) - os << std::setw(2) << static_cast(bytes[i]); - return os.str(); + rss << std::setw(2) << static_cast(bytes[i]); + return rss.str(); } } template std::string fpToString( T value, int precision ) { - std::ostringstream oss; - oss << std::setprecision( precision ) + if (std::isnan(value)) { + return "nan"; + } + + ReusableStringStream rss; + rss << std::setprecision( precision ) << std::fixed << value; - std::string d = oss.str(); + std::string d = rss.str(); std::size_t i = d.find_last_not_of( '0' ); if( i != std::string::npos && i != d.size()-1 ) { if( d[i] == '.' ) @@ -9625,6 +11512,7 @@ std::string StringMaker::convert(const std::string& str) { return s; } +#ifdef CATCH_CONFIG_WCHAR std::string StringMaker::convert(const std::wstring& wstr) { std::string s; s.reserve(wstr.size()); @@ -9633,6 +11521,7 @@ std::string StringMaker::convert(const std::wstring& wstr) { } return ::Catch::Detail::stringify(s); } +#endif std::string StringMaker::convert(char const* str) { if (str) { @@ -9648,6 +11537,7 @@ std::string StringMaker::convert(char* str) { return{ "{null string}" }; } } +#ifdef CATCH_CONFIG_WCHAR std::string StringMaker::convert(wchar_t const * str) { if (str) { return ::Catch::Detail::stringify(std::wstring{ str }); @@ -9662,6 +11552,7 @@ std::string StringMaker::convert(wchar_t * str) { return{ "{null string}" }; } } +#endif std::string StringMaker::convert(int value) { return ::Catch::Detail::stringify(static_cast(value)); @@ -9670,12 +11561,12 @@ std::string StringMaker::convert(long value) { return ::Catch::Detail::stringify(static_cast(value)); } std::string StringMaker::convert(long long value) { - std::ostringstream oss; - oss << value; + ReusableStringStream rss; + rss << value; if (value > Detail::hexThreshold) { - oss << " (0x" << std::hex << value << ')'; + rss << " (0x" << std::hex << value << ')'; } - return oss.str(); + return rss.str(); } std::string StringMaker::convert(unsigned int value) { @@ -9685,12 +11576,12 @@ std::string StringMaker::convert(unsigned long value) { return ::Catch::Detail::stringify(static_cast(value)); } std::string StringMaker::convert(unsigned long long value) { - std::ostringstream oss; - oss << value; + ReusableStringStream rss; + rss << value; if (value > Detail::hexThreshold) { - oss << " (0x" << std::hex << value << ')'; + rss << " (0x" << std::hex << value << ')'; } - return oss.str(); + return rss.str(); } std::string StringMaker::convert(bool b) { @@ -9732,6 +11623,13 @@ std::string StringMaker::convert(double value) { return fpToString(value, 10); } +std::string ratio_string::symbol() { return "a"; } +std::string ratio_string::symbol() { return "f"; } +std::string ratio_string::symbol() { return "p"; } +std::string ratio_string::symbol() { return "n"; } +std::string ratio_string::symbol() { return "u"; } +std::string ratio_string::symbol() { return "m"; } + } // end namespace Catch #if defined(__clang__) @@ -9794,6 +11692,20 @@ namespace Catch { } // end catch_totals.cpp +// start catch_uncaught_exceptions.cpp + +#include + +namespace Catch { + bool uncaught_exceptions() { +#if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) + return std::uncaught_exceptions() > 0; +#else + return std::uncaught_exception(); +#endif + } +} // end namespace Catch +// end catch_uncaught_exceptions.cpp // start catch_version.cpp #include @@ -9826,7 +11738,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 2, 0, 1, "", 0 ); + static Version version( 2, 4, 0, "", 0 ); return version; } @@ -9834,6 +11746,8 @@ namespace Catch { // end catch_version.cpp // start catch_wildcard_pattern.cpp +#include + namespace Catch { WildcardPattern::WildcardPattern( std::string const& pattern, @@ -9873,106 +11787,47 @@ namespace Catch { // end catch_wildcard_pattern.cpp // start catch_xmlwriter.cpp -// start catch_xmlwriter.h +#include -#include -#include +using uchar = unsigned char; namespace Catch { - class XmlEncode { - public: - enum ForWhat { ForTextNodes, ForAttributes }; - - XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); - - void encodeTo( std::ostream& os ) const; - - friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); - - private: - std::string m_str; - ForWhat m_forWhat; - }; - - class XmlWriter { - public: - - class ScopedElement { - public: - ScopedElement( XmlWriter* writer ); - - ScopedElement( ScopedElement&& other ) noexcept; - ScopedElement& operator=( ScopedElement&& other ) noexcept; - - ~ScopedElement(); - - ScopedElement& writeText( std::string const& text, bool indent = true ); - - template - ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { - m_writer->writeAttribute( name, attribute ); - return *this; - } - - private: - mutable XmlWriter* m_writer = nullptr; - }; - - XmlWriter( std::ostream& os = Catch::cout() ); - ~XmlWriter(); - - XmlWriter( XmlWriter const& ) = delete; - XmlWriter& operator=( XmlWriter const& ) = delete; - - XmlWriter& startElement( std::string const& name ); - - ScopedElement scopedElement( std::string const& name ); - - XmlWriter& endElement(); - - XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); - - XmlWriter& writeAttribute( std::string const& name, bool attribute ); +namespace { - template - XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { - m_oss.clear(); - m_oss.str(std::string()); - m_oss << attribute; - return writeAttribute( name, m_oss.str() ); + size_t trailingBytes(unsigned char c) { + if ((c & 0xE0) == 0xC0) { + return 2; } + if ((c & 0xF0) == 0xE0) { + return 3; + } + if ((c & 0xF8) == 0xF0) { + return 4; + } + CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); + } - XmlWriter& writeText( std::string const& text, bool indent = true ); - - XmlWriter& writeComment( std::string const& text ); - - void writeStylesheetRef( std::string const& url ); - - XmlWriter& writeBlankLine(); - - void ensureTagClosed(); - - private: - - void writeDeclaration(); - - void newlineIfNecessary(); - - bool m_tagIsOpen = false; - bool m_needsNewline = false; - std::vector m_tags; - std::string m_indent; - std::ostream& m_os; - std::ostringstream m_oss; - }; - -} + uint32_t headerValue(unsigned char c) { + if ((c & 0xE0) == 0xC0) { + return c & 0x1F; + } + if ((c & 0xF0) == 0xE0) { + return c & 0x0F; + } + if ((c & 0xF8) == 0xF0) { + return c & 0x07; + } + CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); + } -// end catch_xmlwriter.h -#include + void hexEscapeChar(std::ostream& os, unsigned char c) { + os << "\\x" + << std::uppercase << std::hex << std::setfill('0') << std::setw(2) + << static_cast(c); + } -namespace Catch { +} // anonymous namespace XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat ) : m_str( str ), @@ -9980,41 +11835,95 @@ namespace Catch { {} void XmlEncode::encodeTo( std::ostream& os ) const { - // Apostrophe escaping not necessary if we always use " to write attributes // (see: http://www.w3.org/TR/xml/#syntax) - for( std::size_t i = 0; i < m_str.size(); ++ i ) { - char c = m_str[i]; - switch( c ) { - case '<': os << "<"; break; - case '&': os << "&"; break; + for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { + uchar c = m_str[idx]; + switch (c) { + case '<': os << "<"; break; + case '&': os << "&"; break; - case '>': - // See: http://www.w3.org/TR/xml/#syntax - if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) - os << ">"; - else - os << c; + case '>': + // See: http://www.w3.org/TR/xml/#syntax + if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']') + os << ">"; + else + os << c; + break; + + case '\"': + if (m_forWhat == ForAttributes) + os << """; + else + os << c; + break; + + default: + // Check for control characters and invalid utf-8 + + // Escape control characters in standard ascii + // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 + if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) { + hexEscapeChar(os, c); break; + } - case '\"': - if( m_forWhat == ForAttributes ) - os << """; - else - os << c; + // Plain ASCII: Write it to stream + if (c < 0x7F) { + os << c; break; + } - default: - // Escape control chars - based on contribution by @espenalb in PR #465 and - // by @mrpi PR #588 - if ( ( c >= 0 && c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) { - // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 - os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) - << static_cast( c ); - } - else - os << c; + // UTF-8 territory + // Check if the encoding is valid and if it is not, hex escape bytes. + // Important: We do not check the exact decoded values for validity, only the encoding format + // First check that this bytes is a valid lead byte: + // This means that it is not encoded as 1111 1XXX + // Or as 10XX XXXX + if (c < 0xC0 || + c >= 0xF8) { + hexEscapeChar(os, c); + break; + } + + auto encBytes = trailingBytes(c); + // Are there enough bytes left to avoid accessing out-of-bounds memory? + if (idx + encBytes - 1 >= m_str.size()) { + hexEscapeChar(os, c); + break; + } + // The header is valid, check data + // The next encBytes bytes must together be a valid utf-8 + // This means: bitpattern 10XX XXXX and the extracted value is sane (ish) + bool valid = true; + uint32_t value = headerValue(c); + for (std::size_t n = 1; n < encBytes; ++n) { + uchar nc = m_str[idx + n]; + valid &= ((nc & 0xC0) == 0x80); + value = (value << 6) | (nc & 0x3F); + } + + if ( + // Wrong bit pattern of following bytes + (!valid) || + // Overlong encodings + (value < 0x80) || + (0x80 <= value && value < 0x800 && encBytes > 2) || + (0x800 < value && value < 0x10000 && encBytes > 3) || + // Encoded value out of range + (value >= 0x110000) + ) { + hexEscapeChar(os, c); + break; + } + + // If we got here, this is in fact a valid(ish) utf-8 sequence + for (std::size_t n = 0; n < encBytes; ++n) { + os << m_str[idx + n]; + } + idx += encBytes - 1; + break; } } } @@ -10156,7 +12065,7 @@ namespace Catch { #include #include #include -#include +#include #include namespace Catch { @@ -10187,60 +12096,260 @@ namespace Catch { TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config) :StreamingReporterBase(_config) {} - void TestEventListenerBase::assertionStarting(AssertionInfo const &) {} + void TestEventListenerBase::assertionStarting(AssertionInfo const &) {} + + bool TestEventListenerBase::assertionEnded(AssertionStats const &) { + return false; + } + +} // end namespace Catch +// end catch_reporter_bases.cpp +// start catch_reporter_compact.cpp + +namespace { + +#ifdef CATCH_PLATFORM_MAC + const char* failedString() { return "FAILED"; } + const char* passedString() { return "PASSED"; } +#else + const char* failedString() { return "failed"; } + const char* passedString() { return "passed"; } +#endif + + // Colour::LightGrey + Catch::Colour::Code dimColour() { return Catch::Colour::FileName; } + + std::string bothOrAll( std::size_t count ) { + return count == 1 ? std::string() : + count == 2 ? "both " : "all " ; + } + +} // anon namespace + +namespace Catch { +namespace { +// Colour, message variants: +// - white: No tests ran. +// - red: Failed [both/all] N test cases, failed [both/all] M assertions. +// - white: Passed [both/all] N test cases (no assertions). +// - red: Failed N tests cases, failed M assertions. +// - green: Passed [both/all] N tests cases with M assertions. +void printTotals(std::ostream& out, const Totals& totals) { + if (totals.testCases.total() == 0) { + out << "No tests ran."; + } else if (totals.testCases.failed == totals.testCases.total()) { + Colour colour(Colour::ResultError); + const std::string qualify_assertions_failed = + totals.assertions.failed == totals.assertions.total() ? + bothOrAll(totals.assertions.failed) : std::string(); + out << + "Failed " << bothOrAll(totals.testCases.failed) + << pluralise(totals.testCases.failed, "test case") << ", " + "failed " << qualify_assertions_failed << + pluralise(totals.assertions.failed, "assertion") << '.'; + } else if (totals.assertions.total() == 0) { + out << + "Passed " << bothOrAll(totals.testCases.total()) + << pluralise(totals.testCases.total(), "test case") + << " (no assertions)."; + } else if (totals.assertions.failed) { + Colour colour(Colour::ResultError); + out << + "Failed " << pluralise(totals.testCases.failed, "test case") << ", " + "failed " << pluralise(totals.assertions.failed, "assertion") << '.'; + } else { + Colour colour(Colour::ResultSuccess); + out << + "Passed " << bothOrAll(totals.testCases.passed) + << pluralise(totals.testCases.passed, "test case") << + " with " << pluralise(totals.assertions.passed, "assertion") << '.'; + } +} + +// Implementation of CompactReporter formatting +class AssertionPrinter { +public: + AssertionPrinter& operator= (AssertionPrinter const&) = delete; + AssertionPrinter(AssertionPrinter const&) = delete; + AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) + : stream(_stream) + , result(_stats.assertionResult) + , messages(_stats.infoMessages) + , itMessage(_stats.infoMessages.begin()) + , printInfoMessages(_printInfoMessages) {} + + void print() { + printSourceInfo(); + + itMessage = messages.begin(); + + switch (result.getResultType()) { + case ResultWas::Ok: + printResultType(Colour::ResultSuccess, passedString()); + printOriginalExpression(); + printReconstructedExpression(); + if (!result.hasExpression()) + printRemainingMessages(Colour::None); + else + printRemainingMessages(); + break; + case ResultWas::ExpressionFailed: + if (result.isOk()) + printResultType(Colour::ResultSuccess, failedString() + std::string(" - but was ok")); + else + printResultType(Colour::Error, failedString()); + printOriginalExpression(); + printReconstructedExpression(); + printRemainingMessages(); + break; + case ResultWas::ThrewException: + printResultType(Colour::Error, failedString()); + printIssue("unexpected exception with message:"); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::FatalErrorCondition: + printResultType(Colour::Error, failedString()); + printIssue("fatal error condition with message:"); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::DidntThrowException: + printResultType(Colour::Error, failedString()); + printIssue("expected exception, got none"); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::Info: + printResultType(Colour::None, "info"); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::Warning: + printResultType(Colour::None, "warning"); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::ExplicitFailure: + printResultType(Colour::Error, failedString()); + printIssue("explicitly"); + printRemainingMessages(Colour::None); + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + printResultType(Colour::Error, "** internal error **"); + break; + } + } + +private: + void printSourceInfo() const { + Colour colourGuard(Colour::FileName); + stream << result.getSourceInfo() << ':'; + } - bool TestEventListenerBase::assertionEnded(AssertionStats const &) { - return false; + void printResultType(Colour::Code colour, std::string const& passOrFail) const { + if (!passOrFail.empty()) { + { + Colour colourGuard(colour); + stream << ' ' << passOrFail; + } + stream << ':'; + } } -} // end namespace Catch -// end catch_reporter_bases.cpp -// start catch_reporter_compact.cpp + void printIssue(std::string const& issue) const { + stream << ' ' << issue; + } -namespace { + void printExpressionWas() { + if (result.hasExpression()) { + stream << ';'; + { + Colour colour(dimColour()); + stream << " expression was:"; + } + printOriginalExpression(); + } + } -#ifdef CATCH_PLATFORM_MAC - const char* failedString() { return "FAILED"; } - const char* passedString() { return "PASSED"; } -#else - const char* failedString() { return "failed"; } - const char* passedString() { return "passed"; } -#endif + void printOriginalExpression() const { + if (result.hasExpression()) { + stream << ' ' << result.getExpression(); + } + } - // Colour::LightGrey - Catch::Colour::Code dimColour() { return Catch::Colour::FileName; } + void printReconstructedExpression() const { + if (result.hasExpandedExpression()) { + { + Colour colour(dimColour()); + stream << " for: "; + } + stream << result.getExpandedExpression(); + } + } - std::string bothOrAll( std::size_t count ) { - return count == 1 ? std::string() : - count == 2 ? "both " : "all " ; + void printMessage() { + if (itMessage != messages.end()) { + stream << " '" << itMessage->message << '\''; + ++itMessage; + } } -} -namespace Catch { + void printRemainingMessages(Colour::Code colour = dimColour()) { + if (itMessage == messages.end()) + return; - struct CompactReporter : StreamingReporterBase { + // using messages.end() directly yields (or auto) compilation error: + std::vector::const_iterator itEnd = messages.end(); + const std::size_t N = static_cast(std::distance(itMessage, itEnd)); - using StreamingReporterBase::StreamingReporterBase; + { + Colour colourGuard(colour); + stream << " with " << pluralise(N, "message") << ':'; + } - ~CompactReporter() override; + for (; itMessage != itEnd; ) { + // If this assertion is a warning ignore any INFO messages + if (printInfoMessages || itMessage->type != ResultWas::Info) { + stream << " '" << itMessage->message << '\''; + if (++itMessage != itEnd) { + Colour colourGuard(dimColour()); + stream << " and"; + } + } + } + } + +private: + std::ostream& stream; + AssertionResult const& result; + std::vector messages; + std::vector::const_iterator itMessage; + bool printInfoMessages; +}; + +} // anon namespace - static std::string getDescription() { + std::string CompactReporter::getDescription() { return "Reports test results on a single line, suitable for IDEs"; } - ReporterPreferences getPreferences() const override { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = false; - return prefs; + ReporterPreferences CompactReporter::getPreferences() const { + return m_reporterPrefs; } - void noMatchingTestCases( std::string const& spec ) override { + void CompactReporter::noMatchingTestCases( std::string const& spec ) { stream << "No test cases matched '" << spec << '\'' << std::endl; } - void assertionStarting( AssertionInfo const& ) override {} + void CompactReporter::assertionStarting( AssertionInfo const& ) {} - bool assertionEnded( AssertionStats const& _assertionStats ) override { + bool CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) { AssertionResult const& result = _assertionStats.assertionResult; bool printInfoMessages = true; @@ -10259,231 +12368,19 @@ namespace Catch { return true; } - void sectionEnded(SectionStats const& _sectionStats) override { + void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { if (m_config->showDurations() == ShowDurations::Always) { stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; } } - void testRunEnded( TestRunStats const& _testRunStats ) override { - printTotals( _testRunStats.totals ); + void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) { + printTotals( stream, _testRunStats.totals ); stream << '\n' << std::endl; StreamingReporterBase::testRunEnded( _testRunStats ); } - private: - class AssertionPrinter { - public: - AssertionPrinter& operator= ( AssertionPrinter const& ) = delete; - AssertionPrinter( AssertionPrinter const& ) = delete; - AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) - : stream( _stream ) - , result( _stats.assertionResult ) - , messages( _stats.infoMessages ) - , itMessage( _stats.infoMessages.begin() ) - , printInfoMessages( _printInfoMessages ) - {} - - void print() { - printSourceInfo(); - - itMessage = messages.begin(); - - switch( result.getResultType() ) { - case ResultWas::Ok: - printResultType( Colour::ResultSuccess, passedString() ); - printOriginalExpression(); - printReconstructedExpression(); - if ( ! result.hasExpression() ) - printRemainingMessages( Colour::None ); - else - printRemainingMessages(); - break; - case ResultWas::ExpressionFailed: - if( result.isOk() ) - printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); - else - printResultType( Colour::Error, failedString() ); - printOriginalExpression(); - printReconstructedExpression(); - printRemainingMessages(); - break; - case ResultWas::ThrewException: - printResultType( Colour::Error, failedString() ); - printIssue( "unexpected exception with message:" ); - printMessage(); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::FatalErrorCondition: - printResultType( Colour::Error, failedString() ); - printIssue( "fatal error condition with message:" ); - printMessage(); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::DidntThrowException: - printResultType( Colour::Error, failedString() ); - printIssue( "expected exception, got none" ); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::Info: - printResultType( Colour::None, "info" ); - printMessage(); - printRemainingMessages(); - break; - case ResultWas::Warning: - printResultType( Colour::None, "warning" ); - printMessage(); - printRemainingMessages(); - break; - case ResultWas::ExplicitFailure: - printResultType( Colour::Error, failedString() ); - printIssue( "explicitly" ); - printRemainingMessages( Colour::None ); - break; - // These cases are here to prevent compiler warnings - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - printResultType( Colour::Error, "** internal error **" ); - break; - } - } - - private: - void printSourceInfo() const { - Colour colourGuard( Colour::FileName ); - stream << result.getSourceInfo() << ':'; - } - - void printResultType( Colour::Code colour, std::string const& passOrFail ) const { - if( !passOrFail.empty() ) { - { - Colour colourGuard( colour ); - stream << ' ' << passOrFail; - } - stream << ':'; - } - } - - void printIssue( std::string const& issue ) const { - stream << ' ' << issue; - } - - void printExpressionWas() { - if( result.hasExpression() ) { - stream << ';'; - { - Colour colour( dimColour() ); - stream << " expression was:"; - } - printOriginalExpression(); - } - } - - void printOriginalExpression() const { - if( result.hasExpression() ) { - stream << ' ' << result.getExpression(); - } - } - - void printReconstructedExpression() const { - if( result.hasExpandedExpression() ) { - { - Colour colour( dimColour() ); - stream << " for: "; - } - stream << result.getExpandedExpression(); - } - } - - void printMessage() { - if ( itMessage != messages.end() ) { - stream << " '" << itMessage->message << '\''; - ++itMessage; - } - } - - void printRemainingMessages( Colour::Code colour = dimColour() ) { - if ( itMessage == messages.end() ) - return; - - // using messages.end() directly yields (or auto) compilation error: - std::vector::const_iterator itEnd = messages.end(); - const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); - - { - Colour colourGuard( colour ); - stream << " with " << pluralise( N, "message" ) << ':'; - } - - for(; itMessage != itEnd; ) { - // If this assertion is a warning ignore any INFO messages - if( printInfoMessages || itMessage->type != ResultWas::Info ) { - stream << " '" << itMessage->message << '\''; - if ( ++itMessage != itEnd ) { - Colour colourGuard( dimColour() ); - stream << " and"; - } - } - } - } - - private: - std::ostream& stream; - AssertionResult const& result; - std::vector messages; - std::vector::const_iterator itMessage; - bool printInfoMessages; - }; - - // Colour, message variants: - // - white: No tests ran. - // - red: Failed [both/all] N test cases, failed [both/all] M assertions. - // - white: Passed [both/all] N test cases (no assertions). - // - red: Failed N tests cases, failed M assertions. - // - green: Passed [both/all] N tests cases with M assertions. - - void printTotals( const Totals& totals ) const { - if( totals.testCases.total() == 0 ) { - stream << "No tests ran."; - } - else if( totals.testCases.failed == totals.testCases.total() ) { - Colour colour( Colour::ResultError ); - const std::string qualify_assertions_failed = - totals.assertions.failed == totals.assertions.total() ? - bothOrAll( totals.assertions.failed ) : std::string(); - stream << - "Failed " << bothOrAll( totals.testCases.failed ) - << pluralise( totals.testCases.failed, "test case" ) << ", " - "failed " << qualify_assertions_failed << - pluralise( totals.assertions.failed, "assertion" ) << '.'; - } - else if( totals.assertions.total() == 0 ) { - stream << - "Passed " << bothOrAll( totals.testCases.total() ) - << pluralise( totals.testCases.total(), "test case" ) - << " (no assertions)."; - } - else if( totals.assertions.failed ) { - Colour colour( Colour::ResultError ); - stream << - "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " - "failed " << pluralise( totals.assertions.failed, "assertion" ) << '.'; - } - else { - Colour colour( Colour::ResultSuccess ); - stream << - "Passed " << bothOrAll( totals.testCases.passed ) - << pluralise( totals.testCases.passed, "test case" ) << - " with " << pluralise( totals.assertions.passed, "assertion" ) << '.'; - } - } - }; - - CompactReporter::~CompactReporter() {} + CompactReporter::~CompactReporter() {} CATCH_REGISTER_REPORTER( "compact", CompactReporter ) @@ -10497,629 +12394,609 @@ namespace Catch { #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch - // Note that 4062 (not all labels are handled - // and default is missing) is enabled + // Note that 4062 (not all labels are handled + // and default is missing) is enabled #endif namespace Catch { - namespace { - std::size_t makeRatio( std::size_t number, std::size_t total ) { - std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; - return ( ratio == 0 && number > 0 ) ? 1 : ratio; +namespace { + +// Formatter impl for ConsoleReporter +class ConsoleAssertionPrinter { +public: + ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete; + ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete; + ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) + : stream(_stream), + stats(_stats), + result(_stats.assertionResult), + colour(Colour::None), + message(result.getMessage()), + messages(_stats.infoMessages), + printInfoMessages(_printInfoMessages) { + switch (result.getResultType()) { + case ResultWas::Ok: + colour = Colour::Success; + passOrFail = "PASSED"; + //if( result.hasMessage() ) + if (_stats.infoMessages.size() == 1) + messageLabel = "with message"; + if (_stats.infoMessages.size() > 1) + messageLabel = "with messages"; + break; + case ResultWas::ExpressionFailed: + if (result.isOk()) { + colour = Colour::Success; + passOrFail = "FAILED - but was ok"; + } else { + colour = Colour::Error; + passOrFail = "FAILED"; + } + if (_stats.infoMessages.size() == 1) + messageLabel = "with message"; + if (_stats.infoMessages.size() > 1) + messageLabel = "with messages"; + break; + case ResultWas::ThrewException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to unexpected exception with "; + if (_stats.infoMessages.size() == 1) + messageLabel += "message"; + if (_stats.infoMessages.size() > 1) + messageLabel += "messages"; + break; + case ResultWas::FatalErrorCondition: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to a fatal error condition"; + break; + case ResultWas::DidntThrowException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "because no exception was thrown where one was expected"; + break; + case ResultWas::Info: + messageLabel = "info"; + break; + case ResultWas::Warning: + messageLabel = "warning"; + break; + case ResultWas::ExplicitFailure: + passOrFail = "FAILED"; + colour = Colour::Error; + if (_stats.infoMessages.size() == 1) + messageLabel = "explicitly with message"; + if (_stats.infoMessages.size() > 1) + messageLabel = "explicitly with messages"; + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + passOrFail = "** internal error **"; + colour = Colour::Error; + break; } + } - std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { - if( i > j && i > k ) - return i; - else if( j > k ) - return j; - else - return k; + void print() const { + printSourceInfo(); + if (stats.totals.assertions.total() > 0) { + if (result.isOk()) + stream << '\n'; + printResultType(); + printOriginalExpression(); + printReconstructedExpression(); + } else { + stream << '\n'; } + printMessage(); + } - struct ColumnInfo { - enum Justification { Left, Right }; - std::string name; - int width; - Justification justification; - }; - struct ColumnBreak {}; - struct RowBreak {}; +private: + void printResultType() const { + if (!passOrFail.empty()) { + Colour colourGuard(colour); + stream << passOrFail << ":\n"; + } + } + void printOriginalExpression() const { + if (result.hasExpression()) { + Colour colourGuard(Colour::OriginalExpression); + stream << " "; + stream << result.getExpressionInMacro(); + stream << '\n'; + } + } + void printReconstructedExpression() const { + if (result.hasExpandedExpression()) { + stream << "with expansion:\n"; + Colour colourGuard(Colour::ReconstructedExpression); + stream << Column(result.getExpandedExpression()).indent(2) << '\n'; + } + } + void printMessage() const { + if (!messageLabel.empty()) + stream << messageLabel << ':' << '\n'; + for (auto const& msg : messages) { + // If this assertion is a warning ignore any INFO messages + if (printInfoMessages || msg.type != ResultWas::Info) + stream << Column(msg.message).indent(2) << '\n'; + } + } + void printSourceInfo() const { + Colour colourGuard(Colour::FileName); + stream << result.getSourceInfo() << ": "; + } - class TablePrinter { - std::ostream& m_os; - std::vector m_columnInfos; - std::ostringstream m_oss; - int m_currentColumn = -1; - bool m_isOpen = false; + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + Colour::Code colour; + std::string passOrFail; + std::string messageLabel; + std::string message; + std::vector messages; + bool printInfoMessages; +}; - public: - TablePrinter( std::ostream& os, std::vector const& columnInfos ) - : m_os( os ), - m_columnInfos( columnInfos ) - {} +std::size_t makeRatio(std::size_t number, std::size_t total) { + std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0; + return (ratio == 0 && number > 0) ? 1 : ratio; +} - auto columnInfos() const -> std::vector const& { - return m_columnInfos; - } +std::size_t& findMax(std::size_t& i, std::size_t& j, std::size_t& k) { + if (i > j && i > k) + return i; + else if (j > k) + return j; + else + return k; +} - void open() { - if( !m_isOpen ) { - m_isOpen = true; - *this << RowBreak(); - for( auto const& info : m_columnInfos ) - *this << info.name << ColumnBreak(); - *this << RowBreak(); - m_os << Catch::getLineOfChars<'-'>() << "\n"; - } - } - void close() { - if( m_isOpen ) { - *this << RowBreak(); - m_os << std::endl; - m_isOpen = false; - } - } +struct ColumnInfo { + enum Justification { Left, Right }; + std::string name; + int width; + Justification justification; +}; +struct ColumnBreak {}; +struct RowBreak {}; - template - friend TablePrinter& operator << ( TablePrinter& tp, T const& value ) { - tp.m_oss << value; - return tp; - } - - friend TablePrinter& operator << ( TablePrinter& tp, ColumnBreak ) { - auto colStr = tp.m_oss.str(); - // This takes account of utf8 encodings - auto strSize = Catch::StringRef( colStr ).numberOfCharacters(); - tp.m_oss.str(""); - tp.open(); - if( tp.m_currentColumn == static_cast(tp.m_columnInfos.size()-1) ) { - tp.m_currentColumn = -1; - tp.m_os << "\n"; - } - tp.m_currentColumn++; - - auto colInfo = tp.m_columnInfos[tp.m_currentColumn]; - auto padding = ( strSize+2 < static_cast( colInfo.width ) ) - ? std::string( colInfo.width-(strSize+2), ' ' ) - : std::string(); - if( colInfo.justification == ColumnInfo::Left ) - tp.m_os << colStr << padding << " "; - else - tp.m_os << padding << colStr << " "; - return tp; - } +class Duration { + enum class Unit { + Auto, + Nanoseconds, + Microseconds, + Milliseconds, + Seconds, + Minutes + }; + static const uint64_t s_nanosecondsInAMicrosecond = 1000; + static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond; + static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond; + static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond; - friend TablePrinter& operator << ( TablePrinter& tp, RowBreak ) { - if( tp.m_currentColumn > 0 ) { - tp.m_os << "\n"; - tp.m_currentColumn = -1; - } - return tp; - } - }; + uint64_t m_inNanoseconds; + Unit m_units; - class Duration { - enum class Unit { - Auto, - Nanoseconds, - Microseconds, - Milliseconds, - Seconds, - Minutes - }; - static const uint64_t s_nanosecondsInAMicrosecond = 1000; - static const uint64_t s_nanosecondsInAMillisecond = 1000*s_nanosecondsInAMicrosecond; - static const uint64_t s_nanosecondsInASecond = 1000*s_nanosecondsInAMillisecond; - static const uint64_t s_nanosecondsInAMinute = 60*s_nanosecondsInASecond; +public: + explicit Duration(uint64_t inNanoseconds, Unit units = Unit::Auto) + : m_inNanoseconds(inNanoseconds), + m_units(units) { + if (m_units == Unit::Auto) { + if (m_inNanoseconds < s_nanosecondsInAMicrosecond) + m_units = Unit::Nanoseconds; + else if (m_inNanoseconds < s_nanosecondsInAMillisecond) + m_units = Unit::Microseconds; + else if (m_inNanoseconds < s_nanosecondsInASecond) + m_units = Unit::Milliseconds; + else if (m_inNanoseconds < s_nanosecondsInAMinute) + m_units = Unit::Seconds; + else + m_units = Unit::Minutes; + } - uint64_t m_inNanoseconds; - Unit m_units; + } - public: - Duration( uint64_t inNanoseconds, Unit units = Unit::Auto ) - : m_inNanoseconds( inNanoseconds ), - m_units( units ) - { - if( m_units == Unit::Auto ) { - if( m_inNanoseconds < s_nanosecondsInAMicrosecond ) - m_units = Unit::Nanoseconds; - else if( m_inNanoseconds < s_nanosecondsInAMillisecond ) - m_units = Unit::Microseconds; - else if( m_inNanoseconds < s_nanosecondsInASecond ) - m_units = Unit::Milliseconds; - else if( m_inNanoseconds < s_nanosecondsInAMinute ) - m_units = Unit::Seconds; - else - m_units = Unit::Minutes; - } + auto value() const -> double { + switch (m_units) { + case Unit::Microseconds: + return m_inNanoseconds / static_cast(s_nanosecondsInAMicrosecond); + case Unit::Milliseconds: + return m_inNanoseconds / static_cast(s_nanosecondsInAMillisecond); + case Unit::Seconds: + return m_inNanoseconds / static_cast(s_nanosecondsInASecond); + case Unit::Minutes: + return m_inNanoseconds / static_cast(s_nanosecondsInAMinute); + default: + return static_cast(m_inNanoseconds); + } + } + auto unitsAsString() const -> std::string { + switch (m_units) { + case Unit::Nanoseconds: + return "ns"; + case Unit::Microseconds: + return "µs"; + case Unit::Milliseconds: + return "ms"; + case Unit::Seconds: + return "s"; + case Unit::Minutes: + return "m"; + default: + return "** internal error **"; + } - } + } + friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& { + return os << duration.value() << " " << duration.unitsAsString(); + } +}; +} // end anon namespace - auto value() const -> double { - switch( m_units ) { - case Unit::Microseconds: - return m_inNanoseconds / static_cast( s_nanosecondsInAMicrosecond ); - case Unit::Milliseconds: - return m_inNanoseconds / static_cast( s_nanosecondsInAMillisecond ); - case Unit::Seconds: - return m_inNanoseconds / static_cast( s_nanosecondsInASecond ); - case Unit::Minutes: - return m_inNanoseconds / static_cast( s_nanosecondsInAMinute ); - default: - return static_cast( m_inNanoseconds ); - } - } - auto unitsAsString() const -> std::string { - switch( m_units ) { - case Unit::Nanoseconds: - return "ns"; - case Unit::Microseconds: - return "µs"; - case Unit::Milliseconds: - return "ms"; - case Unit::Seconds: - return "s"; - case Unit::Minutes: - return "m"; - default: - return "** internal error **"; - } +class TablePrinter { + std::ostream& m_os; + std::vector m_columnInfos; + std::ostringstream m_oss; + int m_currentColumn = -1; + bool m_isOpen = false; - } - friend auto operator << ( std::ostream& os, Duration const& duration ) -> std::ostream& { - return os << duration.value() << " " << duration.unitsAsString(); - } - }; - } // end anon namespace +public: + TablePrinter( std::ostream& os, std::vector columnInfos ) + : m_os( os ), + m_columnInfos( std::move( columnInfos ) ) {} - struct ConsoleReporter : StreamingReporterBase { - TablePrinter m_tablePrinter; - - ConsoleReporter( ReporterConfig const& config ) - : StreamingReporterBase( config ), - m_tablePrinter( config.stream(), - { - { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH-32, ColumnInfo::Left }, - { "iters", 8, ColumnInfo::Right }, - { "elapsed ns", 14, ColumnInfo::Right }, - { "average", 14, ColumnInfo::Right } - } ) - {} - ~ConsoleReporter() override; - static std::string getDescription() { - return "Reports test results as plain lines of text"; - } + auto columnInfos() const -> std::vector const& { + return m_columnInfos; + } - void noMatchingTestCases( std::string const& spec ) override { - stream << "No test cases matched '" << spec << '\'' << std::endl; + void open() { + if (!m_isOpen) { + m_isOpen = true; + *this << RowBreak(); + for (auto const& info : m_columnInfos) + *this << info.name << ColumnBreak(); + *this << RowBreak(); + m_os << Catch::getLineOfChars<'-'>() << "\n"; } - - void assertionStarting( AssertionInfo const& ) override { + } + void close() { + if (m_isOpen) { + *this << RowBreak(); + m_os << std::endl; + m_isOpen = false; } + } - bool assertionEnded( AssertionStats const& _assertionStats ) override { - AssertionResult const& result = _assertionStats.assertionResult; - - bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); - - // Drop out if result was successful but we're not printing them. - if( !includeResults && result.getResultType() != ResultWas::Warning ) - return false; - - lazyPrint(); + template + friend TablePrinter& operator << (TablePrinter& tp, T const& value) { + tp.m_oss << value; + return tp; + } + + friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) { + auto colStr = tp.m_oss.str(); + // This takes account of utf8 encodings + auto strSize = Catch::StringRef(colStr).numberOfCharacters(); + tp.m_oss.str(""); + tp.open(); + if (tp.m_currentColumn == static_cast(tp.m_columnInfos.size() - 1)) { + tp.m_currentColumn = -1; + tp.m_os << "\n"; + } + tp.m_currentColumn++; + + auto colInfo = tp.m_columnInfos[tp.m_currentColumn]; + auto padding = (strSize + 2 < static_cast(colInfo.width)) + ? std::string(colInfo.width - (strSize + 2), ' ') + : std::string(); + if (colInfo.justification == ColumnInfo::Left) + tp.m_os << colStr << padding << " "; + else + tp.m_os << padding << colStr << " "; + return tp; + } - AssertionPrinter printer( stream, _assertionStats, includeResults ); - printer.print(); - stream << std::endl; - return true; + friend TablePrinter& operator << (TablePrinter& tp, RowBreak) { + if (tp.m_currentColumn > 0) { + tp.m_os << "\n"; + tp.m_currentColumn = -1; } + return tp; + } +}; - void sectionStarting( SectionInfo const& _sectionInfo ) override { - m_headerPrinted = false; - StreamingReporterBase::sectionStarting( _sectionInfo ); - } - void sectionEnded( SectionStats const& _sectionStats ) override { - m_tablePrinter.close(); - if( _sectionStats.missingAssertions ) { - lazyPrint(); - Colour colour( Colour::ResultError ); - if( m_sectionStack.size() > 1 ) - stream << "\nNo assertions in section"; - else - stream << "\nNo assertions in test case"; - stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; - } - if( m_config->showDurations() == ShowDurations::Always ) { - stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; - } - if( m_headerPrinted ) { - m_headerPrinted = false; - } - StreamingReporterBase::sectionEnded( _sectionStats ); - } +ConsoleReporter::ConsoleReporter(ReporterConfig const& config) + : StreamingReporterBase(config), + m_tablePrinter(new TablePrinter(config.stream(), + { + { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left }, + { "iters", 8, ColumnInfo::Right }, + { "elapsed ns", 14, ColumnInfo::Right }, + { "average", 14, ColumnInfo::Right } + })) {} +ConsoleReporter::~ConsoleReporter() = default; + +std::string ConsoleReporter::getDescription() { + return "Reports test results as plain lines of text"; +} - void benchmarkStarting( BenchmarkInfo const& info ) override { - lazyPrintWithoutClosingBenchmarkTable(); +void ConsoleReporter::noMatchingTestCases(std::string const& spec) { + stream << "No test cases matched '" << spec << '\'' << std::endl; +} - auto nameCol = Column( info.name ).width( m_tablePrinter.columnInfos()[0].width-2 ); +void ConsoleReporter::assertionStarting(AssertionInfo const&) {} - bool firstLine = true; - for( auto line : nameCol ) { - if( !firstLine ) - m_tablePrinter << ColumnBreak() << ColumnBreak() << ColumnBreak(); - else - firstLine = false; +bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) { + AssertionResult const& result = _assertionStats.assertionResult; - m_tablePrinter << line << ColumnBreak(); - } - } - void benchmarkEnded( BenchmarkStats const& stats ) override { - Duration average( stats.elapsedTimeInNanoseconds/stats.iterations ); - m_tablePrinter - << stats.iterations << ColumnBreak() - << stats.elapsedTimeInNanoseconds << ColumnBreak() - << average << ColumnBreak(); - } + bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); - void testCaseEnded( TestCaseStats const& _testCaseStats ) override { - m_tablePrinter.close(); - StreamingReporterBase::testCaseEnded( _testCaseStats ); - m_headerPrinted = false; - } - void testGroupEnded( TestGroupStats const& _testGroupStats ) override { - if( currentGroupInfo.used ) { - printSummaryDivider(); - stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; - printTotals( _testGroupStats.totals ); - stream << '\n' << std::endl; - } - StreamingReporterBase::testGroupEnded( _testGroupStats ); - } - void testRunEnded( TestRunStats const& _testRunStats ) override { - printTotalsDivider( _testRunStats.totals ); - printTotals( _testRunStats.totals ); - stream << std::endl; - StreamingReporterBase::testRunEnded( _testRunStats ); - } + // Drop out if result was successful but we're not printing them. + if (!includeResults && result.getResultType() != ResultWas::Warning) + return false; - private: + lazyPrint(); - class AssertionPrinter { - public: - AssertionPrinter& operator= ( AssertionPrinter const& ) = delete; - AssertionPrinter( AssertionPrinter const& ) = delete; - AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) - : stream( _stream ), - stats( _stats ), - result( _stats.assertionResult ), - colour( Colour::None ), - message( result.getMessage() ), - messages( _stats.infoMessages ), - printInfoMessages( _printInfoMessages ) - { - switch( result.getResultType() ) { - case ResultWas::Ok: - colour = Colour::Success; - passOrFail = "PASSED"; - //if( result.hasMessage() ) - if( _stats.infoMessages.size() == 1 ) - messageLabel = "with message"; - if( _stats.infoMessages.size() > 1 ) - messageLabel = "with messages"; - break; - case ResultWas::ExpressionFailed: - if( result.isOk() ) { - colour = Colour::Success; - passOrFail = "FAILED - but was ok"; - } - else { - colour = Colour::Error; - passOrFail = "FAILED"; - } - if( _stats.infoMessages.size() == 1 ) - messageLabel = "with message"; - if( _stats.infoMessages.size() > 1 ) - messageLabel = "with messages"; - break; - case ResultWas::ThrewException: - colour = Colour::Error; - passOrFail = "FAILED"; - messageLabel = "due to unexpected exception with "; - if (_stats.infoMessages.size() == 1) - messageLabel += "message"; - if (_stats.infoMessages.size() > 1) - messageLabel += "messages"; - break; - case ResultWas::FatalErrorCondition: - colour = Colour::Error; - passOrFail = "FAILED"; - messageLabel = "due to a fatal error condition"; - break; - case ResultWas::DidntThrowException: - colour = Colour::Error; - passOrFail = "FAILED"; - messageLabel = "because no exception was thrown where one was expected"; - break; - case ResultWas::Info: - messageLabel = "info"; - break; - case ResultWas::Warning: - messageLabel = "warning"; - break; - case ResultWas::ExplicitFailure: - passOrFail = "FAILED"; - colour = Colour::Error; - if( _stats.infoMessages.size() == 1 ) - messageLabel = "explicitly with message"; - if( _stats.infoMessages.size() > 1 ) - messageLabel = "explicitly with messages"; - break; - // These cases are here to prevent compiler warnings - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - passOrFail = "** internal error **"; - colour = Colour::Error; - break; - } - } + ConsoleAssertionPrinter printer(stream, _assertionStats, includeResults); + printer.print(); + stream << std::endl; + return true; +} - void print() const { - printSourceInfo(); - if( stats.totals.assertions.total() > 0 ) { - if( result.isOk() ) - stream << '\n'; - printResultType(); - printOriginalExpression(); - printReconstructedExpression(); - } - else { - stream << '\n'; - } - printMessage(); - } +void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) { + m_headerPrinted = false; + StreamingReporterBase::sectionStarting(_sectionInfo); +} +void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) { + m_tablePrinter->close(); + if (_sectionStats.missingAssertions) { + lazyPrint(); + Colour colour(Colour::ResultError); + if (m_sectionStack.size() > 1) + stream << "\nNo assertions in section"; + else + stream << "\nNo assertions in test case"; + stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; + } + if (m_config->showDurations() == ShowDurations::Always) { + stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; + } + if (m_headerPrinted) { + m_headerPrinted = false; + } + StreamingReporterBase::sectionEnded(_sectionStats); +} - private: - void printResultType() const { - if( !passOrFail.empty() ) { - Colour colourGuard( colour ); - stream << passOrFail << ":\n"; - } - } - void printOriginalExpression() const { - if( result.hasExpression() ) { - Colour colourGuard( Colour::OriginalExpression ); - stream << " "; - stream << result.getExpressionInMacro(); - stream << '\n'; - } - } - void printReconstructedExpression() const { - if( result.hasExpandedExpression() ) { - stream << "with expansion:\n"; - Colour colourGuard( Colour::ReconstructedExpression ); - stream << Column( result.getExpandedExpression() ).indent(2) << '\n'; - } - } - void printMessage() const { - if( !messageLabel.empty() ) - stream << messageLabel << ':' << '\n'; - for( auto const& msg : messages ) { - // If this assertion is a warning ignore any INFO messages - if( printInfoMessages || msg.type != ResultWas::Info ) - stream << Column( msg.message ).indent(2) << '\n'; - } - } - void printSourceInfo() const { - Colour colourGuard( Colour::FileName ); - stream << result.getSourceInfo() << ": "; - } +void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) { + lazyPrintWithoutClosingBenchmarkTable(); - std::ostream& stream; - AssertionStats const& stats; - AssertionResult const& result; - Colour::Code colour; - std::string passOrFail; - std::string messageLabel; - std::string message; - std::vector messages; - bool printInfoMessages; - }; + auto nameCol = Column( info.name ).width( static_cast( m_tablePrinter->columnInfos()[0].width - 2 ) ); + + bool firstLine = true; + for (auto line : nameCol) { + if (!firstLine) + (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak(); + else + firstLine = false; - void lazyPrint() { + (*m_tablePrinter) << line << ColumnBreak(); + } +} +void ConsoleReporter::benchmarkEnded(BenchmarkStats const& stats) { + Duration average(stats.elapsedTimeInNanoseconds / stats.iterations); + (*m_tablePrinter) + << stats.iterations << ColumnBreak() + << stats.elapsedTimeInNanoseconds << ColumnBreak() + << average << ColumnBreak(); +} - m_tablePrinter.close(); - lazyPrintWithoutClosingBenchmarkTable(); - } +void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) { + m_tablePrinter->close(); + StreamingReporterBase::testCaseEnded(_testCaseStats); + m_headerPrinted = false; +} +void ConsoleReporter::testGroupEnded(TestGroupStats const& _testGroupStats) { + if (currentGroupInfo.used) { + printSummaryDivider(); + stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; + printTotals(_testGroupStats.totals); + stream << '\n' << std::endl; + } + StreamingReporterBase::testGroupEnded(_testGroupStats); +} +void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) { + printTotalsDivider(_testRunStats.totals); + printTotals(_testRunStats.totals); + stream << std::endl; + StreamingReporterBase::testRunEnded(_testRunStats); +} - void lazyPrintWithoutClosingBenchmarkTable() { +void ConsoleReporter::lazyPrint() { - if( !currentTestRunInfo.used ) - lazyPrintRunInfo(); - if( !currentGroupInfo.used ) - lazyPrintGroupInfo(); + m_tablePrinter->close(); + lazyPrintWithoutClosingBenchmarkTable(); +} - if( !m_headerPrinted ) { - printTestCaseAndSectionHeader(); - m_headerPrinted = true; - } - } - void lazyPrintRunInfo() { - stream << '\n' << getLineOfChars<'~'>() << '\n'; - Colour colour( Colour::SecondaryText ); - stream << currentTestRunInfo->name - << " is a Catch v" << libraryVersion() << " host application.\n" - << "Run with -? for options\n\n"; +void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() { - if( m_config->rngSeed() != 0 ) - stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; + if (!currentTestRunInfo.used) + lazyPrintRunInfo(); + if (!currentGroupInfo.used) + lazyPrintGroupInfo(); - currentTestRunInfo.used = true; - } - void lazyPrintGroupInfo() { - if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { - printClosedHeader( "Group: " + currentGroupInfo->name ); - currentGroupInfo.used = true; - } - } - void printTestCaseAndSectionHeader() { - assert( !m_sectionStack.empty() ); - printOpenHeader( currentTestCaseInfo->name ); + if (!m_headerPrinted) { + printTestCaseAndSectionHeader(); + m_headerPrinted = true; + } +} +void ConsoleReporter::lazyPrintRunInfo() { + stream << '\n' << getLineOfChars<'~'>() << '\n'; + Colour colour(Colour::SecondaryText); + stream << currentTestRunInfo->name + << " is a Catch v" << libraryVersion() << " host application.\n" + << "Run with -? for options\n\n"; - if( m_sectionStack.size() > 1 ) { - Colour colourGuard( Colour::Headers ); + if (m_config->rngSeed() != 0) + stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; - auto - it = m_sectionStack.begin()+1, // Skip first section (test case) - itEnd = m_sectionStack.end(); - for( ; it != itEnd; ++it ) - printHeaderString( it->name, 2 ); - } + currentTestRunInfo.used = true; +} +void ConsoleReporter::lazyPrintGroupInfo() { + if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1) { + printClosedHeader("Group: " + currentGroupInfo->name); + currentGroupInfo.used = true; + } +} +void ConsoleReporter::printTestCaseAndSectionHeader() { + assert(!m_sectionStack.empty()); + printOpenHeader(currentTestCaseInfo->name); - SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; + if (m_sectionStack.size() > 1) { + Colour colourGuard(Colour::Headers); - if( !lineInfo.empty() ){ - stream << getLineOfChars<'-'>() << '\n'; - Colour colourGuard( Colour::FileName ); - stream << lineInfo << '\n'; - } - stream << getLineOfChars<'.'>() << '\n' << std::endl; - } + auto + it = m_sectionStack.begin() + 1, // Skip first section (test case) + itEnd = m_sectionStack.end(); + for (; it != itEnd; ++it) + printHeaderString(it->name, 2); + } - void printClosedHeader( std::string const& _name ) { - printOpenHeader( _name ); - stream << getLineOfChars<'.'>() << '\n'; - } - void printOpenHeader( std::string const& _name ) { - stream << getLineOfChars<'-'>() << '\n'; - { - Colour colourGuard( Colour::Headers ); - printHeaderString( _name ); - } - } + SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; - // if string has a : in first line will set indent to follow it on - // subsequent lines - void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { - std::size_t i = _string.find( ": " ); - if( i != std::string::npos ) - i+=2; - else - i = 0; - stream << Column( _string ).indent( indent+i ).initialIndent( indent ) << '\n'; - } + if (!lineInfo.empty()) { + stream << getLineOfChars<'-'>() << '\n'; + Colour colourGuard(Colour::FileName); + stream << lineInfo << '\n'; + } + stream << getLineOfChars<'.'>() << '\n' << std::endl; +} - struct SummaryColumn { +void ConsoleReporter::printClosedHeader(std::string const& _name) { + printOpenHeader(_name); + stream << getLineOfChars<'.'>() << '\n'; +} +void ConsoleReporter::printOpenHeader(std::string const& _name) { + stream << getLineOfChars<'-'>() << '\n'; + { + Colour colourGuard(Colour::Headers); + printHeaderString(_name); + } +} - SummaryColumn( std::string const& _label, Colour::Code _colour ) - : label( _label ), - colour( _colour ) - {} - SummaryColumn addRow( std::size_t count ) { - std::ostringstream oss; - oss << count; - std::string row = oss.str(); - for( auto& oldRow : rows ) { - while( oldRow.size() < row.size() ) - oldRow = ' ' + oldRow; - while( oldRow.size() > row.size() ) - row = ' ' + row; - } - rows.push_back( row ); - return *this; - } +// if string has a : in first line will set indent to follow it on +// subsequent lines +void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) { + std::size_t i = _string.find(": "); + if (i != std::string::npos) + i += 2; + else + i = 0; + stream << Column(_string).indent(indent + i).initialIndent(indent) << '\n'; +} - std::string label; - Colour::Code colour; - std::vector rows; +struct SummaryColumn { + + SummaryColumn( std::string _label, Colour::Code _colour ) + : label( std::move( _label ) ), + colour( _colour ) {} + SummaryColumn addRow( std::size_t count ) { + ReusableStringStream rss; + rss << count; + std::string row = rss.str(); + for (auto& oldRow : rows) { + while (oldRow.size() < row.size()) + oldRow = ' ' + oldRow; + while (oldRow.size() > row.size()) + row = ' ' + row; + } + rows.push_back(row); + return *this; + } - }; + std::string label; + Colour::Code colour; + std::vector rows; - void printTotals( Totals const& totals ) { - if( totals.testCases.total() == 0 ) { - stream << Colour( Colour::Warning ) << "No tests ran\n"; - } - else if( totals.assertions.total() > 0 && totals.testCases.allPassed() ) { - stream << Colour( Colour::ResultSuccess ) << "All tests passed"; - stream << " (" - << pluralise( totals.assertions.passed, "assertion" ) << " in " - << pluralise( totals.testCases.passed, "test case" ) << ')' - << '\n'; - } - else { +}; - std::vector columns; - columns.push_back( SummaryColumn( "", Colour::None ) - .addRow( totals.testCases.total() ) - .addRow( totals.assertions.total() ) ); - columns.push_back( SummaryColumn( "passed", Colour::Success ) - .addRow( totals.testCases.passed ) - .addRow( totals.assertions.passed ) ); - columns.push_back( SummaryColumn( "failed", Colour::ResultError ) - .addRow( totals.testCases.failed ) - .addRow( totals.assertions.failed ) ); - columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) - .addRow( totals.testCases.failedButOk ) - .addRow( totals.assertions.failedButOk ) ); - - printSummaryRow( "test cases", columns, 0 ); - printSummaryRow( "assertions", columns, 1 ); - } - } - void printSummaryRow( std::string const& label, std::vector const& cols, std::size_t row ) { - for( auto col : cols ) { - std::string value = col.rows[row]; - if( col.label.empty() ) { - stream << label << ": "; - if( value != "0" ) - stream << value; - else - stream << Colour( Colour::Warning ) << "- none -"; - } - else if( value != "0" ) { - stream << Colour( Colour::LightGrey ) << " | "; - stream << Colour( col.colour ) - << value << ' ' << col.label; - } - } - stream << '\n'; - } +void ConsoleReporter::printTotals( Totals const& totals ) { + if (totals.testCases.total() == 0) { + stream << Colour(Colour::Warning) << "No tests ran\n"; + } else if (totals.assertions.total() > 0 && totals.testCases.allPassed()) { + stream << Colour(Colour::ResultSuccess) << "All tests passed"; + stream << " (" + << pluralise(totals.assertions.passed, "assertion") << " in " + << pluralise(totals.testCases.passed, "test case") << ')' + << '\n'; + } else { - void printTotalsDivider( Totals const& totals ) { - if( totals.testCases.total() > 0 ) { - std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); - std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); - std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); - while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) - findMax( failedRatio, failedButOkRatio, passedRatio )++; - while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) - findMax( failedRatio, failedButOkRatio, passedRatio )--; - - stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); - stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); - if( totals.testCases.allPassed() ) - stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); - else - stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); - } - else { - stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); - } - stream << '\n'; - } - void printSummaryDivider() { - stream << getLineOfChars<'-'>() << '\n'; + std::vector columns; + columns.push_back(SummaryColumn("", Colour::None) + .addRow(totals.testCases.total()) + .addRow(totals.assertions.total())); + columns.push_back(SummaryColumn("passed", Colour::Success) + .addRow(totals.testCases.passed) + .addRow(totals.assertions.passed)); + columns.push_back(SummaryColumn("failed", Colour::ResultError) + .addRow(totals.testCases.failed) + .addRow(totals.assertions.failed)); + columns.push_back(SummaryColumn("failed as expected", Colour::ResultExpectedFailure) + .addRow(totals.testCases.failedButOk) + .addRow(totals.assertions.failedButOk)); + + printSummaryRow("test cases", columns, 0); + printSummaryRow("assertions", columns, 1); + } +} +void ConsoleReporter::printSummaryRow(std::string const& label, std::vector const& cols, std::size_t row) { + for (auto col : cols) { + std::string value = col.rows[row]; + if (col.label.empty()) { + stream << label << ": "; + if (value != "0") + stream << value; + else + stream << Colour(Colour::Warning) << "- none -"; + } else if (value != "0") { + stream << Colour(Colour::LightGrey) << " | "; + stream << Colour(col.colour) + << value << ' ' << col.label; } + } + stream << '\n'; +} - private: - bool m_headerPrinted = false; - }; - - CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) +void ConsoleReporter::printTotalsDivider(Totals const& totals) { + if (totals.testCases.total() > 0) { + std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total()); + std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total()); + std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total()); + while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1) + findMax(failedRatio, failedButOkRatio, passedRatio)++; + while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1) + findMax(failedRatio, failedButOkRatio, passedRatio)--; + + stream << Colour(Colour::Error) << std::string(failedRatio, '='); + stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '='); + if (totals.testCases.allPassed()) + stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '='); + else + stream << Colour(Colour::Success) << std::string(passedRatio, '='); + } else { + stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '='); + } + stream << '\n'; +} +void ConsoleReporter::printSummaryDivider() { + stream << getLineOfChars<'-'>() << '\n'; +} - ConsoleReporter::~ConsoleReporter() {} +CATCH_REGISTER_REPORTER("console", ConsoleReporter) } // end namespace Catch @@ -11129,8 +13006,8 @@ namespace Catch { // end catch_reporter_console.cpp // start catch_reporter_junit.cpp -#include - +#include +#include #include #include @@ -11171,300 +13048,331 @@ namespace Catch { return it->substr(1); return std::string(); } - } + } // anonymous namespace - class JunitReporter : public CumulativeReporterBase { - public: - JunitReporter( ReporterConfig const& _config ) + JunitReporter::JunitReporter( ReporterConfig const& _config ) : CumulativeReporterBase( _config ), xml( _config.stream() ) { m_reporterPrefs.shouldRedirectStdOut = true; + m_reporterPrefs.shouldReportAllAssertions = true; } - ~JunitReporter() override; + JunitReporter::~JunitReporter() {} - static std::string getDescription() { - return "Reports test results in an XML format that looks like Ant's junitreport target"; - } + std::string JunitReporter::getDescription() { + return "Reports test results in an XML format that looks like Ant's junitreport target"; + } - void noMatchingTestCases( std::string const& /*spec*/ ) override {} + void JunitReporter::noMatchingTestCases( std::string const& /*spec*/ ) {} - void testRunStarting( TestRunInfo const& runInfo ) override { - CumulativeReporterBase::testRunStarting( runInfo ); - xml.startElement( "testsuites" ); - } + void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) { + CumulativeReporterBase::testRunStarting( runInfo ); + xml.startElement( "testsuites" ); + } - void testGroupStarting( GroupInfo const& groupInfo ) override { - suiteTimer.start(); - stdOutForSuite.str(""); - stdErrForSuite.str(""); - unexpectedExceptions = 0; - CumulativeReporterBase::testGroupStarting( groupInfo ); - } + void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) { + suiteTimer.start(); + stdOutForSuite.clear(); + stdErrForSuite.clear(); + unexpectedExceptions = 0; + CumulativeReporterBase::testGroupStarting( groupInfo ); + } - void testCaseStarting( TestCaseInfo const& testCaseInfo ) override { - m_okToFail = testCaseInfo.okToFail(); - } - bool assertionEnded( AssertionStats const& assertionStats ) override { - if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) - unexpectedExceptions++; - return CumulativeReporterBase::assertionEnded( assertionStats ); - } + void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) { + m_okToFail = testCaseInfo.okToFail(); + } - void testCaseEnded( TestCaseStats const& testCaseStats ) override { - stdOutForSuite << testCaseStats.stdOut; - stdErrForSuite << testCaseStats.stdErr; - CumulativeReporterBase::testCaseEnded( testCaseStats ); - } + bool JunitReporter::assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) + unexpectedExceptions++; + return CumulativeReporterBase::assertionEnded( assertionStats ); + } - void testGroupEnded( TestGroupStats const& testGroupStats ) override { - double suiteTime = suiteTimer.getElapsedSeconds(); - CumulativeReporterBase::testGroupEnded( testGroupStats ); - writeGroup( *m_testGroups.back(), suiteTime ); - } + void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { + stdOutForSuite += testCaseStats.stdOut; + stdErrForSuite += testCaseStats.stdErr; + CumulativeReporterBase::testCaseEnded( testCaseStats ); + } - void testRunEndedCumulative() override { - xml.endElement(); - } + void JunitReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { + double suiteTime = suiteTimer.getElapsedSeconds(); + CumulativeReporterBase::testGroupEnded( testGroupStats ); + writeGroup( *m_testGroups.back(), suiteTime ); + } - void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { - XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); - TestGroupStats const& stats = groupNode.value; - xml.writeAttribute( "name", stats.groupInfo.name ); - xml.writeAttribute( "errors", unexpectedExceptions ); - xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); - xml.writeAttribute( "tests", stats.totals.assertions.total() ); - xml.writeAttribute( "hostname", "tbd" ); // !TBD - if( m_config->showDurations() == ShowDurations::Never ) - xml.writeAttribute( "time", "" ); - else - xml.writeAttribute( "time", suiteTime ); - xml.writeAttribute( "timestamp", getCurrentTimestamp() ); + void JunitReporter::testRunEndedCumulative() { + xml.endElement(); + } + + void JunitReporter::writeGroup( TestGroupNode const& groupNode, double suiteTime ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); + TestGroupStats const& stats = groupNode.value; + xml.writeAttribute( "name", stats.groupInfo.name ); + xml.writeAttribute( "errors", unexpectedExceptions ); + xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); + xml.writeAttribute( "tests", stats.totals.assertions.total() ); + xml.writeAttribute( "hostname", "tbd" ); // !TBD + if( m_config->showDurations() == ShowDurations::Never ) + xml.writeAttribute( "time", "" ); + else + xml.writeAttribute( "time", suiteTime ); + xml.writeAttribute( "timestamp", getCurrentTimestamp() ); + + // Write test cases + for( auto const& child : groupNode.children ) + writeTestCase( *child ); + + xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), false ); + xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), false ); + } + + void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) { + TestCaseStats const& stats = testCaseNode.value; - // Write test cases - for( auto const& child : groupNode.children ) - writeTestCase( *child ); + // All test cases have exactly one section - which represents the + // test case itself. That section may have 0-n nested sections + assert( testCaseNode.children.size() == 1 ); + SectionNode const& rootSection = *testCaseNode.children.front(); - xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); - xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); + std::string className = stats.testInfo.className; + + if( className.empty() ) { + className = fileNameTag(stats.testInfo.tags); + if ( className.empty() ) + className = "global"; } - void writeTestCase( TestCaseNode const& testCaseNode ) { - TestCaseStats const& stats = testCaseNode.value; + if ( !m_config->name().empty() ) + className = m_config->name() + "." + className; - // All test cases have exactly one section - which represents the - // test case itself. That section may have 0-n nested sections - assert( testCaseNode.children.size() == 1 ); - SectionNode const& rootSection = *testCaseNode.children.front(); + writeSection( className, "", rootSection ); + } - std::string className = stats.testInfo.className; + void JunitReporter::writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode ) { + std::string name = trim( sectionNode.stats.sectionInfo.name ); + if( !rootName.empty() ) + name = rootName + '/' + name; + if( !sectionNode.assertions.empty() || + !sectionNode.stdOut.empty() || + !sectionNode.stdErr.empty() ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); if( className.empty() ) { - className = fileNameTag(stats.testInfo.tags); - if ( className.empty() ) - className = "global"; + xml.writeAttribute( "classname", name ); + xml.writeAttribute( "name", "root" ); } + else { + xml.writeAttribute( "classname", className ); + xml.writeAttribute( "name", name ); + } + xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) ); - if ( !m_config->name().empty() ) - className = m_config->name() + "." + className; + writeAssertions( sectionNode ); - writeSection( className, "", rootSection ); + if( !sectionNode.stdOut.empty() ) + xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); + if( !sectionNode.stdErr.empty() ) + xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); } + for( auto const& childNode : sectionNode.childSections ) + if( className.empty() ) + writeSection( name, "", *childNode ); + else + writeSection( className, name, *childNode ); + } - void writeSection( std::string const& className, - std::string const& rootName, - SectionNode const& sectionNode ) { - std::string name = trim( sectionNode.stats.sectionInfo.name ); - if( !rootName.empty() ) - name = rootName + '/' + name; - - if( !sectionNode.assertions.empty() || - !sectionNode.stdOut.empty() || - !sectionNode.stdErr.empty() ) { - XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); - if( className.empty() ) { - xml.writeAttribute( "classname", name ); - xml.writeAttribute( "name", "root" ); - } - else { - xml.writeAttribute( "classname", className ); - xml.writeAttribute( "name", name ); - } - xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) ); + void JunitReporter::writeAssertions( SectionNode const& sectionNode ) { + for( auto const& assertion : sectionNode.assertions ) + writeAssertion( assertion ); + } - writeAssertions( sectionNode ); + void JunitReporter::writeAssertion( AssertionStats const& stats ) { + AssertionResult const& result = stats.assertionResult; + if( !result.isOk() ) { + std::string elementName; + switch( result.getResultType() ) { + case ResultWas::ThrewException: + case ResultWas::FatalErrorCondition: + elementName = "error"; + break; + case ResultWas::ExplicitFailure: + elementName = "failure"; + break; + case ResultWas::ExpressionFailed: + elementName = "failure"; + break; + case ResultWas::DidntThrowException: + elementName = "failure"; + break; - if( !sectionNode.stdOut.empty() ) - xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); - if( !sectionNode.stdErr.empty() ) - xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); + // We should never see these here: + case ResultWas::Info: + case ResultWas::Warning: + case ResultWas::Ok: + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + elementName = "internalError"; + break; } - for( auto const& childNode : sectionNode.childSections ) - if( className.empty() ) - writeSection( name, "", *childNode ); - else - writeSection( className, name, *childNode ); - } - - void writeAssertions( SectionNode const& sectionNode ) { - for( auto const& assertion : sectionNode.assertions ) - writeAssertion( assertion ); - } - void writeAssertion( AssertionStats const& stats ) { - AssertionResult const& result = stats.assertionResult; - if( !result.isOk() ) { - std::string elementName; - switch( result.getResultType() ) { - case ResultWas::ThrewException: - case ResultWas::FatalErrorCondition: - elementName = "error"; - break; - case ResultWas::ExplicitFailure: - elementName = "failure"; - break; - case ResultWas::ExpressionFailed: - elementName = "failure"; - break; - case ResultWas::DidntThrowException: - elementName = "failure"; - break; - - // We should never see these here: - case ResultWas::Info: - case ResultWas::Warning: - case ResultWas::Ok: - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - elementName = "internalError"; - break; - } - XmlWriter::ScopedElement e = xml.scopedElement( elementName ); + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); - xml.writeAttribute( "message", result.getExpandedExpression() ); - xml.writeAttribute( "type", result.getTestMacroName() ); + xml.writeAttribute( "message", result.getExpandedExpression() ); + xml.writeAttribute( "type", result.getTestMacroName() ); - std::ostringstream oss; - if( !result.getMessage().empty() ) - oss << result.getMessage() << '\n'; - for( auto const& msg : stats.infoMessages ) - if( msg.type == ResultWas::Info ) - oss << msg.message << '\n'; + ReusableStringStream rss; + if( !result.getMessage().empty() ) + rss << result.getMessage() << '\n'; + for( auto const& msg : stats.infoMessages ) + if( msg.type == ResultWas::Info ) + rss << msg.message << '\n'; - oss << "at " << result.getSourceInfo(); - xml.writeText( oss.str(), false ); - } + rss << "at " << result.getSourceInfo(); + xml.writeText( rss.str(), false ); } + } - XmlWriter xml; - Timer suiteTimer; - std::ostringstream stdOutForSuite; - std::ostringstream stdErrForSuite; - unsigned int unexpectedExceptions = 0; - bool m_okToFail = false; - }; - - JunitReporter::~JunitReporter() {} CATCH_REGISTER_REPORTER( "junit", JunitReporter ) } // end namespace Catch // end catch_reporter_junit.cpp -// start catch_reporter_multi.cpp +// start catch_reporter_listening.cpp + +#include namespace Catch { - void MultipleReporters::add( IStreamingReporterPtr&& reporter ) { - m_reporters.push_back( std::move( reporter ) ); + ListeningReporter::ListeningReporter() { + // We will assume that listeners will always want all assertions + m_preferences.shouldReportAllAssertions = true; + } + + void ListeningReporter::addListener( IStreamingReporterPtr&& listener ) { + m_listeners.push_back( std::move( listener ) ); + } + + void ListeningReporter::addReporter(IStreamingReporterPtr&& reporter) { + assert(!m_reporter && "Listening reporter can wrap only 1 real reporter"); + m_reporter = std::move( reporter ); + m_preferences.shouldRedirectStdOut = m_reporter->getPreferences().shouldRedirectStdOut; } - ReporterPreferences MultipleReporters::getPreferences() const { - return m_reporters[0]->getPreferences(); + ReporterPreferences ListeningReporter::getPreferences() const { + return m_preferences; } - std::set MultipleReporters::getSupportedVerbosities() { + std::set ListeningReporter::getSupportedVerbosities() { return std::set{ }; } - void MultipleReporters::noMatchingTestCases( std::string const& spec ) { - for( auto const& reporter : m_reporters ) - reporter->noMatchingTestCases( spec ); + void ListeningReporter::noMatchingTestCases( std::string const& spec ) { + for ( auto const& listener : m_listeners ) { + listener->noMatchingTestCases( spec ); + } + m_reporter->noMatchingTestCases( spec ); } - void MultipleReporters::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) { - for( auto const& reporter : m_reporters ) - reporter->benchmarkStarting( benchmarkInfo ); + void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) { + for ( auto const& listener : m_listeners ) { + listener->benchmarkStarting( benchmarkInfo ); + } + m_reporter->benchmarkStarting( benchmarkInfo ); } - void MultipleReporters::benchmarkEnded( BenchmarkStats const& benchmarkStats ) { - for( auto const& reporter : m_reporters ) - reporter->benchmarkEnded( benchmarkStats ); + void ListeningReporter::benchmarkEnded( BenchmarkStats const& benchmarkStats ) { + for ( auto const& listener : m_listeners ) { + listener->benchmarkEnded( benchmarkStats ); + } + m_reporter->benchmarkEnded( benchmarkStats ); } - void MultipleReporters::testRunStarting( TestRunInfo const& testRunInfo ) { - for( auto const& reporter : m_reporters ) - reporter->testRunStarting( testRunInfo ); + void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) { + for ( auto const& listener : m_listeners ) { + listener->testRunStarting( testRunInfo ); + } + m_reporter->testRunStarting( testRunInfo ); } - void MultipleReporters::testGroupStarting( GroupInfo const& groupInfo ) { - for( auto const& reporter : m_reporters ) - reporter->testGroupStarting( groupInfo ); + void ListeningReporter::testGroupStarting( GroupInfo const& groupInfo ) { + for ( auto const& listener : m_listeners ) { + listener->testGroupStarting( groupInfo ); + } + m_reporter->testGroupStarting( groupInfo ); } - void MultipleReporters::testCaseStarting( TestCaseInfo const& testInfo ) { - for( auto const& reporter : m_reporters ) - reporter->testCaseStarting( testInfo ); + void ListeningReporter::testCaseStarting( TestCaseInfo const& testInfo ) { + for ( auto const& listener : m_listeners ) { + listener->testCaseStarting( testInfo ); + } + m_reporter->testCaseStarting( testInfo ); } - void MultipleReporters::sectionStarting( SectionInfo const& sectionInfo ) { - for( auto const& reporter : m_reporters ) - reporter->sectionStarting( sectionInfo ); + void ListeningReporter::sectionStarting( SectionInfo const& sectionInfo ) { + for ( auto const& listener : m_listeners ) { + listener->sectionStarting( sectionInfo ); + } + m_reporter->sectionStarting( sectionInfo ); } - void MultipleReporters::assertionStarting( AssertionInfo const& assertionInfo ) { - for( auto const& reporter : m_reporters ) - reporter->assertionStarting( assertionInfo ); + void ListeningReporter::assertionStarting( AssertionInfo const& assertionInfo ) { + for ( auto const& listener : m_listeners ) { + listener->assertionStarting( assertionInfo ); + } + m_reporter->assertionStarting( assertionInfo ); } // The return value indicates if the messages buffer should be cleared: - bool MultipleReporters::assertionEnded( AssertionStats const& assertionStats ) { - bool clearBuffer = false; - for( auto const& reporter : m_reporters ) - clearBuffer |= reporter->assertionEnded( assertionStats ); - return clearBuffer; + bool ListeningReporter::assertionEnded( AssertionStats const& assertionStats ) { + for( auto const& listener : m_listeners ) { + static_cast( listener->assertionEnded( assertionStats ) ); + } + return m_reporter->assertionEnded( assertionStats ); } - void MultipleReporters::sectionEnded( SectionStats const& sectionStats ) { - for( auto const& reporter : m_reporters ) - reporter->sectionEnded( sectionStats ); + void ListeningReporter::sectionEnded( SectionStats const& sectionStats ) { + for ( auto const& listener : m_listeners ) { + listener->sectionEnded( sectionStats ); + } + m_reporter->sectionEnded( sectionStats ); } - void MultipleReporters::testCaseEnded( TestCaseStats const& testCaseStats ) { - for( auto const& reporter : m_reporters ) - reporter->testCaseEnded( testCaseStats ); + void ListeningReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { + for ( auto const& listener : m_listeners ) { + listener->testCaseEnded( testCaseStats ); + } + m_reporter->testCaseEnded( testCaseStats ); } - void MultipleReporters::testGroupEnded( TestGroupStats const& testGroupStats ) { - for( auto const& reporter : m_reporters ) - reporter->testGroupEnded( testGroupStats ); + void ListeningReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { + for ( auto const& listener : m_listeners ) { + listener->testGroupEnded( testGroupStats ); + } + m_reporter->testGroupEnded( testGroupStats ); } - void MultipleReporters::testRunEnded( TestRunStats const& testRunStats ) { - for( auto const& reporter : m_reporters ) - reporter->testRunEnded( testRunStats ); + void ListeningReporter::testRunEnded( TestRunStats const& testRunStats ) { + for ( auto const& listener : m_listeners ) { + listener->testRunEnded( testRunStats ); + } + m_reporter->testRunEnded( testRunStats ); } - void MultipleReporters::skipTest( TestCaseInfo const& testInfo ) { - for( auto const& reporter : m_reporters ) - reporter->skipTest( testInfo ); + void ListeningReporter::skipTest( TestCaseInfo const& testInfo ) { + for ( auto const& listener : m_listeners ) { + listener->skipTest( testInfo ); + } + m_reporter->skipTest( testInfo ); } - bool MultipleReporters::isMulti() const { + bool ListeningReporter::isMulti() const { return true; } } // end namespace Catch -// end catch_reporter_multi.cpp +// end catch_reporter_listening.cpp // start catch_reporter_xml.cpp #if defined(_MSC_VER) @@ -11475,211 +13383,200 @@ namespace Catch { #endif namespace Catch { - class XmlReporter : public StreamingReporterBase { - public: - XmlReporter( ReporterConfig const& _config ) - : StreamingReporterBase( _config ), - m_xml(_config.stream()) - { - m_reporterPrefs.shouldRedirectStdOut = true; - } + XmlReporter::XmlReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_xml(_config.stream()) + { + m_reporterPrefs.shouldRedirectStdOut = true; + m_reporterPrefs.shouldReportAllAssertions = true; + } - ~XmlReporter() override; + XmlReporter::~XmlReporter() = default; - static std::string getDescription() { - return "Reports test results as an XML document"; - } + std::string XmlReporter::getDescription() { + return "Reports test results as an XML document"; + } - virtual std::string getStylesheetRef() const { - return std::string(); - } + std::string XmlReporter::getStylesheetRef() const { + return std::string(); + } - void writeSourceInfo( SourceLineInfo const& sourceInfo ) { - m_xml - .writeAttribute( "filename", sourceInfo.file ) - .writeAttribute( "line", sourceInfo.line ); - } + void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) { + m_xml + .writeAttribute( "filename", sourceInfo.file ) + .writeAttribute( "line", sourceInfo.line ); + } - public: // StreamingReporterBase + void XmlReporter::noMatchingTestCases( std::string const& s ) { + StreamingReporterBase::noMatchingTestCases( s ); + } - void noMatchingTestCases( std::string const& s ) override { - StreamingReporterBase::noMatchingTestCases( s ); - } + void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) { + StreamingReporterBase::testRunStarting( testInfo ); + std::string stylesheetRef = getStylesheetRef(); + if( !stylesheetRef.empty() ) + m_xml.writeStylesheetRef( stylesheetRef ); + m_xml.startElement( "Catch" ); + if( !m_config->name().empty() ) + m_xml.writeAttribute( "name", m_config->name() ); + } - void testRunStarting( TestRunInfo const& testInfo ) override { - StreamingReporterBase::testRunStarting( testInfo ); - std::string stylesheetRef = getStylesheetRef(); - if( !stylesheetRef.empty() ) - m_xml.writeStylesheetRef( stylesheetRef ); - m_xml.startElement( "Catch" ); - if( !m_config->name().empty() ) - m_xml.writeAttribute( "name", m_config->name() ); - } + void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) { + StreamingReporterBase::testGroupStarting( groupInfo ); + m_xml.startElement( "Group" ) + .writeAttribute( "name", groupInfo.name ); + } - void testGroupStarting( GroupInfo const& groupInfo ) override { - StreamingReporterBase::testGroupStarting( groupInfo ); - m_xml.startElement( "Group" ) - .writeAttribute( "name", groupInfo.name ); - } + void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) { + StreamingReporterBase::testCaseStarting(testInfo); + m_xml.startElement( "TestCase" ) + .writeAttribute( "name", trim( testInfo.name ) ) + .writeAttribute( "description", testInfo.description ) + .writeAttribute( "tags", testInfo.tagsAsString() ); - void testCaseStarting( TestCaseInfo const& testInfo ) override { - StreamingReporterBase::testCaseStarting(testInfo); - m_xml.startElement( "TestCase" ) - .writeAttribute( "name", trim( testInfo.name ) ) - .writeAttribute( "description", testInfo.description ) - .writeAttribute( "tags", testInfo.tagsAsString() ); + writeSourceInfo( testInfo.lineInfo ); - writeSourceInfo( testInfo.lineInfo ); + if ( m_config->showDurations() == ShowDurations::Always ) + m_testCaseTimer.start(); + m_xml.ensureTagClosed(); + } - if ( m_config->showDurations() == ShowDurations::Always ) - m_testCaseTimer.start(); + void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) { + StreamingReporterBase::sectionStarting( sectionInfo ); + if( m_sectionDepth++ > 0 ) { + m_xml.startElement( "Section" ) + .writeAttribute( "name", trim( sectionInfo.name ) ); + writeSourceInfo( sectionInfo.lineInfo ); m_xml.ensureTagClosed(); } + } - void sectionStarting( SectionInfo const& sectionInfo ) override { - StreamingReporterBase::sectionStarting( sectionInfo ); - if( m_sectionDepth++ > 0 ) { - m_xml.startElement( "Section" ) - .writeAttribute( "name", trim( sectionInfo.name ) ) - .writeAttribute( "description", sectionInfo.description ); - writeSourceInfo( sectionInfo.lineInfo ); - m_xml.ensureTagClosed(); - } - } - - void assertionStarting( AssertionInfo const& ) override { } + void XmlReporter::assertionStarting( AssertionInfo const& ) { } - bool assertionEnded( AssertionStats const& assertionStats ) override { + bool XmlReporter::assertionEnded( AssertionStats const& assertionStats ) { - AssertionResult const& result = assertionStats.assertionResult; + AssertionResult const& result = assertionStats.assertionResult; - bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); + bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); - if( includeResults ) { - // Print any info messages in tags. - for( auto const& msg : assertionStats.infoMessages ) { - if( msg.type == ResultWas::Info ) { - m_xml.scopedElement( "Info" ) - .writeText( msg.message ); - } else if ( msg.type == ResultWas::Warning ) { - m_xml.scopedElement( "Warning" ) - .writeText( msg.message ); - } + if( includeResults || result.getResultType() == ResultWas::Warning ) { + // Print any info messages in tags. + for( auto const& msg : assertionStats.infoMessages ) { + if( msg.type == ResultWas::Info && includeResults ) { + m_xml.scopedElement( "Info" ) + .writeText( msg.message ); + } else if ( msg.type == ResultWas::Warning ) { + m_xml.scopedElement( "Warning" ) + .writeText( msg.message ); } } + } - // Drop out if result was successful but we're not printing them. - if( !includeResults && result.getResultType() != ResultWas::Warning ) - return true; - - // Print the expression if there is one. - if( result.hasExpression() ) { - m_xml.startElement( "Expression" ) - .writeAttribute( "success", result.succeeded() ) - .writeAttribute( "type", result.getTestMacroName() ); + // Drop out if result was successful but we're not printing them. + if( !includeResults && result.getResultType() != ResultWas::Warning ) + return true; - writeSourceInfo( result.getSourceInfo() ); + // Print the expression if there is one. + if( result.hasExpression() ) { + m_xml.startElement( "Expression" ) + .writeAttribute( "success", result.succeeded() ) + .writeAttribute( "type", result.getTestMacroName() ); - m_xml.scopedElement( "Original" ) - .writeText( result.getExpression() ); - m_xml.scopedElement( "Expanded" ) - .writeText( result.getExpandedExpression() ); - } + writeSourceInfo( result.getSourceInfo() ); - // And... Print a result applicable to each result type. - switch( result.getResultType() ) { - case ResultWas::ThrewException: - m_xml.startElement( "Exception" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - case ResultWas::FatalErrorCondition: - m_xml.startElement( "FatalErrorCondition" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - case ResultWas::Info: - m_xml.scopedElement( "Info" ) - .writeText( result.getMessage() ); - break; - case ResultWas::Warning: - // Warning will already have been written - break; - case ResultWas::ExplicitFailure: - m_xml.startElement( "Failure" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - default: - break; - } + m_xml.scopedElement( "Original" ) + .writeText( result.getExpression() ); + m_xml.scopedElement( "Expanded" ) + .writeText( result.getExpandedExpression() ); + } - if( result.hasExpression() ) + // And... Print a result applicable to each result type. + switch( result.getResultType() ) { + case ResultWas::ThrewException: + m_xml.startElement( "Exception" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); m_xml.endElement(); - - return true; + break; + case ResultWas::FatalErrorCondition: + m_xml.startElement( "FatalErrorCondition" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); + break; + case ResultWas::Info: + m_xml.scopedElement( "Info" ) + .writeText( result.getMessage() ); + break; + case ResultWas::Warning: + // Warning will already have been written + break; + case ResultWas::ExplicitFailure: + m_xml.startElement( "Failure" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); + break; + default: + break; } - void sectionEnded( SectionStats const& sectionStats ) override { - StreamingReporterBase::sectionEnded( sectionStats ); - if( --m_sectionDepth > 0 ) { - XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); - e.writeAttribute( "successes", sectionStats.assertions.passed ); - e.writeAttribute( "failures", sectionStats.assertions.failed ); - e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); - - if ( m_config->showDurations() == ShowDurations::Always ) - e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); + if( result.hasExpression() ) + m_xml.endElement(); - m_xml.endElement(); - } - } + return true; + } - void testCaseEnded( TestCaseStats const& testCaseStats ) override { - StreamingReporterBase::testCaseEnded( testCaseStats ); - XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); - e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); + void XmlReporter::sectionEnded( SectionStats const& sectionStats ) { + StreamingReporterBase::sectionEnded( sectionStats ); + if( --m_sectionDepth > 0 ) { + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); + e.writeAttribute( "successes", sectionStats.assertions.passed ); + e.writeAttribute( "failures", sectionStats.assertions.failed ); + e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); if ( m_config->showDurations() == ShowDurations::Always ) - e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); - - if( !testCaseStats.stdOut.empty() ) - m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false ); - if( !testCaseStats.stdErr.empty() ) - m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false ); + e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); m_xml.endElement(); } + } - void testGroupEnded( TestGroupStats const& testGroupStats ) override { - StreamingReporterBase::testGroupEnded( testGroupStats ); - // TODO: Check testGroupStats.aborting and act accordingly. - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) - .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) - .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); - m_xml.endElement(); - } + void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { + StreamingReporterBase::testCaseEnded( testCaseStats ); + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); + e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); - void testRunEnded( TestRunStats const& testRunStats ) override { - StreamingReporterBase::testRunEnded( testRunStats ); - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", testRunStats.totals.assertions.passed ) - .writeAttribute( "failures", testRunStats.totals.assertions.failed ) - .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); - m_xml.endElement(); - } + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); - private: - Timer m_testCaseTimer; - XmlWriter m_xml; - int m_sectionDepth = 0; - }; + if( !testCaseStats.stdOut.empty() ) + m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false ); + if( !testCaseStats.stdErr.empty() ) + m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false ); + + m_xml.endElement(); + } + + void XmlReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { + StreamingReporterBase::testGroupEnded( testGroupStats ); + // TODO: Check testGroupStats.aborting and act accordingly. + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) + .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) { + StreamingReporterBase::testRunEnded( testRunStats ); + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testRunStats.totals.assertions.passed ) + .writeAttribute( "failures", testRunStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } - XmlReporter::~XmlReporter() {} CATCH_REGISTER_REPORTER( "xml", XmlReporter ) } // end namespace Catch @@ -11705,7 +13602,7 @@ namespace Catch { #ifndef __OBJC__ -#if defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) +#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) // Standard C/C++ Win32 Unicode wmain entry point extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { #else @@ -11739,6 +13636,8 @@ int main (int argc, char * const argv[]) { // end catch_default_main.hpp #endif +#if !defined(CATCH_CONFIG_IMPL_ONLY) + #ifdef CLARA_CONFIG_MAIN_NOT_DEFINED # undef CLARA_CONFIG_MAIN #endif @@ -11781,13 +13680,14 @@ int main (int argc, char * const argv[]) { #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) -#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) ) +#define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE",__VA_ARGS__ ) #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) +#define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) @@ -11797,11 +13697,12 @@ int main (int argc, char * const argv[]) { // "BDD-style" convenience wrappers #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) -#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc ) -#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc ) -#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc ) -#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc ) -#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc ) +#define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) +#define CATCH_AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc ) +#define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc ) +#define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc ) +#define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) +#define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else @@ -11839,13 +13740,14 @@ int main (int argc, char * const argv[]) { #define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) #define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) -#define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) ) +#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE",__VA_ARGS__ ) #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) +#define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) #define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) @@ -11859,15 +13761,17 @@ int main (int argc, char * const argv[]) { #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) -#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc ) -#define WHEN( desc ) SECTION( std::string(" When: ") + desc ) -#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc ) -#define THEN( desc ) SECTION( std::string(" Then: ") + desc ) -#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc ) +#define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) +#define AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc ) +#define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc ) +#define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc ) +#define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) +#define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) using Catch::Detail::Approx; -#else +#else // CATCH_CONFIG_DISABLE + ////// // If this config identifier is defined then all CATCH macros are prefixed with CATCH_ #ifdef CATCH_CONFIG_PREFIX_ALL @@ -11912,6 +13816,7 @@ using Catch::Detail::Approx; #define CATCH_METHOD_AS_TEST_CASE( method, ... ) #define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0) #define CATCH_SECTION( ... ) +#define CATCH_DYNAMIC_SECTION( ... ) #define CATCH_FAIL( ... ) (void)(0) #define CATCH_FAIL_CHECK( ... ) (void)(0) #define CATCH_SUCCEED( ... ) (void)(0) @@ -11922,6 +13827,7 @@ using Catch::Detail::Approx; #define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) #define CATCH_GIVEN( desc ) +#define CATCH_AND_GIVEN( desc ) #define CATCH_WHEN( desc ) #define CATCH_AND_WHEN( desc ) #define CATCH_THEN( desc ) @@ -11970,6 +13876,7 @@ using Catch::Detail::Approx; #define METHOD_AS_TEST_CASE( method, ... ) #define REGISTER_TEST_CASE( Function, ... ) (void)(0) #define SECTION( ... ) +#define DYNAMIC_SECTION( ... ) #define FAIL( ... ) (void)(0) #define FAIL_CHECK( ... ) (void)(0) #define SUCCEED( ... ) (void)(0) @@ -11984,6 +13891,7 @@ using Catch::Detail::Approx; #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) #define GIVEN( desc ) +#define AND_GIVEN( desc ) #define WHEN( desc ) #define AND_WHEN( desc ) #define THEN( desc ) @@ -11993,6 +13901,8 @@ using Catch::Detail::Approx; #endif +#endif // ! CATCH_CONFIG_IMPL_ONLY + // start catch_reenable_warnings.h From 0d9e385aa088637f3ff6c916f69cbbc7c4813e74 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Tue, 4 Sep 2018 14:22:00 -0600 Subject: [PATCH 180/184] Improve vector eraser tool The distance to points was being calculated incorrectly since the dot product produces the *square* of the eulerian distance. There were also differences in how the vector eraser width was being calculate compared to the bitmap tools (particularly, it takes into consideration the scaling, which we removed I think) --- core_lib/src/graphics/vector/vectorimage.cpp | 3 +++ core_lib/src/tool/erasertool.cpp | 17 ++++++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/core_lib/src/graphics/vector/vectorimage.cpp b/core_lib/src/graphics/vector/vectorimage.cpp index cf2d36744..a66648d5c 100644 --- a/core_lib/src/graphics/vector/vectorimage.cpp +++ b/core_lib/src/graphics/vector/vectorimage.cpp @@ -1407,6 +1407,9 @@ QList VectorImage::getVerticesCloseTo(QPointF P1, qreal maxDistance) { QList result; + // Square maxDistance rather than taking the square root for each distance + maxDistance *= maxDistance; + for (int curve = 0; curve < mCurves.size(); curve++) { for (int vertex = -1; vertex < mCurves.at(curve).getVertexSize(); vertex++) diff --git a/core_lib/src/tool/erasertool.cpp b/core_lib/src/tool/erasertool.cpp index 755f5d8f5..f968d776c 100644 --- a/core_lib/src/tool/erasertool.cpp +++ b/core_lib/src/tool/erasertool.cpp @@ -229,7 +229,7 @@ void EraserTool::drawStroke() qreal opacity = 1.0; mCurrentWidth = properties.width; - if (properties.pressure == true) + if (properties.pressure) { opacity = m_pStrokeManager->getPressure(); mCurrentWidth = (mCurrentWidth + ( m_pStrokeManager->getPressure() * mCurrentWidth)) * 0.5; @@ -274,16 +274,15 @@ void EraserTool::drawStroke() } else if ( layer->type() == Layer::VECTOR ) { - qreal brushWidth = 0; - if (properties.pressure ) { - brushWidth = properties.width * m_pStrokeManager->getPressure(); - } - else { - brushWidth = properties.width; + mCurrentWidth = properties.width; + if (properties.pressure) + { + mCurrentWidth = (mCurrentWidth + ( m_pStrokeManager->getPressure() * mCurrentWidth)) * 0.5; } + qreal brushWidth = mCurrentWidth; QPen pen( Qt::white, brushWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin ); - int rad = qRound( ( brushWidth / 2 + 2 ) * mEditor->view()->scaling() ); + int rad = qRound(brushWidth) / 2 + 2; if ( p.size() == 4 ) { @@ -331,7 +330,7 @@ void EraserTool::updateStrokes() if ( layer->type() == Layer::VECTOR ) { - qreal radius = ( properties.width / 2 ) / mEditor->view()->scaling(); + qreal radius = properties.width / 2; QList nearbyVertices = ( ( LayerVector * )layer )->getLastVectorImageAtFrame( mEditor->currentFrame(), 0 ) ->getVerticesCloseTo( getCurrentPoint(), radius ); for ( int i = 0; i < nearbyVertices.size(); i++ ) From 6d05e09af891ef46006aeca4c67c887c03898bd9 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Thu, 6 Sep 2018 23:04:24 -0600 Subject: [PATCH 181/184] Refactor assembleAudio to use ffmpeg This gets rid of all that ugly custom code for handling wavs, fixes issues when the audio starts outside of the export range, probably improves audio syncing, and is way faster. --- core_lib/src/movieexporter.cpp | 162 +++++---------------------------- 1 file changed, 25 insertions(+), 137 deletions(-) diff --git a/core_lib/src/movieexporter.cpp b/core_lib/src/movieexporter.cpp index d6def65d1..2e4c26e11 100644 --- a/core_lib/src/movieexporter.cpp +++ b/core_lib/src/movieexporter.cpp @@ -31,75 +31,6 @@ GNU General Public License for more details. #include "layersound.h" #include "soundclip.h" -// refs -// http://www.topherlee.com/software/pcm-tut-wavformat.html -// http://soundfile.sapp.org/doc/WaveFormat/ -// -struct WavFileHeader -{ - char riff[4]; - int32_t chuckSize; - char format[4]; - char fmtID[4]; - int32_t fmtChuckSize; - int16_t audioFormat; - int16_t numChannels; - int32_t sampleRate; - int32_t byteRate; - int16_t blockAlign; - int16_t bitsPerSample; - char dataChuckID[4]; - int32_t dataSize; - - void InitWithDefaultValues() - { - strncpy(riff, "RIFF", 4); - chuckSize = 0; - strncpy(format, "WAVE", 4); - strncpy(fmtID, "fmt ", 4); - fmtChuckSize = 16; - audioFormat = 1; // 1 means PCM - numChannels = 2; // stereo - sampleRate = 44100; - bitsPerSample = 16; - blockAlign = (bitsPerSample * numChannels) / 8; - byteRate = (sampleRate * bitsPerSample * numChannels) / 8; - - strncpy(dataChuckID, "data", 4); - dataSize = 0; - } -}; - -int16_t safeSumInt16(int16_t a, int16_t b) -{ - int32_t a32 = static_cast(a); - int32_t b32 = static_cast(b); - - if ((a32 + b32) > INT16_MAX) - { - return INT16_MAX; - } - else if ((a32 + b32) < INT16_MIN) - { - return INT16_MIN; - } - return a + b; -} - -void skipUselessChucks(WavFileHeader& header, QFile& file) -{ - // We only care about the 'data' chuck - while (memcmp(header.dataChuckID, "data", 4) != 0) - { - int skipByteCount = header.dataSize; - std::vector skipData(skipByteCount); - file.read(skipData.data(), skipByteCount); - - file.read((char*)&header.dataChuckID, 4); - file.read((char*)&header.dataSize, 4); - } -} - QString ffmpegLocation() { #ifdef _WIN32 @@ -251,15 +182,6 @@ Status MovieExporter::assembleAudio(const Object* obj, Q_ASSERT(startFrame >= 0); Q_ASSERT(endFrame >= startFrame); - float lengthInSec = (endFrame - startFrame + 1) / (float)fps; - qDebug() << "Audio Length = " << lengthInSec << " seconds"; - - int32_t audioDataSize = 44100 * 2 * 2 * lengthInSec; - - std::vector audioData(audioDataSize / sizeof(int16_t)); - - bool audioDataValid = false; - QDir dir(mTempWorkDir); Q_ASSERT(dir.exists()); @@ -279,6 +201,9 @@ Status MovieExporter::assembleAudio(const Object* obj, int clipCount = 0; + QString strCmd, filterComplex, amixInput; + strCmd += QString("\"%1\"").arg(ffmpegPath); + for (SoundClip* clip : allSoundClips) { if (mCanceled) @@ -286,69 +211,32 @@ Status MovieExporter::assembleAudio(const Object* obj, return Status::CANCELED; } - // convert audio file: 44100Hz sampling rate, stereo, signed 16 bit little endian - // supported audio file types: wav, mp3, ogg... ( all file types supported by ffmpeg ) - QString strCmd; - strCmd += QString("\"%1\"").arg(ffmpegPath); - strCmd += QString(" -i \"%1\" ").arg(clip->fileName()); - strCmd += "-ar 44100 -acodec pcm_s16le -ac 2 -y "; - strCmd += QString("\"%1\"").arg(tempAudioPath); - - executeFFMpeg(strCmd, [](float){}); - qDebug() << "audio file: " + tempAudioPath; - - // Read wav file header - WavFileHeader header; - QFile file(tempAudioPath); - file.open(QIODevice::ReadOnly); - file.read((char*)&header, sizeof(WavFileHeader)); - - skipUselessChucks(header, file); - - int32_t audioSize = header.dataSize; - - qDebug() << "audio len " << audioSize; - - // before calling malloc should check: audioSize < max credible value - std::vector< int16_t > data(audioSize / sizeof(int16_t)); - file.read((char*)data.data(), audioSize); - audioDataValid = true; - - float fframe = (float)clip->pos() / (float)fps; - int delta = fframe * 44100 * 2; - qDebug() << "audio delta " << delta; + // Add sound file as input + strCmd += QString(" -i \"%1\"").arg(clip->fileName()); - int indexMax = std::min(audioSize / 2, audioDataSize / 2 - delta); + // Offset the sound to its correct position + // See https://superuser.com/questions/716320/ffmpeg-placing-audio-at-specific-location + filterComplex += QString("[%1:a:0] adelay=%2S|%2S [ad%1];") + .arg(clipCount).arg(qRound(44100.0 * (clip->pos() - 1) / fps)); + amixInput += QString("[ad%1]").arg(clipCount); - // audio files 'mixing': 'higher' sound layers overwrite 'lower' sound layers - for (int i = 0; i < indexMax; i++) - { - audioData[i + delta] = safeSumInt16(audioData[i + delta], data[i]); - } - - file.close(); - - progress((float)clipCount / allSoundClips.size()); clipCount++; } - - if (!audioDataValid) - { - return Status::SAFE; - } - - // save mixed audio file ( will be used as audio stream ) - QFile file(mTempWorkDir + "/tmpaudio.wav"); - file.open(QIODevice::WriteOnly); - - WavFileHeader outputHeader; - outputHeader.InitWithDefaultValues(); - outputHeader.dataSize = audioDataSize; - outputHeader.chuckSize = 36 + audioDataSize; - - file.write((char*)&outputHeader, sizeof(outputHeader)); - file.write((char*)audioData.data(), audioDataSize); - file.close(); + // Output arguments + // Mix audio + strCmd += QString(" -filter_complex \"%1%2 amix=inputs=%3 [out]\"") + .arg(filterComplex).arg(amixInput).arg(clipCount); + // Convert audio file: 44100Hz sampling rate, stereo, signed 16 bit little endian + // Supported audio file types: wav, mp3, ogg... ( all file types supported by ffmpeg ) + strCmd += " -ar 44100 -acodec pcm_s16le -ac 2 -map \"[out]\" -y"; + // Trim audio + strCmd += QString(" -ss %1").arg((startFrame - 1) / static_cast(fps)); + strCmd += QString(" -to %1").arg(endFrame / static_cast(fps)); + // Output path + strCmd += " " + mTempWorkDir + "/tmpaudio.wav"; + + STATUS_CHECK(executeFFMpeg(strCmd, progress)); + qDebug() << "audio file: " + tempAudioPath; return Status::OK; } From 140b08208fb7884242e103c6bcb7bc6986a57c54 Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Wed, 5 Sep 2018 17:10:42 +1000 Subject: [PATCH 182/184] Only do auto-crop on the bitmap images in layers, skip temporary bitmap images --- core_lib/src/canvaspainter.cpp | 2 -- core_lib/src/graphics/bitmap/bitmapimage.cpp | 5 ++--- core_lib/src/graphics/bitmap/bitmapimage.h | 6 ++++-- core_lib/src/interface/scribblearea.cpp | 1 - core_lib/src/structure/layerbitmap.cpp | 1 + 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/core_lib/src/canvaspainter.cpp b/core_lib/src/canvaspainter.cpp index 59bcaf7a2..877b57312 100644 --- a/core_lib/src/canvaspainter.cpp +++ b/core_lib/src/canvaspainter.cpp @@ -211,7 +211,6 @@ void CanvasPainter::paintBitmapFrame(QPainter& painter, //qCDebug(mLog) << "Paint Image Size:" << paintedImage->image()->size(); BitmapImage paintToImage; - paintToImage.ignoreAutoCrop(); paintToImage.paste(paintedImage); if (colorize) @@ -244,7 +243,6 @@ void CanvasPainter::paintBitmapFrame(QPainter& painter, painter.setWorldMatrixEnabled(true); prescale(&paintToImage); - paintToImage.ignoreAutoCrop(); paintToImage.paintImage(painter, mScaledBitmap, mScaledBitmap.rect(), paintToImage.bounds()); } diff --git a/core_lib/src/graphics/bitmap/bitmapimage.cpp b/core_lib/src/graphics/bitmap/bitmapimage.cpp index 9b8ff6c97..5446b7945 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.cpp +++ b/core_lib/src/graphics/bitmap/bitmapimage.cpp @@ -26,7 +26,6 @@ BitmapImage::BitmapImage() { mImage = std::make_shared(); // create null image mBounds = QRect(0, 0, 0, 0); - mMinBound = true; } BitmapImage::BitmapImage(const BitmapImage& a) : KeyFrame(a) @@ -357,8 +356,8 @@ void BitmapImage::setCompositionModeBounds(QRect sourceBounds, bool isSourceMinB */ void BitmapImage::autoCrop() { - // Exit if current bounds are null - if (mBounds.isEmpty()) return; + if (!mEnableAutoCrop) return; + if (mBounds.isEmpty()) return; // Exit if current bounds are null if (!mImage) return; Q_ASSERT(mBounds.size() == mImage->size()); diff --git a/core_lib/src/graphics/bitmap/bitmapimage.h b/core_lib/src/graphics/bitmap/bitmapimage.h index aa7b2bbc1..5136f1e96 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.h +++ b/core_lib/src/graphics/bitmap/bitmapimage.h @@ -106,7 +106,7 @@ class BitmapImage : public KeyFrame * for the contained image. */ bool isMinimallyBounded() const { return mMinBound; } - void ignoreAutoCrop() { mMinBound = true; } + void enableAutoCrop(bool b) { mEnableAutoCrop = b; } Status writeFile(const QString& filename); @@ -121,8 +121,10 @@ class BitmapImage : public KeyFrame private: std::shared_ptr< QImage > mImage; QRect mBounds; + /** @see isMinimallyBounded() */ - bool mMinBound; + bool mMinBound = true; + bool mEnableAutoCrop = false; }; #endif diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index d64c0d837..0f4d42811 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -694,7 +694,6 @@ void ScribbleArea::paintBitmapBuffer() default: //nothing break; } - mBufferImg->ignoreAutoCrop(); targetImage->paste(mBufferImg, cm); } diff --git a/core_lib/src/structure/layerbitmap.cpp b/core_lib/src/structure/layerbitmap.cpp index 4596fe199..4757bfb13 100644 --- a/core_lib/src/structure/layerbitmap.cpp +++ b/core_lib/src/structure/layerbitmap.cpp @@ -89,6 +89,7 @@ KeyFrame* LayerBitmap::createKeyFrame(int position, Object*) { BitmapImage* b = new BitmapImage; b->setPos(position); + b->enableAutoCrop(true); return b; } From b08cfced702a37e15c00327baa4d8840c632a75e Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Mon, 17 Sep 2018 13:42:03 +1000 Subject: [PATCH 183/184] Fix: the first colour of colour palette doesn't update by the replace command --- app/src/colorpalettewidget.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/colorpalettewidget.cpp b/app/src/colorpalettewidget.cpp index 21c611619..25b604e57 100644 --- a/app/src/colorpalettewidget.cpp +++ b/app/src/colorpalettewidget.cpp @@ -131,7 +131,7 @@ void ColorPaletteWidget::replaceItem() QColor newColour = editor()->color()->frontColor(); - if (index > 0) + if (index >= 0) { updateItemColor(index, newColour); emit colorChanged(newColour); @@ -581,7 +581,8 @@ void ColorPaletteWidget::updateItemColor(int itemIndex, QColor newColor) QIcon swatchIcon; swatchIcon.addPixmap(colourSwatch, QIcon::Normal); - if(ui->colorListWidget->viewMode() == QListView::IconMode) { + if(ui->colorListWidget->viewMode() == QListView::IconMode) + { // Draw selection border swatchPainter.setPen(borderHighlight); swatchPainter.drawRect(0, 0, mIconSize.width() - 1, mIconSize.height() - 1); From 58aaec26d77441e3aa3579e16d044cbf6d6c256b Mon Sep 17 00:00:00 2001 From: Matt Chang Date: Mon, 17 Sep 2018 15:47:10 +1000 Subject: [PATCH 184/184] Version bump v0.6.2 rc1 --- app/data/Info.plist | 2 +- app/src/aboutdialog.cpp | 2 +- app/src/mainwindow2.cpp | 2 +- common.pri | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/data/Info.plist b/app/data/Info.plist index 2a1bb953d..c8a0dbf4f 100644 --- a/app/data/Info.plist +++ b/app/data/Info.plist @@ -62,7 +62,7 @@ CFBundleSignature PC2D CFBundleVersion - 0.6.2d + 0.6.2.0 LSApplicationCategoryType public.app-category.graphics-design NSHighResolutionCapable diff --git a/app/src/aboutdialog.cpp b/app/src/aboutdialog.cpp index edb6a3221..f1c79e3c1 100644 --- a/app/src/aboutdialog.cpp +++ b/app/src/aboutdialog.cpp @@ -40,7 +40,7 @@ AboutDialog::~AboutDialog() void AboutDialog::init() { QStringList devText; - devText << tr("Version: %1", "Version Number in About Dialog").arg(APP_VERSION); + devText << tr("Version: %1", "Version Number in About Dialog").arg(APP_VERSION " RC1"); #if defined(GIT_EXISTS) && defined(NIGHTLY_BUILD) devText << "commit: " S__GIT_COMMIT_HASH ; devText << "date: " S__GIT_TIMESTAMP ; diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index 492597765..aed17cc85 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -83,7 +83,7 @@ GNU General Public License for more details. #ifdef NIGHTLY_BUILD #define PENCIL_WINDOW_TITLE QString("[*]Pencil2D - Nightly Build %1").arg( BUILD_DATE ) #else -#define PENCIL_WINDOW_TITLE QString("[*]Pencil2D v%1").arg(APP_VERSION) +#define PENCIL_WINDOW_TITLE QString("[*]Pencil2D v%1").arg(APP_VERSION " RC1") #endif diff --git a/common.pri b/common.pri index d3449fc59..8fad62f6e 100644 --- a/common.pri +++ b/common.pri @@ -1,5 +1,5 @@ -VERSION = 0.6.1.1 +VERSION = 0.6.2 DEFINES += APP_VERSION=\\\"$$VERSION\\\" NIGHTLY {