From c4d9210c35025e328df57a10364c0da5570b1c15 Mon Sep 17 00:00:00 2001 From: lupoDharkael Date: Wed, 10 May 2017 22:14:05 +0200 Subject: [PATCH] Add initial code --- .gitmodules | 3 + capture/button.cpp | 172 ++++++++ capture/button.h | 67 +++ capture/buttonhandler.cpp | 272 ++++++++++++ capture/buttonhandler.h | 32 ++ capture/capturemodification.cpp | 41 ++ capture/capturemodification.h | 24 ++ capture/capturewidget.cpp | 477 +++++++++++++++++++++ capture/capturewidget.h | 107 +++++ capture/screenshot.cpp | 129 ++++++ capture/screenshot.h | 24 ++ configwindow.cpp | 48 +++ configwindow.h | 17 + controller.cpp | 65 +++ controller.h | 43 ++ flameshot.pro | 57 +++ graphics.qrc | 38 ++ img/buttonIconsBlack/LICENSE.txt | 202 +++++++++ img/buttonIconsBlack/README.md | 1 + img/buttonIconsBlack/arrow-bottom-left.svg | 1 + img/buttonIconsBlack/circle-outline.svg | 1 + img/buttonIconsBlack/close.svg | 1 + img/buttonIconsBlack/cloud-upload.svg | 1 + img/buttonIconsBlack/content-copy.svg | 1 + img/buttonIconsBlack/content-save.svg | 1 + img/buttonIconsBlack/cursor-move.svg | 1 + img/buttonIconsBlack/exit-to-app.svg | 1 + img/buttonIconsBlack/format-text.svg | 1 + img/buttonIconsBlack/line.svg | 56 +++ img/buttonIconsBlack/marker.svg | 1 + img/buttonIconsBlack/mouse-off.svg | 1 + img/buttonIconsBlack/mouse.svg | 1 + img/buttonIconsBlack/pencil.svg | 1 + img/buttonIconsBlack/square-outline.svg | 1 + img/buttonIconsBlack/undo-variant.svg | 1 + img/buttonIconsWhite/LICENSE.txt | 202 +++++++++ img/buttonIconsWhite/README.md | 1 + img/buttonIconsWhite/arrow-bottom-left.svg | 54 +++ img/buttonIconsWhite/circle-outline.svg | 54 +++ img/buttonIconsWhite/close.svg | 54 +++ img/buttonIconsWhite/cloud-upload.svg | 54 +++ img/buttonIconsWhite/content-copy.svg | 54 +++ img/buttonIconsWhite/content-save.svg | 54 +++ img/buttonIconsWhite/cursor-move.svg | 55 +++ img/buttonIconsWhite/exit-to-app.svg | 54 +++ img/buttonIconsWhite/format-text.svg | 54 +++ img/buttonIconsWhite/line.svg | 57 +++ img/buttonIconsWhite/marker.svg | 54 +++ img/buttonIconsWhite/mouse-off.svg | 54 +++ img/buttonIconsWhite/mouse.svg | 54 +++ img/buttonIconsWhite/pencil.svg | 54 +++ img/buttonIconsWhite/square-outline.svg | 54 +++ img/buttonIconsWhite/undo-variant.svg | 54 +++ img/flameshot.svg | 94 ++++ img/flameshotLogoLicense.txt | 253 +++++++++++ infowindow.cpp | 10 + infowindow.h | 16 + main.cpp | 21 + nativeeventfilter.cpp | 61 +++ nativeeventfilter.h | 23 + singleapplication | 1 + styles/button.css | 12 + 62 files changed, 3452 insertions(+) create mode 100644 .gitmodules create mode 100644 capture/button.cpp create mode 100644 capture/button.h create mode 100644 capture/buttonhandler.cpp create mode 100644 capture/buttonhandler.h create mode 100644 capture/capturemodification.cpp create mode 100644 capture/capturemodification.h create mode 100644 capture/capturewidget.cpp create mode 100644 capture/capturewidget.h create mode 100644 capture/screenshot.cpp create mode 100644 capture/screenshot.h create mode 100644 configwindow.cpp create mode 100644 configwindow.h create mode 100644 controller.cpp create mode 100644 controller.h create mode 100644 flameshot.pro create mode 100644 graphics.qrc create mode 100644 img/buttonIconsBlack/LICENSE.txt create mode 100644 img/buttonIconsBlack/README.md create mode 100644 img/buttonIconsBlack/arrow-bottom-left.svg create mode 100644 img/buttonIconsBlack/circle-outline.svg create mode 100644 img/buttonIconsBlack/close.svg create mode 100644 img/buttonIconsBlack/cloud-upload.svg create mode 100644 img/buttonIconsBlack/content-copy.svg create mode 100644 img/buttonIconsBlack/content-save.svg create mode 100644 img/buttonIconsBlack/cursor-move.svg create mode 100644 img/buttonIconsBlack/exit-to-app.svg create mode 100644 img/buttonIconsBlack/format-text.svg create mode 100644 img/buttonIconsBlack/line.svg create mode 100644 img/buttonIconsBlack/marker.svg create mode 100644 img/buttonIconsBlack/mouse-off.svg create mode 100644 img/buttonIconsBlack/mouse.svg create mode 100644 img/buttonIconsBlack/pencil.svg create mode 100644 img/buttonIconsBlack/square-outline.svg create mode 100644 img/buttonIconsBlack/undo-variant.svg create mode 100644 img/buttonIconsWhite/LICENSE.txt create mode 100644 img/buttonIconsWhite/README.md create mode 100644 img/buttonIconsWhite/arrow-bottom-left.svg create mode 100644 img/buttonIconsWhite/circle-outline.svg create mode 100644 img/buttonIconsWhite/close.svg create mode 100644 img/buttonIconsWhite/cloud-upload.svg create mode 100644 img/buttonIconsWhite/content-copy.svg create mode 100644 img/buttonIconsWhite/content-save.svg create mode 100644 img/buttonIconsWhite/cursor-move.svg create mode 100644 img/buttonIconsWhite/exit-to-app.svg create mode 100644 img/buttonIconsWhite/format-text.svg create mode 100644 img/buttonIconsWhite/line.svg create mode 100644 img/buttonIconsWhite/marker.svg create mode 100644 img/buttonIconsWhite/mouse-off.svg create mode 100644 img/buttonIconsWhite/mouse.svg create mode 100644 img/buttonIconsWhite/pencil.svg create mode 100644 img/buttonIconsWhite/square-outline.svg create mode 100644 img/buttonIconsWhite/undo-variant.svg create mode 100644 img/flameshot.svg create mode 100644 img/flameshotLogoLicense.txt create mode 100644 infowindow.cpp create mode 100644 infowindow.h create mode 100644 main.cpp create mode 100644 nativeeventfilter.cpp create mode 100644 nativeeventfilter.h create mode 160000 singleapplication create mode 100644 styles/button.css diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..3795c16c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "singleapplication"] + path = singleapplication + url = https://github.com/itay-grudev/SingleApplication diff --git a/capture/button.cpp b/capture/button.cpp new file mode 100644 index 00000000..c34ad75e --- /dev/null +++ b/capture/button.cpp @@ -0,0 +1,172 @@ +#include "button.h" +#include +#include +#include +#include + +namespace { + const int BUTTON_SIZE = 30; +} + +Button::Button(Type t, QWidget *parent) : QPushButton(parent) { + setFocusPolicy(Qt::NoFocus); + m_buttonType = t; + resize(BUTTON_SIZE, BUTTON_SIZE); + setMouseTracking(true); + setMask(QRegion(QRect(-1,-1,BUTTON_SIZE+2, BUTTON_SIZE+2), QRegion::Ellipse)); + + if (t == Button::Type::selectionIndicator) { + QFont f = this->font(); + setFont(QFont(f.family(), 7, QFont::Bold)); + } else { + setIcon(getIcon(t)); + } + setToolTip(typeTooltip[t]); + + emergeAnimation = new QPropertyAnimation(this, "size", this); + emergeAnimation->setEasingCurve(QEasingCurve::InOutQuad); + emergeAnimation->setDuration(80); + emergeAnimation->setStartValue(QSize(0, 0)); + emergeAnimation->setEndValue(QSize(BUTTON_SIZE, BUTTON_SIZE)); + +} + +QIcon Button::getIcon(const Type t) { + QString iconColor = "White"; // or "Black" + QString path = ":/img/buttonIcons" + iconColor + "/"; + + if (t == Type::mouseVisibility) { + QSettings settings; + bool mouseVisible = settings.value("mouseVisible").toBool(); + if (mouseVisible){ + path += "mouse.svg"; + } else { + path += "mouse-off.svg"; + } + return QIcon(path); + } + + switch (t) { + case Type::arrow: + path += "arrow-bottom-left.svg"; + break; + case Type::circle: + path += "circle-outline.svg"; + break; + case Type::colorPicker: + path += "square-outline.svg"; + break; + case Type::copy: + path += "content-copy.svg"; + break; + case Type::exit: + path += "close.svg"; + break; + case Type::imageUploader: + path += "cloud-upload.svg"; + break; + case Type::line: + path += "line.svg"; + break; + case Type::marker: + path += "marker.svg"; + break; + case Type::pencil: + path += "pencil.svg"; + break; + case Type::rectangle: + path += "square-outline.svg"; + break; + case Type::save: + path += "content-save.svg"; + break; + case Type::text: + path += "format-text.svg"; + break; + case Type::undo: + path += "undo-variant.svg"; + break; + case Type::move: + path += "cursor-move.svg"; + break; + default: + break; + } + return QIcon(path); +} + +void Button::enterEvent(QEvent *e) { + Q_EMIT hovered(); + QWidget::enterEvent(e); +} + +void Button::leaveEvent(QEvent *e) { + Q_EMIT mouseExited(); + QWidget::leaveEvent(e); +} + +void Button::mouseReleaseEvent(QMouseEvent *) { + + if (m_buttonType == Type::mouseVisibility) { + QSettings settings; + bool mouseVisible = settings.value("mouseVisible").toBool(); + settings.setValue("mouseVisible", !mouseVisible); + setIcon(getIcon(Type::mouseVisibility)); + } else if (m_buttonType == Type::colorPicker) { + + } + + Q_EMIT typeEmited(m_buttonType); + +} + +void Button::animatedShow() { + show(); + emergeAnimation->start(); +} + +Button::Type Button::getButtonType() const { + return m_buttonType; +} + +size_t Button::getButtonBaseSize() { + return BUTTON_SIZE; +} + +Button::typeData Button::typeTooltip = { + {Button::Type::selectionIndicator, "Shows the dimensions of the selection (X Y)"}, + {Button::Type::mouseVisibility, "Sets the visibility of the mouse pointer"}, + {Button::Type::exit, "Leaves the capture screen"}, + {Button::Type::copy, "Copies the selecion into the clipboard"}, + {Button::Type::save, "Opens the save image window"}, + {Button::Type::pencil, "Sets the paint tool to a pencil"}, + {Button::Type::line, "Sets the paint tool to a line drawer"}, + {Button::Type::arrow, "Sets the paint tool to an arrow drawer"}, + {Button::Type::rectangle, "Sets the paint tool to a rectagle drawer"}, + {Button::Type::circle, "Sets the paint tool to a circle drawer"}, + {Button::Type::marker, "Sets the paint tool to a marker"}, + {Button::Type::text, "Sets the paint tool to a text creator"}, + {Button::Type::colorPicker, "Opens the color picker widget"}, + {Button::Type::undo, "Undo the last modification"}, + {Button::Type::imageUploader, "Upload the selection to Imgur"}, + {Button::Type::move, "Move the selection area"} + }; + +Button::typeData Button::typeName = { + {Button::Type::selectionIndicator, "Selection Size Indicator"}, + {Button::Type::mouseVisibility, "Mouse Visibility"}, + {Button::Type::exit, "Exit"}, + {Button::Type::copy, "Copy"}, + {Button::Type::save, "Save"}, + {Button::Type::pencil, "Pencil"}, + {Button::Type::line, "Line"}, + {Button::Type::arrow, "Arrow"}, + {Button::Type::rectangle, "Rectangle"}, + {Button::Type::circle, "Circle"}, + {Button::Type::marker, "Marker"}, + {Button::Type::text, "Text"}, + {Button::Type::colorPicker, "Color Picker"}, + {Button::Type::undo, "Undo"}, + {Button::Type::imageUploader, "Image Uploader"}, + {Button::Type::move, "Move"} +}; diff --git a/capture/button.h b/capture/button.h new file mode 100644 index 00000000..a7072f43 --- /dev/null +++ b/capture/button.h @@ -0,0 +1,67 @@ +#ifndef BUTTON_H +#define BUTTON_H + +#include +#include +#include "button.h" + +class QWidget; +class QPropertyAnimation; + +class Button : public QPushButton { + Q_OBJECT + +public: + enum class Type { + selectionIndicator, + mouseVisibility, + exit, + copy, + save, + pencil, + line, + arrow, + rectangle, + circle, + marker, + text, + colorPicker, + undo, + imageUploader, + move, + last + }; + + typedef std::map typeData; + static typeData typeTooltip; + static typeData typeName; + + explicit Button(Type, QWidget *parent = 0); + + static QIcon getIcon(const Type); + static size_t getButtonBaseSize(); + + Type getButtonType() const; + + void animatedShow(); + +protected: + virtual void enterEvent(QEvent *); + virtual void leaveEvent(QEvent *); + virtual void mouseReleaseEvent(QMouseEvent *); + +private: + Button(QWidget *parent = 0); + Type m_buttonType; + + QPropertyAnimation *emergeAnimation; + +signals: + void hovered(); + void mouseExited(); + void typeEmited(Type); + +public slots: +}; + +#endif // BUTTON_H diff --git a/capture/buttonhandler.cpp b/capture/buttonhandler.cpp new file mode 100644 index 00000000..f241109c --- /dev/null +++ b/capture/buttonhandler.cpp @@ -0,0 +1,272 @@ +#include "buttonhandler.h" +#include + +namespace { + const int SEPARATION = 6; +} + +ButtonHandler::ButtonHandler(const QVector &v) { + if (!v.isEmpty()) { + m_distance = v[0]->getButtonBaseSize() + SEPARATION; + m_vectorButtons = v; + } +} + +ButtonHandler::ButtonHandler() { +} + +void ButtonHandler::hide() { + for (Button *b: m_vectorButtons) b->hide(); +} + +void ButtonHandler::show() { + for (Button *b: m_vectorButtons) b->animatedShow(); +} + +bool ButtonHandler::isVisible() const { + bool ret = false; + if (!m_vectorButtons.isEmpty()) ret = m_vectorButtons[0]->isVisible(); + return ret; +} + +size_t ButtonHandler::size() const { + return m_vectorButtons.size(); +} + +void ButtonHandler::updatePosition(const QRect &selection, + const QRect &limits) { + const QVector::size_type vecLength = m_vectorButtons.size(); + if (vecLength == 0) { + return; + } + // button dimmensions + const int baseHeight = Button::getButtonBaseSize(); + const int baseWidth = Button::getButtonBaseSize(); + // copy of the selection area for internal modifications + QRect baseArea = selection; + + // calculates the blocked sides (no more space for buttons) + bool blockedRight = + (limits.right() - baseArea.right() < SEPARATION*2 + baseWidth); + bool blockedLeft = + (baseArea.x() < baseWidth + SEPARATION*2); + bool blockedBotton = + (limits.bottom() - baseArea.bottom() < SEPARATION*2 + baseHeight); + bool blockedTop = + (baseArea.y() < baseHeight + SEPARATION*2); + + // detect if a side is smaller than a button in order to prevent collision + // and redimension the base area the the base size of a single button per side + if (baseArea.width() < baseWidth) { + if (blockedRight && !blockedLeft) { + baseArea.setX(baseArea.x() - (baseWidth-baseArea.width())); + } else if (!blockedLeft && !blockedRight) { + // when not close to the left side (because the rect grows to the right) + baseArea.setX(baseArea.x() - (baseWidth-baseArea.width()) / 2); + } + baseArea.setWidth(baseWidth); + } + if (baseArea.height() < baseHeight) { + if (blockedBotton && !blockedTop) { + baseArea.setY(baseArea.y() - (baseHeight-baseArea.height())); + } else if (!blockedTop && !blockedBotton) { + // when not close to the top (because the rect grows to the bottom) + baseArea.setY(baseArea.y() - (baseHeight-baseArea.height()) / 2); + } + baseArea.setHeight(baseHeight); + } + // indicates the actual button to be moved + QVector::size_type elemIndicator = 0; + + while (elemIndicator < vecLength) { + // update of blocked sides + blockedRight = (limits.right() - baseArea.right() < SEPARATION * 2 + baseWidth); + blockedLeft = (baseArea.x() < baseWidth + SEPARATION * 2); + blockedBotton = (limits.bottom() - baseArea.bottom() < SEPARATION * 2 + baseHeight); + blockedTop = (baseArea.y() < baseHeight + SEPARATION * 2); + // helper booleans + bool oneHorizontalBlocked = (!blockedRight && blockedLeft) || + (blockedRight && !blockedLeft); + bool horizontalBlocked = blockedRight && blockedLeft; + + // add them inside the area when there is no more space + if (blockedBotton && horizontalBlocked && blockedTop) { + int buttonsPerRow = (baseArea.width() - SEPARATION) / (baseWidth + SEPARATION); + int xPos = baseArea.left() + SEPARATION; + int yPos = baseArea.bottom() - SEPARATION - baseHeight; + + for (; elemIndicator < vecLength; ++elemIndicator) { + if (elemIndicator % buttonsPerRow == 0 && elemIndicator != 0) { + xPos = baseArea.left() + SEPARATION; + yPos -= (SEPARATION + baseHeight); + } + m_vectorButtons[elemIndicator]->move(xPos, yPos); + xPos += (SEPARATION + baseWidth); + } + break; + } + int buttonsPerRow = (baseArea.width() + SEPARATION) / (baseWidth + SEPARATION); + int buttonsPerCol = (baseArea.height() + SEPARATION) / (baseHeight + SEPARATION); + + int extraButtons = vecLength - buttonsPerRow*2 - buttonsPerCol*2; + int elemsAtCorners = extraButtons > 4 ? 4 : extraButtons; + + if (!blockedBotton) { + int addCounter = + (vecLength - elemIndicator < buttonsPerRow) ? + vecLength - elemIndicator : buttonsPerRow; + if (elemsAtCorners > 2) { + int temp = elemsAtCorners - 2; + if (oneHorizontalBlocked && temp > 1) { + temp -= 1; + } + addCounter += temp; + } + QPoint center = QPoint(baseArea.center().x(), + baseArea.bottom() + SEPARATION); + if (addCounter > buttonsPerRow) { + if (blockedLeft) { + center.setX(center.x() + (baseWidth+SEPARATION)/2); + } else if (blockedRight) { + center.setX(center.x() - (baseWidth+SEPARATION)/2); + } + } + + QVector positions = getHPoints(center, addCounter); + for (QPoint p: positions) { + m_vectorButtons[elemIndicator]->move(p); + ++elemIndicator; + } + } + if (!blockedRight && elemIndicator < vecLength) { + int addCounter = + (vecLength - elemIndicator < buttonsPerCol) ? + vecLength - elemIndicator : buttonsPerCol; + + QPoint center = QPoint(baseArea.right() + SEPARATION, + baseArea.center().y()); + QVector positions = getVPoints(center, addCounter); + for (QPoint p: positions) { + m_vectorButtons[elemIndicator]->move(p); + ++elemIndicator; + } + } + if (!blockedTop && elemIndicator < vecLength) { + int addCounter = + (vecLength - elemIndicator < buttonsPerRow) ? + vecLength - elemIndicator : buttonsPerRow; + + if (elemsAtCorners > 1 && !horizontalBlocked && !oneHorizontalBlocked) { + addCounter += 2; + } else if ((elemsAtCorners == 1 && + (!horizontalBlocked || oneHorizontalBlocked)) || + (elemsAtCorners > 1 && oneHorizontalBlocked)) { + addCounter += 1; + } + QPoint center = QPoint(baseArea.center().x(), + baseArea.top() - (SEPARATION+baseHeight)); + if (addCounter == 1 + buttonsPerRow) { + if (blockedLeft) { + center.setX(center.x() + (baseWidth+SEPARATION)/2); + } else if (blockedRight) { + center.setX(center.x() - (baseWidth+SEPARATION)/2); + } + } + QVector positions = getHPoints(center, addCounter); + for (QPoint p: positions) { + m_vectorButtons[elemIndicator]->move(p); + ++elemIndicator; + } + } + if (!blockedLeft && elemIndicator < vecLength) { + int addCounter = + (vecLength - elemIndicator < buttonsPerCol) ? + vecLength - elemIndicator : buttonsPerCol; + + if (vecLength - elemIndicator < buttonsPerRow) { + addCounter = vecLength - elemIndicator; + } + QPoint center = QPoint(baseArea.left() - (SEPARATION+baseWidth), + baseArea.center().y()); + QVector positions = getVPoints(center, addCounter); + for (QPoint p: positions) { + m_vectorButtons[elemIndicator]->move(p); + ++elemIndicator; + } + } + // if there are elements for the next cycle, increase the size of the base area + if (elemIndicator < vecLength && + !(blockedBotton && horizontalBlocked && blockedTop)) { + + if (blockedRight && !blockedLeft) { + baseArea.setX(baseArea.x() - (baseWidth+SEPARATION)); + } else if (!blockedRight && !blockedLeft) { + baseArea.setX(baseArea.x() - (baseWidth+SEPARATION)); + baseArea.setWidth(baseArea.width() + (baseWidth + SEPARATION)); + } else { + baseArea.setWidth(baseArea.width() + (baseWidth + SEPARATION)); + } + + if (blockedBotton && !blockedTop) { + baseArea.setY(baseArea.y() - (baseHeight + SEPARATION)); + } else if (!blockedTop && !blockedBotton) { + baseArea.setY(baseArea.y() - (baseHeight+SEPARATION)); + baseArea.setHeight(baseArea.height() + (baseHeight + SEPARATION)); + } else { + baseArea.setHeight(baseArea.height() + (baseHeight + SEPARATION)); + } + } + } +} + +QVector ButtonHandler::getHPoints( + const QPoint ¢er, const int elements) const { + + QVector res; + QPoint left, right; + if (elements % 2 == 0) { + left = QPoint(center.x()-m_distance + SEPARATION/2, center.y()); + right = QPoint(center.x()+SEPARATION/2, center.y()); + } else { + res.append(QPoint(center.x()-(m_distance-SEPARATION)/2, center.y())); + left = QPoint(res[0].x()-m_distance, res[0].y()); + right = QPoint(res[0].x()+m_distance, res[0].y()); + } + while (elements > res.length()) { + res.append(left); + res.append(right); + left.setX(left.x()-m_distance); + right.setX(right.x()+m_distance); + } + return res; +} + +QVector ButtonHandler::getVPoints( + const QPoint ¢er, const int elements) const { + + QVector res; + QPoint up, down; + if (elements % 2 == 0) { + up = QPoint(center.x(), center.y()-m_distance + SEPARATION/2); + down = QPoint(center.x(), center.y()+SEPARATION/2); + } else { + res.append(QPoint(center.x(), center.y()-(m_distance-SEPARATION)/2)); + up = QPoint(res[0].x(), res[0].y()-m_distance); + down = QPoint(res[0].x(), res[0].y()+m_distance); + } + while (elements > res.length()) { + res.append(up); + res.append(down); + up.setY(up.y()-m_distance); + down.setY(down.y()+m_distance); + } + return res; +} + +void ButtonHandler::setButtons(QVector