NC/Optimisations and bug fixes for objects editing (#1600)
* Optimise undo/redo for thickness, do not save every change on mouse wheel, save just the result (cherry picked from commit c0bd74790e086dcde1c242a31e27f992a04c07e2) * fix - In some cases undo/redo stack has excess steps (root cause is in the start move object event on a small not noticeable mouse move) (cherry picked from commit 912f39f38083e368979f34ef14821979c34482bb) * fix - It is impossible to remove an object using the "Undo the latest modification" button on second attempt (full undo, draw something, full undo again) (cherry picked from commit a7f77a130a497ac6fdecd59eb43c889dcc6cbe1a) * fix - Picked font family in the text editing tool is applied to the autoincrement tool (cherry picked from commit 11c5eb29b1078bd6aba91fe7a74c2682767ad47c) * Add git hash to version in the about dialog (cherry picked from commit b4dbf52b3217b51614100bd307046772a37dc484) * Add configuration option to limit undo steps (cherry picked from commit f13cbecabb172060b196a535348f145457ad2f0f) * Object delete operation is not registered on the undo stack (cherry picked from commit 5c966cb5d3702a4d735dd542ad03a80899250b4a) * fix - Unable to draw an object from second attempt after ColorPicker was called (cherry picked from commit 49a119886fec253376703e8aa2386e16bc23cbcf) * fix - App freezes and then crashes when changing object line thickness via Active thickness slider in the tool settings (cherry picked from commit 26fd64f1c333f70c67282630362cbc5fc8427a39) * fix - set min and max values for thickness slider to 1-100 (cherry picked from commit 6d8661666e4e199a3c29f991d52bef73ec36129c) * fix - Crash on Move Tool button with an active Text editor (cherry picked from commit 461f95da3afda56c0e9693e768e86b18d056eecc) * fix - Text is not modified when picking it as object in the list (cherry picked from commit 366bb0928b430d442dc67299353f7dc5ceb743b4) * fix - Text modification cannot be undone fix - Object that was created after the text object disappears after undo editing text (cherry picked from commit 79b2fb92aca65b177cffb386db141d30551a2b1c) * fix - Text is not saved if picking any object in the objects list without clicking at the empty space (cherry picked from commit 4679a744a3d2498fe27379f89d48b347a34ae0dc) * Last available undo step reset everything to the beginning (cherry picked from commit 4af7423d00cfaa9feabc905400aa3ac30fc4a3ea) * Missed changes (cherry-pick) for switching ColorPicker behaviour (right mouse click and hold to right mouse click and left click) Co-authored-by: Yuriy Puchkov <yuriy.puchkov@namecheap.com>
This commit is contained in:
@@ -31,12 +31,13 @@
|
||||
#include <QPainter>
|
||||
#include <QScreen>
|
||||
#include <QShortcut>
|
||||
#include <QUndoView>
|
||||
#include <draggablewidgetmaker.h>
|
||||
|
||||
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
#define MOUSE_DISTANCE_TO_START_MOVING 3
|
||||
|
||||
// CaptureWidget is the main component used to capture the screen. It contains
|
||||
// an area of selection with its respective buttons.
|
||||
|
||||
@@ -65,7 +66,11 @@ CaptureWidget::CaptureWidget(uint id,
|
||||
, m_lastPressedRedo(false)
|
||||
, m_panel(nullptr)
|
||||
, m_selection(nullptr)
|
||||
, m_existingObjectIsChanged(false)
|
||||
, m_startMove(false)
|
||||
{
|
||||
m_undoStack.setUndoLimit(ConfigHandler().undoLimit() + 1);
|
||||
|
||||
// Base config of the widget
|
||||
m_eventFilter = new HoverEventFilter(this);
|
||||
connect(m_eventFilter,
|
||||
@@ -272,9 +277,6 @@ bool CaptureWidget::commitCurrentTool()
|
||||
m_toolWidget) {
|
||||
pushToolToStack();
|
||||
}
|
||||
if (m_activeTool) {
|
||||
m_activeTool->setEditMode(false);
|
||||
}
|
||||
releaseActiveTool();
|
||||
return true;
|
||||
}
|
||||
@@ -297,6 +299,8 @@ void CaptureWidget::deleteToolWidgetOrClose()
|
||||
m_toolWidget->close();
|
||||
delete m_toolWidget;
|
||||
m_toolWidget = nullptr;
|
||||
} else if (m_colorPicker && m_colorPicker->isVisible()) {
|
||||
m_colorPicker->hide();
|
||||
} else {
|
||||
// close CaptureWidget
|
||||
close();
|
||||
@@ -306,6 +310,12 @@ void CaptureWidget::deleteToolWidgetOrClose()
|
||||
void CaptureWidget::releaseActiveTool()
|
||||
{
|
||||
if (m_activeTool) {
|
||||
if (m_activeTool->editMode()) {
|
||||
m_activeTool->setEditMode(false);
|
||||
if (m_activeTool->isChanged()) {
|
||||
pushObjectsStateToUndoStack();
|
||||
}
|
||||
}
|
||||
if (-1 == m_panel->activeLayerIndex() && m_activeButton) {
|
||||
// delete tool if no active selection, otherwise object shouldn't be
|
||||
// deleted, because it is in undo/redo stack
|
||||
@@ -400,8 +410,7 @@ bool CaptureWidget::startDrawObjectTool(const QPoint& pos)
|
||||
// point and shouldn't wait for second point and move event
|
||||
m_activeTool->drawEnd(m_context.mousePos);
|
||||
m_captureToolObjects.append(m_activeTool);
|
||||
m_undoStack.push(
|
||||
new ModificationCommand(this, m_captureToolObjects));
|
||||
pushObjectsStateToUndoStack();
|
||||
releaseActiveTool();
|
||||
m_mouseIsClicked = false;
|
||||
}
|
||||
@@ -410,6 +419,16 @@ bool CaptureWidget::startDrawObjectTool(const QPoint& pos)
|
||||
return false;
|
||||
}
|
||||
|
||||
void CaptureWidget::pushObjectsStateToUndoStack()
|
||||
{
|
||||
m_existingObjectIsChanged = false;
|
||||
// push zero state to be able to do a complete undo
|
||||
if (m_undoStack.count() == 0 || m_undoStack.index() == 0) {
|
||||
m_undoStack.push(new ModificationCommand(this, m_captureToolObjects));
|
||||
}
|
||||
m_undoStack.push(new ModificationCommand(this, m_captureToolObjects));
|
||||
}
|
||||
|
||||
int CaptureWidget::selectToolItemAtPos(const QPoint& pos)
|
||||
{
|
||||
// Try to select existing tool, "-1" - no active tool
|
||||
@@ -434,8 +453,14 @@ int CaptureWidget::selectToolItemAtPos(const QPoint& pos)
|
||||
|
||||
void CaptureWidget::mousePressEvent(QMouseEvent* e)
|
||||
{
|
||||
m_startMove = false;
|
||||
m_startMovePos = QPoint();
|
||||
m_dragStartPoint = m_mousePressedPos = e->pos();
|
||||
m_activeToolOffsetToMouseOnStart = QPoint();
|
||||
if (m_colorPicker->isVisible()) {
|
||||
updateCursor();
|
||||
return;
|
||||
}
|
||||
|
||||
// reset object selection if capture area selection is active
|
||||
if (m_selection->getMouseSide(e->pos()) != SelectionWidget::NO_SIDE) {
|
||||
@@ -443,6 +468,9 @@ void CaptureWidget::mousePressEvent(QMouseEvent* e)
|
||||
}
|
||||
|
||||
if (e->button() == Qt::RightButton) {
|
||||
if (m_activeTool && m_activeTool->editMode()) {
|
||||
return;
|
||||
}
|
||||
showColorPicker(m_mousePressedPos);
|
||||
} else if (e->button() == Qt::LeftButton) {
|
||||
m_showInitialMsg = false;
|
||||
@@ -471,8 +499,8 @@ void CaptureWidget::mousePressEvent(QMouseEvent* e)
|
||||
}
|
||||
}
|
||||
|
||||
// Commit current tool if it has edit widget and mouse click is outside of
|
||||
// it
|
||||
// Commit current tool if it has edit widget and mouse click is outside
|
||||
// of it
|
||||
if (m_toolWidget && !m_toolWidget->geometry().contains(e->pos())) {
|
||||
commitCurrentTool();
|
||||
m_panel->setToolWidget(nullptr);
|
||||
@@ -508,18 +536,34 @@ void CaptureWidget::mouseMoveEvent(QMouseEvent* e)
|
||||
m_context.mousePos = e->pos();
|
||||
bool symmetryMod = qApp->keyboardModifiers() & Qt::ShiftModifier;
|
||||
|
||||
int activeLayerIndex = m_panel->activeLayerIndex();
|
||||
int activeLayerIndex = -1;
|
||||
if (m_mouseIsClicked) {
|
||||
activeLayerIndex = m_panel->activeLayerIndex();
|
||||
}
|
||||
if (m_mouseIsClicked && !m_activeButton && activeLayerIndex >= 0) {
|
||||
// Move existing object
|
||||
QPointer<CaptureTool> activeTool =
|
||||
m_captureToolObjects.at(activeLayerIndex);
|
||||
if (m_activeToolOffsetToMouseOnStart.isNull()) {
|
||||
setCursor(Qt::OpenHandCursor);
|
||||
m_activeToolOffsetToMouseOnStart = e->pos() - *activeTool->pos();
|
||||
if (!m_startMove) {
|
||||
// Check for the minimal offset to start moving an object
|
||||
if (m_startMovePos.isNull()) {
|
||||
m_startMovePos = e->pos();
|
||||
}
|
||||
if ((e->pos() - m_startMovePos).manhattanLength() >
|
||||
MOUSE_DISTANCE_TO_START_MOVING) {
|
||||
m_startMove = true;
|
||||
}
|
||||
}
|
||||
if (m_startMove) {
|
||||
QPointer<CaptureTool> activeTool =
|
||||
m_captureToolObjects.at(activeLayerIndex);
|
||||
if (m_activeToolOffsetToMouseOnStart.isNull()) {
|
||||
setCursor(Qt::OpenHandCursor);
|
||||
m_activeToolOffsetToMouseOnStart =
|
||||
e->pos() - *activeTool->pos();
|
||||
}
|
||||
activeTool->move(e->pos() - m_activeToolOffsetToMouseOnStart);
|
||||
m_activeToolIsMoved = true;
|
||||
drawToolsData(false);
|
||||
}
|
||||
activeTool->move(e->pos() - m_activeToolOffsetToMouseOnStart);
|
||||
m_activeToolIsMoved = true;
|
||||
drawToolsData(false);
|
||||
} else if (m_mouseIsClicked &&
|
||||
(!m_activeButton ||
|
||||
(m_activeButton && m_activeButton->tool() &&
|
||||
@@ -627,16 +671,14 @@ void CaptureWidget::mouseMoveEvent(QMouseEvent* e)
|
||||
|
||||
void CaptureWidget::mouseReleaseEvent(QMouseEvent* e)
|
||||
{
|
||||
if (e->button() == Qt::RightButton || m_colorPicker->isVisible()) {
|
||||
if (e->button() == Qt::LeftButton && m_colorPicker->isVisible()) {
|
||||
// Color picker
|
||||
m_colorPicker->hide();
|
||||
if (!m_context.color.isValid()) {
|
||||
m_context.color = ConfigHandler().drawColorValue();
|
||||
m_panel->show();
|
||||
} else {
|
||||
// push current state to the undo stack
|
||||
m_undoStack.push(
|
||||
new ModificationCommand(this, m_captureToolObjects));
|
||||
} else if (m_panel->activeLayerIndex() >= 0) {
|
||||
pushObjectsStateToUndoStack();
|
||||
}
|
||||
} else if (m_mouseIsClicked) {
|
||||
if (m_activeTool) {
|
||||
@@ -649,9 +691,7 @@ void CaptureWidget::mouseReleaseEvent(QMouseEvent* e)
|
||||
}
|
||||
} else {
|
||||
if (m_activeToolIsMoved) {
|
||||
// push current state to the undo stack
|
||||
m_undoStack.push(
|
||||
new ModificationCommand(this, m_captureToolObjects));
|
||||
pushObjectsStateToUndoStack();
|
||||
}
|
||||
|
||||
// Try to select existing tool if it was in the selection area but
|
||||
@@ -786,17 +826,15 @@ void CaptureWidget::wheelEvent(QWheelEvent* e)
|
||||
m_activeButton->tool()->showMousePreview()) {
|
||||
update();
|
||||
}
|
||||
emit thicknessChanged(m_context.thickness);
|
||||
|
||||
// update selected object thickness
|
||||
// Reset selection if mouse pos is not in selection area
|
||||
auto toolItem = activeToolObject();
|
||||
if (toolItem) {
|
||||
toolItem->thicknessChanged(m_context.thickness);
|
||||
|
||||
// TODO - save thickness update, but not immediately
|
||||
m_undoStack.push(new ModificationCommand(this, m_captureToolObjects));
|
||||
m_existingObjectIsChanged = true;
|
||||
}
|
||||
emit thicknessChanged(m_context.thickness);
|
||||
}
|
||||
|
||||
void CaptureWidget::resizeEvent(QResizeEvent* e)
|
||||
@@ -965,8 +1003,12 @@ void CaptureWidget::setState(CaptureToolButton* b)
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_toolWidget && m_activeTool && m_activeTool->isValid()) {
|
||||
pushToolToStack();
|
||||
if (m_toolWidget && m_activeTool) {
|
||||
if (m_activeTool->isValid()) {
|
||||
pushToolToStack();
|
||||
} else {
|
||||
releaseActiveTool();
|
||||
}
|
||||
}
|
||||
if (m_activeButton != b) {
|
||||
processTool(b->tool());
|
||||
@@ -1072,16 +1114,6 @@ void CaptureWidget::handleButtonSignal(CaptureTool::Request r)
|
||||
m_toolWidget->setFocus();
|
||||
}
|
||||
break;
|
||||
case CaptureTool::REQ_ADD_CHILD_WINDOW:
|
||||
if (!m_activeTool) {
|
||||
break;
|
||||
} else {
|
||||
QWidget* w = m_activeTool->widget();
|
||||
connect(
|
||||
this, &CaptureWidget::destroyed, w, &QWidget::deleteLater);
|
||||
w->show();
|
||||
}
|
||||
break;
|
||||
case CaptureTool::REQ_ADD_EXTERNAL_WIDGETS:
|
||||
if (!m_activeTool) {
|
||||
break;
|
||||
@@ -1133,6 +1165,15 @@ void CaptureWidget::setDrawColor(const QColor& c)
|
||||
|
||||
void CaptureWidget::updateActiveLayer(const int& layer)
|
||||
{
|
||||
// TODO - refactor this part, make all objects to work with
|
||||
// m_activeTool->isChanged() and remove m_existingObjectIsChanged
|
||||
if (m_activeTool && m_activeTool->nameID() == ToolType::TEXT &&
|
||||
m_activeTool->isChanged()) {
|
||||
commitCurrentTool();
|
||||
}
|
||||
if (m_existingObjectIsChanged) {
|
||||
pushObjectsStateToUndoStack();
|
||||
}
|
||||
drawToolsData(false, true);
|
||||
}
|
||||
|
||||
@@ -1158,6 +1199,7 @@ void CaptureWidget::removeToolObject(int index)
|
||||
}
|
||||
m_context.circleCount = circleCount;
|
||||
}
|
||||
pushObjectsStateToUndoStack();
|
||||
drawToolsData();
|
||||
}
|
||||
}
|
||||
@@ -1166,13 +1208,14 @@ void CaptureWidget::setDrawThickness(const int& t)
|
||||
{
|
||||
m_context.thickness = qBound(1, t, 100);
|
||||
ConfigHandler().setDrawThickness(m_context.thickness);
|
||||
emit thicknessChanged(m_context.thickness);
|
||||
|
||||
auto toolItem = activeToolObject();
|
||||
if (toolItem) {
|
||||
// Change thickness
|
||||
emit toolItem->thicknessChanged(t);
|
||||
drawToolsData(false, true);
|
||||
} else {
|
||||
emit thicknessChanged(m_context.thickness);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1375,12 +1418,12 @@ void CaptureWidget::updateCursor()
|
||||
|
||||
void CaptureWidget::pushToolToStack()
|
||||
{
|
||||
// push zero state to be able to do a complete undo
|
||||
if (m_undoStack.count() == 0) {
|
||||
m_undoStack.push(new ModificationCommand(this, m_captureToolObjects));
|
||||
}
|
||||
|
||||
// append current tool to the new state
|
||||
bool isChanged = true;
|
||||
if (m_activeTool && m_activeTool->editMode()) {
|
||||
m_activeTool->setEditMode(false);
|
||||
isChanged = m_activeTool->isChanged();
|
||||
}
|
||||
if (m_activeTool && m_activeButton) {
|
||||
disconnect(this,
|
||||
&CaptureWidget::colorChanged,
|
||||
@@ -1394,13 +1437,13 @@ void CaptureWidget::pushToolToStack()
|
||||
disconnect(m_panel->toolWidget(), nullptr, m_activeTool, nullptr);
|
||||
}
|
||||
|
||||
m_activeTool->setEditMode(false);
|
||||
m_captureToolObjects.append(m_activeTool);
|
||||
releaseActiveTool();
|
||||
}
|
||||
|
||||
// push current state to the undo stack
|
||||
m_undoStack.push(new ModificationCommand(this, m_captureToolObjects));
|
||||
if (isChanged) {
|
||||
pushObjectsStateToUndoStack();
|
||||
}
|
||||
}
|
||||
|
||||
void CaptureWidget::drawToolsData(bool updateLayersPanel, bool drawSelection)
|
||||
@@ -1530,6 +1573,11 @@ void CaptureWidget::undo()
|
||||
m_lastPressedUndo = true;
|
||||
m_lastPressedRedo = false;
|
||||
m_undoStack.undo();
|
||||
if (m_undoStack.index() == 0 && m_captureToolObjects.size() > 0) {
|
||||
m_lastPressedUndo = false;
|
||||
m_captureToolObjects.clear();
|
||||
drawToolsData();
|
||||
}
|
||||
}
|
||||
|
||||
void CaptureWidget::redo()
|
||||
|
||||
Reference in New Issue
Block a user