diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..4730979 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "sources/QSS"] + path = sources/QSS + url = https://github.com/GTRONICK/QSS.git diff --git a/sources/JossPaint.pro b/sources/JossPaint.pro index ed213f9..cd947b5 100644 --- a/sources/JossPaint.pro +++ b/sources/JossPaint.pro @@ -47,6 +47,7 @@ SOURCES += main.cpp\ instruments/selectioninstrument.cpp \ instruments/curvelineinstrument.cpp \ instruments/colorpickerpaletteinstrument.cpp \ + instruments/cropinstrument.cpp \ instruments/textinstrument.cpp \ effects/abstracteffect.cpp \ effects/negativeeffect.cpp \ @@ -88,6 +89,7 @@ HEADERS += mainwindow.h \ instruments/curvelineinstrument.h \ instruments/textinstrument.h \ instruments/colorpickerpaletteinstrument.h \ + instruments/cropinstrument.h \ effects/abstracteffect.h \ effects/negativeeffect.h \ effects/grayeffect.h \ diff --git a/sources/QSS b/sources/QSS new file mode 160000 index 0000000..3be409c --- /dev/null +++ b/sources/QSS @@ -0,0 +1 @@ +Subproject commit 3be409c2c784a837ebc142f7a70499e15e0c3d27 diff --git a/sources/additionaltools.cpp b/sources/additionaltools.cpp index 4a7b334..9d818f0 100644 --- a/sources/additionaltools.cpp +++ b/sources/additionaltools.cpp @@ -144,12 +144,16 @@ bool AdditionalTools::zoomImage(qreal factor) } } -bool AdditionalTools::rotateImage(int x, int y) +bool AdditionalTools::rotateImage(int x, int y,int z) { - QTransform transform = QTransform().rotate(x, Qt::Axis::XAxis).rotate(y, Qt::Axis::YAxis); + QTransform transform = QTransform() + .rotate(x, Qt::Axis::XAxis) + .rotate(y, Qt::Axis::YAxis) + .rotate(z,Qt::Axis::ZAxis); mPImageArea->setImage(mPImageArea->getImage()->transformed(transform)); mPImageArea->resize((mPImageArea->getImage()->rect().width()), (mPImageArea->getImage()->rect().height())); + mPImageArea->update(); mPImageArea->setEdited(true); mPImageArea->clearSelection(); return true; diff --git a/sources/additionaltools.h b/sources/additionaltools.h index bcf74f4..0cf18fe 100644 --- a/sources/additionaltools.h +++ b/sources/additionaltools.h @@ -85,7 +85,7 @@ class AdditionalTools : public QObject * @return returns true in case of success */ bool zoomImage(qreal factor); - bool rotateImage(int x,int y); + bool rotateImage(int x,int y,int z); private: ImageArea *mPImageArea; /**< A pointer to ImageArea */ diff --git a/sources/datasingleton.cpp b/sources/datasingleton.cpp index fbb0b2a..0897f78 100644 --- a/sources/datasingleton.cpp +++ b/sources/datasingleton.cpp @@ -82,6 +82,7 @@ void DataSingleton::readSetting() mEditShortcuts.insert("Copy", settings.value("/Shortcuts/Edit/Copy", QKeySequence(QKeySequence::Copy)).value()); mEditShortcuts.insert("Paste", settings.value("/Shortcuts/Edit/Paste", QKeySequence(QKeySequence::Paste)).value()); mEditShortcuts.insert("Cut", settings.value("/Shortcuts/Edit/Cut", QKeySequence(QKeySequence::Cut)).value()); + mEditShortcuts.insert("Crop", settings.value("/Shortcuts/Edit/Crop", QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_X)).value()); //read shortcuts for instruments menu mInstrumentsShortcuts.insert("Cursor", settings.value("/Shortcuts/Instruments/Cursor", "Ctrl+1").value()); @@ -96,7 +97,7 @@ void DataSingleton::readSetting() mInstrumentsShortcuts.insert("Ellipse", settings.value("/Shortcuts/Instruments/Ellipse", "Ctrl+0").value()); mInstrumentsShortcuts.insert("Curve", settings.value("/Shortcuts/Instruments/Curve", "").value()); mInstrumentsShortcuts.insert("Text", settings.value("/Shortcuts/Instruments/Text", "").value()); - // TODO: Add shortcuts for new instruments here + mInstrumentsShortcuts.insert("Crop", settings.value("/Shortcuts/Instruments/Crop", "").value()); //read shortcuts for tools menu mToolsShortcuts.insert("ZoomIn", settings.value("/Shortcuts/Tools/Zoom/ZoomIn", QKeySequence(QKeySequence::ZoomIn)).value()); @@ -141,6 +142,7 @@ void DataSingleton::writeSettings() settings.setValue("/Shortcuts/Instruments/Fill", mInstrumentsShortcuts["Fill"]); settings.setValue("/Shortcuts/Instruments/Rect", mInstrumentsShortcuts["Rect"]); settings.setValue("/Shortcuts/Instruments/Ellipse", mInstrumentsShortcuts["Ellipse"]); + settings.setValue("/Shortcuts/Instruments/Crop", mInstrumentsShortcuts["Crop"]); //write shortcuts for tools menu settings.setValue("/Shortcuts/Tools/Zoom/ZoomIn", mToolsShortcuts["ZoomIn"]); diff --git a/sources/imagearea.cpp b/sources/imagearea.cpp index d19102e..2a308cf 100644 --- a/sources/imagearea.cpp +++ b/sources/imagearea.cpp @@ -46,6 +46,7 @@ A copy of the License : https://github.com/maifeeulasad/Paint/blob/main/LICENSE #include "instruments/selectioninstrument.h" #include "instruments/curvelineinstrument.h" #include "instruments/textinstrument.h" +#include "instruments/cropinstrument.h" #include "dialogs/resizedialog.h" #include "effects/abstracteffect.h" @@ -155,6 +156,7 @@ ImageArea::ImageArea(const bool &isOpen, const QString &filePath, QWidget *paren mInstrumentsHandlers[COLORPICKERPALETTE] = new ColorpickerPaletteInstrument(this); mInstrumentsHandlers[CURVELINE] = new CurveLineInstrument(this); mInstrumentsHandlers[TEXT] = new TextInstrument(this); + mInstrumentsHandlers[CROP] = new CropInstrument(this); // Effects handlers mEffectsHandlers.fill(0, (int)EFFECTS_COUNT); @@ -341,9 +343,10 @@ void ImageArea::rotateImage(bool flag) emit sendNewImageSize(mImage->size()); } -void ImageArea::rotateImage(int x,int y) +void ImageArea::rotateImage(int x,int y,int z) { - mAdditionalTools->rotateImage(x,y); + mAdditionalTools->rotateImage(x,y,z); + emit sendNewImageSize(mImage->size()); } void ImageArea::applyEffect(EffectsEnum effect) @@ -377,6 +380,11 @@ void ImageArea::cutImage() instrument->cutImage(*this); } +void ImageArea::cropImage() +{ + SelectionInstrument *instrument = static_cast (mInstrumentsHandlers.at(CURSOR)); + instrument->cropImage(*this); +} void ImageArea::mousePressEvent(QMouseEvent *event) { if(event->button() == Qt::LeftButton && @@ -424,7 +432,6 @@ void ImageArea::mouseMoveEvent(QMouseEvent *event) if(instrument != NONE_INSTRUMENT) { - //todo : fix segmentation-fault in color picker palette mInstrumentHandler->mouseMoveEvent(event, *this); } } @@ -506,6 +513,8 @@ void ImageArea::restoreCursor() mCurrentCursor = new QCursor(*mPixmap); setCursor(*mCurrentCursor); break; + case CROP: + break; } } @@ -516,7 +525,7 @@ void ImageArea::drawCursor() QPoint center(13, 13); switch(DataSingleton::Instance()->getInstrument()) { - case NONE_INSTRUMENT: case LINE: case COLORPICKERPALETTE: case MAGNIFIER: case SPRAY: + case NONE_INSTRUMENT: case LINE: case COLORPICKERPALETTE: case MAGNIFIER: case SPRAY: case CROP: case FILL: case RECTANGLE: case ELLIPSE: case CURSOR: case INSTRUMENTS_COUNT: case CURVELINE: case TEXT: break; @@ -528,7 +537,7 @@ void ImageArea::drawCursor() switch(DataSingleton::Instance()->getInstrument()) { case NONE_INSTRUMENT: case LINE: case COLORPICKERPALETTE: case MAGNIFIER: case SPRAY: - case FILL: case RECTANGLE: case ELLIPSE: case CURSOR: case INSTRUMENTS_COUNT: + case FILL: case RECTANGLE: case ELLIPSE: case CURSOR: case INSTRUMENTS_COUNT: case CROP: case CURVELINE: case TEXT: break; case PEN: diff --git a/sources/imagearea.h b/sources/imagearea.h index 5ff4577..5a9488b 100644 --- a/sources/imagearea.h +++ b/sources/imagearea.h @@ -97,7 +97,7 @@ class ImageArea : public QWidget * @param flag Rotate to left or to right. */ void rotateImage(bool flag); - void rotateImage(int x,int y); + void rotateImage(int x,int y,int z); inline QString getFileName() { return (mFilePath.isEmpty() ? mFilePath : mFilePath.split('/').last()); } @@ -157,6 +157,7 @@ class ImageArea : public QWidget * */ void cutImage(); + void cropImage(); /** * @brief Save all image changes to image copy. * diff --git a/sources/instruments/colorpickerpaletteinstrument.cpp b/sources/instruments/colorpickerpaletteinstrument.cpp index 7c5916b..950fd33 100644 --- a/sources/instruments/colorpickerpaletteinstrument.cpp +++ b/sources/instruments/colorpickerpaletteinstrument.cpp @@ -3,9 +3,6 @@ MIT License Copyright (c) 2020 Maifee Ul Asad -Copyright (c) 2012 EasyPaint https://github.com/Gr1N/EasyPaint - - Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights diff --git a/sources/instruments/colorpickerpaletteinstrument.h b/sources/instruments/colorpickerpaletteinstrument.h index f3cbd56..bca5ddb 100644 --- a/sources/instruments/colorpickerpaletteinstrument.h +++ b/sources/instruments/colorpickerpaletteinstrument.h @@ -3,9 +3,6 @@ MIT License Copyright (c) 2020 Maifee Ul Asad -Copyright (c) 2012 EasyPaint https://github.com/Gr1N/EasyPaint - - Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights diff --git a/sources/instruments/cropinstrument.cpp b/sources/instruments/cropinstrument.cpp new file mode 100644 index 0000000..6552cd8 --- /dev/null +++ b/sources/instruments/cropinstrument.cpp @@ -0,0 +1,238 @@ +/* +MIT License + +Copyright (c) 2020 Maifee Ul Asad + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +GitHub repo : https://github.com/maifeeulasad/Paint + +A copy of the License : https://github.com/maifeeulasad/Paint/blob/main/LICENSE +*/ + +#include "cropinstrument.h" +#include "../imagearea.h" +#include "../undocommand.h" +#include "math.h" + +#include +#include +#include + +CropInstrument::CropInstrument(QObject *parent) : + AbstractSelection(parent){ + this->installEventFilter(this); +} + +void CropInstrument::copyImage(ImageArea &imageArea) +{ + if (mIsSelectionExists) + { + imageArea.setImage(mImageCopy); + QClipboard *globalClipboard = QApplication::clipboard(); + QImage copyImage; + if(mIsImageSelected) + { + copyImage = mSelectedImage; + } + else + { + copyImage = imageArea.getImage()->copy(mTopLeftPoint.x(), mTopLeftPoint.y(), mWidth, mHeight); + } + globalClipboard->setImage(copyImage, QClipboard::Clipboard); + } +} + +void CropInstrument::cutImage(ImageArea &imageArea) +{ + if (mIsSelectionExists) + { + copyImage(imageArea); + if(mIsSelectionExists) + { + imageArea.setImage(mImageCopy); + paint(imageArea); + } + makeUndoCommand(imageArea); + if (/*mSelectedImage != mPasteImage || !*/mIsImageSelected) + { + imageArea.setImage(mImageCopy); + } + else + { + clearSelectionBackground(imageArea); + } + mTopLeftPoint = QPoint(0, 0); + mBottomRightPoint = QPoint(0, 0); + mImageCopy = *imageArea.getImage(); + imageArea.update(); + mIsSelectionExists = false; + imageArea.restoreCursor(); + emit sendEnableCopyCutActions(false); + } +} + +void CropInstrument::pasteImage(ImageArea &imageArea) +{ + QClipboard *globalClipboard = QApplication::clipboard(); + if(mIsSelectionExists) + { + imageArea.setImage(mImageCopy); + paint(imageArea); + mImageCopy = *imageArea.getImage(); + } + makeUndoCommand(imageArea); + mPasteImage = globalClipboard->image(); + if (!mPasteImage.isNull()) + { + mSelectedImage = mPasteImage; + mImageCopy = *imageArea.getImage(); + mTopLeftPoint = QPoint(0, 0); + mBottomRightPoint = QPoint(mPasteImage.width(), mPasteImage.height()) - QPoint(1, 1); + mHeight = mPasteImage.height(); + mWidth = mPasteImage.width(); + mIsImageSelected = mIsSelectionExists = true; + paint(imageArea); + drawBorder(imageArea); + imageArea.restoreCursor(); + emit sendEnableCopyCutActions(true); + } +} + +void CropInstrument::startAdjusting(ImageArea &imageArea) +{ + mImageCopy = *imageArea.getImage(); + mIsImageSelected = false; +} + +void CropInstrument::startSelection(ImageArea &) +{ +} + +void CropInstrument::startResizing(ImageArea &imageArea) +{ + if (!mIsImageSelected) + { + clearSelectionBackground(imageArea); + } + if (mIsSelectionAdjusting) + { + mIsImageSelected = false; + } +} + +void CropInstrument::startMoving(ImageArea &imageArea) +{ + clearSelectionBackground(imageArea); + if (mIsSelectionAdjusting) + { + mIsImageSelected = false; + } +} + +void CropInstrument::select(ImageArea &) +{ +} + +void CropInstrument::resize(ImageArea &) +{ +} + +void CropInstrument::move(ImageArea &) +{ +} + +void CropInstrument::completeSelection(ImageArea &imageArea) +{ + mSelectedImage = imageArea.getImage()->copy(mTopLeftPoint.x(), + mTopLeftPoint.y(), + mWidth, mHeight); + emit sendEnableCopyCutActions(true); +} + +void CropInstrument::completeResizing(ImageArea &imageArea) +{ + mSelectedImage = imageArea.getImage()->copy(mTopLeftPoint.x(), + mTopLeftPoint.y(), + mWidth, mHeight); +} + +void CropInstrument::completeMoving(ImageArea &imageArea) +{ + if (mIsSelectionAdjusting) + { + mSelectedImage = imageArea.getImage()->copy(mTopLeftPoint.x(), + mTopLeftPoint.y(), + mWidth, mHeight); + } + +} + +void CropInstrument::clearSelectionBackground(ImageArea &imageArea) +{ + if (!mIsSelectionAdjusting) + { + QPainter blankPainter(imageArea.getImage()); + blankPainter.setPen(Qt::white); + blankPainter.setBrush(QBrush(Qt::white)); + blankPainter.setBackgroundMode(Qt::OpaqueMode); + blankPainter.drawRect(QRect(mTopLeftPoint, mBottomRightPoint - QPoint(1, 1))); + blankPainter.end(); + mImageCopy = *imageArea.getImage(); + } +} + +void CropInstrument::clear() +{ + mSelectedImage = QImage(); + emit sendEnableCopyCutActions(false); +} + +void CropInstrument::paint(ImageArea &imageArea, bool, bool) +{ + if (mIsSelectionExists && !mIsSelectionAdjusting) + { + if(mTopLeftPoint != mBottomRightPoint) + { + QPainter painter(imageArea.getImage()); + QRect source(0, 0, mSelectedImage.width(), mSelectedImage.height()); + QRect target(mTopLeftPoint, mBottomRightPoint); + painter.drawImage(target, mSelectedImage, source); + painter.end(); + } + imageArea.setEdited(true); + imageArea.update(); + } +} + +void CropInstrument::showMenu(ImageArea &) +{ + +} + +bool CropInstrument::eventFilter(QObject *obj, QEvent *ev) +{ + (void)obj; + QKeyEvent *keyEvent = static_cast(ev); + if (keyEvent->key() == Qt::Key_Enter){ + //crop here + return true; + } + return false; +} diff --git a/sources/instruments/cropinstrument.h b/sources/instruments/cropinstrument.h new file mode 100644 index 0000000..7e5d33a --- /dev/null +++ b/sources/instruments/cropinstrument.h @@ -0,0 +1,97 @@ +/* +MIT License + +Copyright (c) 2020 Maifee Ul Asad + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +GitHub repo : https://github.com/maifeeulasad/Paint + +A copy of the License : https://github.com/maifeeulasad/Paint/blob/main/LICENSE +*/ + +#ifndef CROPINSTRUMENT_H +#define CROPINSTRUMENT_H + +#include "abstractselection.h" + +QT_BEGIN_NAMESPACE +class QUndoStack; +QT_END_NAMESPACE + +class CropInstrument : public AbstractSelection +{ + Q_OBJECT + +public: + explicit CropInstrument(QObject *parent = 0); + + /** + * @brief Clears background image at selection area. + * + * @param imageArea ImageArea for applying changes. + */ + void clearSelectionBackground(ImageArea &imageArea); + /** + * @brief Copying image to the clipboard. + * + * @param imageArea ImageArea for applying changes. + */ + void copyImage(ImageArea &imageArea); + /** + * @brief Paste image from the clipboard. + * + * @param imageArea ImageArea for applying changes. + */ + void pasteImage(ImageArea &imageArea); + /** + * @brief Cut image to the clipboard. + * + * @param imageArea ImageArea for applying changes. + */ + void cutImage(ImageArea &imageArea); + +private: + void startAdjusting(ImageArea &imageArea); + void startSelection(ImageArea &); + void startResizing(ImageArea &imageArea); + void startMoving(ImageArea &imageArea); + void select(ImageArea &); + void resize(ImageArea &); + void move(ImageArea &); + void completeSelection(ImageArea &imageArea); + void completeResizing(ImageArea &imageArea); + void completeMoving(ImageArea &imageArea); + void clear(); + void paint(ImageArea &imageArea, bool = false, bool = false); + void showMenu(ImageArea &); + + QImage mSelectedImage, /**< Copy of selected image. */ + mPasteImage; /**< Image to paste */ + +protected: + bool eventFilter(QObject *obj, QEvent *ev); + +signals: + void sendEnableCopyCutActions(bool enable); + void sendEnableSelectionInstrument(bool enable); + +}; + +#endif // CROPINSTRUMENT_H diff --git a/sources/instruments/selectioninstrument.cpp b/sources/instruments/selectioninstrument.cpp index 152758d..9274f36 100644 --- a/sources/instruments/selectioninstrument.cpp +++ b/sources/instruments/selectioninstrument.cpp @@ -91,6 +91,17 @@ void SelectionInstrument::cutImage(ImageArea &imageArea) } } +void SelectionInstrument::cropImage(ImageArea &imageArea) +{ + QImage cropArea = imageArea.getImage()->copy(mTopLeftPoint.x(), mTopLeftPoint.y(), mWidth, mHeight); + makeUndoCommand(imageArea); + imageArea.setImage(cropArea); + imageArea.update(); + mIsSelectionExists = false; + imageArea.restoreCursor(); + emit sendEnableCopyCutActions(false); +} + void SelectionInstrument::pasteImage(ImageArea &imageArea) { QClipboard *globalClipboard = QApplication::clipboard(); diff --git a/sources/instruments/selectioninstrument.h b/sources/instruments/selectioninstrument.h index 839ff12..f3b8866 100644 --- a/sources/instruments/selectioninstrument.h +++ b/sources/instruments/selectioninstrument.h @@ -69,6 +69,7 @@ class SelectionInstrument : public AbstractSelection * @param imageArea ImageArea for applying changes. */ void cutImage(ImageArea &imageArea); + void cropImage(ImageArea &imageArea); private: void startAdjusting(ImageArea &imageArea); diff --git a/sources/josspaintenums.h b/sources/josspaintenums.h index 3828ac6..3112471 100644 --- a/sources/josspaintenums.h +++ b/sources/josspaintenums.h @@ -51,6 +51,7 @@ typedef enum ELLIPSE, CURVELINE, TEXT, + CROP, // Don't use it. (Used to know count of current instrument) INSTRUMENTS_COUNT diff --git a/sources/main.cpp b/sources/main.cpp index a2616d9..aecb30c 100644 --- a/sources/main.cpp +++ b/sources/main.cpp @@ -34,6 +34,7 @@ A copy of the License : https://github.com/maifeeulasad/Paint/blob/main/LICENSE #include #include #include +#include #include "mainwindow.h" #include "datasingleton.h" @@ -55,9 +56,15 @@ void printVersion() int main(int argc, char *argv[]) { QApplication a(argc, argv); - a.setApplicationName("Paint"); + a.setApplicationName("Joss Paint"); a.setApplicationVersion("0.1.1"); + QFile styleFile( ":/QSS/MacOS.qss" ); + styleFile.open( QFile::ReadOnly ); + + QString style( styleFile.readAll() ); + a.setStyleSheet( style ); + QStringList args = a.arguments(); QRegExp rxArgHelp("--help"); diff --git a/sources/mainwindow.cpp b/sources/mainwindow.cpp index 4ccdaac..c90fee8 100644 --- a/sources/mainwindow.cpp +++ b/sources/mainwindow.cpp @@ -54,6 +54,10 @@ A copy of the License : https://github.com/maifeeulasad/Paint/blob/main/LICENSE MainWindow::MainWindow(QStringList filePaths, QWidget *parent) : QMainWindow(parent), mPrevInstrumentSetted(false) { + mRotX = 0; + mRotY = 0; + mRotZ = 0; + QSize winSize = DataSingleton::Instance()->getWindowSize(); if (DataSingleton::Instance()->getIsRestoreWindowSize() && winSize.isValid()) { resize(winSize); @@ -234,6 +238,14 @@ void MainWindow::initializeMainMenu() connect(mCutAction, &QAction::triggered, this, &MainWindow::cutAct); editMenu->addAction(mCutAction); + mCropAction = new QAction(tr("Crop S&election")); + mCropAction->setIcon(QIcon::fromTheme("transform-crop")); + mCropAction->setIconVisibleInMenu(true); + mCropAction->setEnabled(false); + connect(mCropAction, &QAction::triggered, this, &MainWindow::cropAct); + editMenu->addAction(mCropAction); + + editMenu->addSeparator(); QAction *settingsAction = new QAction(tr("&Settings"), this); @@ -329,6 +341,13 @@ void MainWindow::initializeMainMenu() mInstrumentsMenu->addAction(mTextAction); mInstrumentsActMap.insert(TEXT, mTextAction); + QAction *mCropAction = new QAction(tr("Crop"), this); + mCropAction->setCheckable(true); + mCropAction->setIcon(QIcon::fromTheme("transform-crop", QIcon(":/media/instruments-icons/crop.png"))); + connect(mCropAction, &QAction::triggered, this, &MainWindow::instumentsAct); + mInstrumentsMenu->addAction(mCropAction); + mInstrumentsActMap.insert(CROP, mCropAction); + // TODO: Add new instrument action here mEffectsMenu = menuBar()->addMenu(tr("E&ffects")); @@ -394,6 +413,23 @@ void MainWindow::initializeMainMenu() mToolsMenu->addMenu(rotateMenu); + QMenu *flipMenu = new QMenu(tr("Flip")); + + QAction *flipVAction = new QAction(tr("Vertically"), this); + flipVAction->setIcon(QIcon::fromTheme("object-flip-vertical", QIcon(":/media/actions-icons/object-flip-vertical.png"))); + flipVAction->setIconVisibleInMenu(true); + connect(flipVAction, &QAction::triggered, this, &MainWindow::flipVerticalAct); + flipMenu->addAction(flipVAction); + + QAction *flipHAction = new QAction(tr("Horizontally"), this); + flipHAction->setIcon(QIcon::fromTheme("object-flip-horizontal", QIcon(":/media/actions-icons/object-flip-horizontal.png"))); + flipHAction->setIconVisibleInMenu(true); + connect(flipHAction, &QAction::triggered, this, &MainWindow::flipHorizontalAct); + flipMenu->addAction(flipHAction); + + mToolsMenu->addMenu(flipMenu); + + QMenu *zoomMenu = new QMenu(tr("Zoom")); mZoomInAction = new QAction(tr("Zoom In"), this); @@ -585,6 +621,12 @@ void MainWindow::cutAct() imageArea->cutImage(); } +void MainWindow::cropAct() +{ + if (ImageArea *imageArea = getCurrentImageArea()) + imageArea->cropImage(); +} + void MainWindow::updateShortcuts() { mNewAction->setShortcut(DataSingleton::Instance()->getFileShortcutByKey("New")); @@ -600,6 +642,7 @@ void MainWindow::updateShortcuts() mCopyAction->setShortcut(DataSingleton::Instance()->getEditShortcutByKey("Copy")); mPasteAction->setShortcut(DataSingleton::Instance()->getEditShortcutByKey("Paste")); mCutAction->setShortcut(DataSingleton::Instance()->getEditShortcutByKey("Cut")); + mCropAction->setShortcut(DataSingleton::Instance()->getEditShortcutByKey("Crop")); mInstrumentsActMap[CURSOR]->setShortcut(DataSingleton::Instance()->getInstrumentShortcutByKey("Cursor")); mInstrumentsActMap[ERASER]->setShortcut(DataSingleton::Instance()->getInstrumentShortcutByKey("Lastic")); @@ -613,7 +656,7 @@ void MainWindow::updateShortcuts() mInstrumentsActMap[ELLIPSE]->setShortcut(DataSingleton::Instance()->getInstrumentShortcutByKey("Ellipse")); mInstrumentsActMap[CURVELINE]->setShortcut(DataSingleton::Instance()->getInstrumentShortcutByKey("Curve")); mInstrumentsActMap[TEXT]->setShortcut(DataSingleton::Instance()->getInstrumentShortcutByKey("Text")); - // TODO: Add new instruments' shorcuts here + mInstrumentsActMap[CROP]->setShortcut(DataSingleton::Instance()->getInstrumentShortcutByKey("Crop")); mZoomInAction->setShortcut(DataSingleton::Instance()->getToolShortcutByKey("ZoomIn")); mZoomOutAction->setShortcut(DataSingleton::Instance()->getToolShortcutByKey("ZoomOut")); @@ -645,7 +688,22 @@ void MainWindow::rotateRightImageAct() getCurrentImageArea()->rotateImage(true); } -//todo : rotate degree input, or options +void MainWindow::rotateImageAct() +{ + getCurrentImageArea()->rotateImage(mRotX,mRotY,mRotZ); +} + +void MainWindow::flipVerticalAct() +{ + //mRotX += 180; + getCurrentImageArea()->rotateImage(180,0,0); +} + +void MainWindow::flipHorizontalAct() +{ + //mRotY += 180; + getCurrentImageArea()->rotateImage(0,180,0); +} void MainWindow::zoomInAct() { @@ -827,6 +885,7 @@ void MainWindow::enableCopyCutActions(bool enable) { mCopyAction->setEnabled(enable); mCutAction->setEnabled(enable); + mCropAction->setEnabled(enable); } void MainWindow::clearImageSelection() diff --git a/sources/mainwindow.h b/sources/mainwindow.h index 81278ba..81b180d 100644 --- a/sources/mainwindow.h +++ b/sources/mainwindow.h @@ -106,11 +106,12 @@ class MainWindow : public QMainWindow QMap mInstrumentsActMap; QMap mEffectsActMap; QAction *mSaveAction, *mSaveAsAction, *mCloseAction, *mPrintAction, - *mUndoAction, *mRedoAction, *mCopyAction, *mCutAction, + *mUndoAction, *mRedoAction, *mCopyAction, *mCutAction, *mCropAction, *mNewAction, *mOpenAction, *mExitAction, *mPasteAction, *mZoomInAction, *mZoomOutAction; QMenu *mInstrumentsMenu, *mEffectsMenu, *mToolsMenu; QUndoGroup *mUndoStackGroup; bool mPrevInstrumentSetted; /**< Used for magnifier */ + int mRotX,mRotY,mRotZ; private slots: void activateTab(const int &index); void setNewSizeToSizeLabel(const QSize &size); @@ -127,12 +128,16 @@ private slots: void copyAct(); void pasteAct(); void cutAct(); + void cropAct(); void settingsAct(); void effectsAct(); void resizeImageAct(); void resizeCanvasAct(); void rotateLeftImageAct(); void rotateRightImageAct(); + void rotateImageAct(); + void flipVerticalAct(); + void flipHorizontalAct(); void zoomInAct(); void zoomOutAct(); void advancedZoomAct(); diff --git a/sources/media/actions-icons/object-flip-horizontal.png b/sources/media/actions-icons/object-flip-horizontal.png new file mode 100644 index 0000000..b9f414d Binary files /dev/null and b/sources/media/actions-icons/object-flip-horizontal.png differ diff --git a/sources/media/actions-icons/object-flip-vertical.png b/sources/media/actions-icons/object-flip-vertical.png new file mode 100644 index 0000000..d94f8bf Binary files /dev/null and b/sources/media/actions-icons/object-flip-vertical.png differ diff --git a/sources/media/instruments-icons/crop.png b/sources/media/instruments-icons/crop.png new file mode 100644 index 0000000..874298e Binary files /dev/null and b/sources/media/instruments-icons/crop.png differ diff --git a/sources/paint.pro b/sources/paint.pro index 1dd0508..1d424d9 100644 --- a/sources/paint.pro +++ b/sources/paint.pro @@ -47,6 +47,7 @@ SOURCES += main.cpp\ instruments/selectioninstrument.cpp \ instruments/curvelineinstrument.cpp \ instruments/colorpickerpaletteinstrument.cpp \ + instruments/cropinstrument.cpp \ instruments/textinstrument.cpp \ effects/abstracteffect.cpp \ effects/negativeeffect.cpp \ @@ -88,6 +89,7 @@ HEADERS += mainwindow.h \ instruments/curvelineinstrument.h \ instruments/textinstrument.h \ instruments/colorpickerpaletteinstrument.h \ + instruments/cropinstrument.h \ effects/abstracteffect.h \ effects/negativeeffect.h \ effects/grayeffect.h \ diff --git a/sources/resources.qrc b/sources/resources.qrc index a7dee71..9c63b3e 100644 --- a/sources/resources.qrc +++ b/sources/resources.qrc @@ -16,6 +16,7 @@ media/instruments-icons/cursor_pipette.png media/instruments-icons/cursor_spray.png media/instruments-icons/cursor_fill.png + media/instruments-icons/crop.png media/textures/transparent.jpg media/actions-icons/application-exit.png media/actions-icons/document-new.png @@ -38,5 +39,16 @@ media/logo/josspaint_64.png media/instruments-icons/curve.png media/actions-icons/clear-gray.png + + + QSS/Ubuntu.qss + QSS/AMOLED.qss + QSS/Aqua.qss + QSS/ConsoleStyle.qss + QSS/ElegantDark.qss + QSS/ConsoleStyle.qss + QSS/ManjaroMix.qss + QSS/MaterialDark.qss + QSS/NeonButtons.qss diff --git a/sources/widgets/colorchooser.cpp b/sources/widgets/colorchooser.cpp index 8da6f2f..8a0d566 100644 --- a/sources/widgets/colorchooser.cpp +++ b/sources/widgets/colorchooser.cpp @@ -40,14 +40,14 @@ A copy of the License : https://github.com/maifeeulasad/Paint/blob/main/LICENSE ColorChooser::ColorChooser(const int &r, const int &g, const int &b, QWidget *parent) : QLabel(parent) { - setFrameStyle(QFrame::Raised | QFrame::Box); + setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); mCurrentColor = new QColor(r, g, b); mPixmapColor = new QPixmap(20, 20); mPainterColor = new QPainter(mPixmapColor); mPainterColor->fillRect(0, 0, 20, 20, *mCurrentColor); mPainterColor->end(); setMargin(3); - setAlignment(Qt::AlignHCenter); + setAlignment(Qt::AlignBottom); setPixmap(*mPixmapColor); } diff --git a/sources/widgets/toolbar.cpp b/sources/widgets/toolbar.cpp index a4bbb01..1128e12 100644 --- a/sources/widgets/toolbar.cpp +++ b/sources/widgets/toolbar.cpp @@ -38,6 +38,7 @@ A copy of the License : https://github.com/maifeeulasad/Paint/blob/main/LICENSE #include #include #include +#include ToolBar::ToolBar(const QMap &actMap, QWidget *parent) : QToolBar(tr("Instruments"), parent), mActMap(actMap) @@ -59,6 +60,7 @@ QToolButton* ToolBar::createToolButton(QAction *act) void ToolBar::initializeItems() { + QLabel *InstrumentText = new QLabel(tr("Instruments"), this); mCursorButton = createToolButton(mActMap[CURSOR]); mEraserButton = createToolButton(mActMap[ERASER]); mPenButton = createToolButton(mActMap[PEN]); @@ -71,25 +73,38 @@ void ToolBar::initializeItems() mEllipseButton = createToolButton(mActMap[ELLIPSE]); mCurveButton = createToolButton(mActMap[CURVELINE]); mTextButton = createToolButton(mActMap[TEXT]); + mCropButton = createToolButton(mActMap[CROP]); + + textPenSize = new QLabel(tr("Pen size: 1 "), this); + mPenSize = new QSlider(Qt::Horizontal); + mPenSize->setMinimum(1); + mPenSize->setMaximum(25); + mPenSize->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); + connect(mPenSize, &QAbstractSlider::valueChanged, this, &ToolBar::valuePenSize); QGridLayout *bLayout = new QGridLayout(); - bLayout->setMargin(3); - bLayout->addWidget(mPenButton, 0, 0); - bLayout->addWidget(mEraserButton, 0, 1); - bLayout->addWidget(mColorPickerPaletteButton, 1, 0); - bLayout->addWidget(mMagnifierButton, 1, 1); - bLayout->addWidget(mCursorButton, 2, 0); - bLayout->addWidget(mLineButton, 2, 1); - bLayout->addWidget(mSprayButton, 3, 0); - bLayout->addWidget(mFillButton, 3, 1); - bLayout->addWidget(mRectangleButton, 4, 0); - bLayout->addWidget(mEllipseButton, 4, 1); - bLayout->addWidget(mCurveButton, 5, 0); - bLayout->addWidget(mTextButton, 5, 1); + bLayout->setMargin(1); + bLayout->addWidget(InstrumentText, 0, 0, 1, 4, Qt::AlignCenter); + bLayout->addWidget(mPenButton, 1, 0); + bLayout->addWidget(mSprayButton, 1, 1); + bLayout->addWidget(mEraserButton, 1, 2); + bLayout->addWidget(mLineButton, 1, 3); + bLayout->addWidget(mCurveButton, 2, 0); + bLayout->addWidget(mRectangleButton, 2, 1); + bLayout->addWidget(mEllipseButton, 2, 2); + bLayout->addWidget(mCropButton, 2, 3); + bLayout->addWidget(mCursorButton, 3, 0); + bLayout->addWidget(mMagnifierButton, 3, 1); + bLayout->addWidget(mTextButton, 3, 2); + bLayout->addWidget(textPenSize, 4, 0, 1, 4); + bLayout->addWidget(mPenSize, 5, 0, 1, 4); + QWidget *bWidget = new QWidget(); bWidget->setLayout(bLayout); + QLabel *ColorText = new QLabel(tr("Color"), this); + mPColorChooser = new ColorChooser(0, 0, 0, this); mPColorChooser->setStatusTip(tr("Primary color")); mPColorChooser->setToolTip(tr("Primary color")); @@ -100,18 +115,13 @@ void ToolBar::initializeItems() mSColorChooser->setToolTip(tr("Secondary color")); connect(mSColorChooser, &ColorChooser::sendColor, this, &ToolBar::secondaryColorChanged); - QSpinBox *penSizeSpin = new QSpinBox(); - penSizeSpin->setRange(1, 20); - penSizeSpin->setValue(1); - penSizeSpin->setStatusTip(tr("Pen size")); - penSizeSpin->setToolTip(tr("Pen size")); - connect(penSizeSpin, SIGNAL(valueChanged(int)), this, SLOT(penValueChanged(int))); - QGridLayout *tLayout = new QGridLayout(); - tLayout->setMargin(3); - tLayout->addWidget(mPColorChooser, 0, 0); - tLayout->addWidget(mSColorChooser, 0, 1); - tLayout->addWidget(penSizeSpin, 1, 0, 1, 2); + tLayout->setMargin(1); + tLayout->addWidget(ColorText, 0, 0, 1, 4, Qt::AlignCenter); + tLayout->addWidget(mColorPickerPaletteButton, 1, 0); + tLayout->addWidget(mFillButton, 1, 1); + tLayout->addWidget(mPColorChooser, 1, 2); + tLayout->addWidget(mSColorChooser, 1, 3); QWidget *tWidget = new QWidget(); tWidget->setLayout(tLayout); @@ -121,9 +131,10 @@ void ToolBar::initializeItems() addWidget(tWidget); } -void ToolBar::penValueChanged(const int &value) +void ToolBar::valuePenSize(const int &value) { - DataSingleton::Instance()->setPenSize(value); + DataSingleton::Instance()->setPenSize(value); + textPenSize->setText(QString(tr("Pen size: %1")).arg(mPenSize->value())); } void ToolBar::primaryColorChanged(const QColor &color) diff --git a/sources/widgets/toolbar.h b/sources/widgets/toolbar.h index 8cce102..344b3fc 100644 --- a/sources/widgets/toolbar.h +++ b/sources/widgets/toolbar.h @@ -32,8 +32,10 @@ A copy of the License : https://github.com/maifeeulasad/Paint/blob/main/LICENSE #ifndef TOOLBAR_H #define TOOLBAR_H +#include "palettebutton.h" #include "../josspaintenums.h" - +#include +#include #include QT_BEGIN_NAMESPACE @@ -41,10 +43,6 @@ class QToolButton; class ColorChooser; QT_END_NAMESPACE -/** - * @brief Toolbar with instrumets buttons, color choosers and etc. - * - */ class ToolBar : public QToolBar { Q_OBJECT @@ -53,25 +51,17 @@ class ToolBar : public QToolBar explicit ToolBar(const QMap &actMap, QWidget *parent = 0); private: - /** - * @brief Initialize all buttons, color choosers and etc. - * - */ void initializeItems(); - /** - * @brief Create new QToolButton - * - * @param name Name of button - * @param iconPath Path to button icon. - * @return QToolButton Created QToolButton. - */ - QToolButton* createToolButton(QAction *act); + QToolButton* createToolButton(QAction *act); QToolButton *mCursorButton, *mEraserButton, *mPenButton, *mLineButton, *mColorPickerButton,*mColorPickerPaletteButton, *mMagnifierButton, *mSprayButton, *mFillButton, - *mRectangleButton, *mEllipseButton, *mCurveButton, *mTextButton; + *mRectangleButton, *mEllipseButton, *mCurveButton, *mTextButton, *mCropButton; ColorChooser *mPColorChooser, *mSColorChooser; + QSlider *mPenSize; + QLabel *textPenSize; + bool mPrevInstrumentSetted; const QMap &mActMap; @@ -84,7 +74,7 @@ public slots: void setSecondaryColorView(); private slots: - void penValueChanged(const int &value); + void valuePenSize(const int &value); void primaryColorChanged(const QColor &color); void secondaryColorChanged(const QColor &color);