Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor setsquare to use MVC pattern #4211

Merged
merged 24 commits into from
Dec 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
30de4de
Refactor setsquare using the MVC pattern
rolandlo Oct 15, 2022
f963bdc
Minor formatting changes
rolandlo Oct 15, 2022
e78dd0e
Derive setsquare classes from geometryTool classes
rolandlo Oct 15, 2022
dc30e5d
Minor simplification
rolandlo Oct 13, 2022
acadf56
Fix highlighter and eraser strokes near geometry tool
rolandlo Oct 13, 2022
d00707c
Use CairoSaveGuards
rolandlo Oct 13, 2022
a261150
Refactor getMatrix
rolandlo Oct 13, 2022
e506cd8
Apply reviewer suggestions
rolandlo Nov 24, 2022
8256abb
Compute repaint range in GeometryTool class
rolandlo Nov 24, 2022
f106be5
Fix radius locking for setsquare
rolandlo Nov 24, 2022
adcd8f7
Fix scrolling in GeometryToolHandler
rolandlo Nov 24, 2022
2a54aec
Cache geometry tool drawing into a mask
rolandlo Nov 24, 2022
ef43310
mark origin
rolandlo Nov 26, 2022
d189777
remove undefined updateValues method
rolandlo Nov 26, 2022
ad90e50
Apply reviewer suggestions
rolandlo Nov 28, 2022
e8b2bbb
GeometryToolHandler -> GeometryToolInputHandler
rolandlo Nov 28, 2022
9e30878
Use RadialStroke and EdgeStroke
rolandlo Nov 28, 2022
36edf6d
use unique_ptr for geometry tool related classes
rolandlo Nov 28, 2022
707806b
Lock mutex in addStrokeToLayer
rolandlo Nov 28, 2022
50bb9ad
let Control own geometryToolController
rolandlo Nov 30, 2022
ca1f988
let InputContext own geometryToolInputHandler
rolandlo Nov 30, 2022
5e4c481
let Control own geometryTool
rolandlo Nov 30, 2022
5a96bcc
Account for line width in tool range
rolandlo Nov 30, 2022
bf58c4c
Apply more reviewer suggestions
rolandlo Dec 4, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
85 changes: 62 additions & 23 deletions src/core/control/Control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "control/ClipboardHandler.h" // for Clip...
#include "control/RecentManager.h" // for Rece...
#include "control/ScrollHandler.h" // for Scro...
#include "control/SetsquareController.h" // for Sets...
#include "control/Tool.h" // for Tool
#include "control/ToolHandler.h" // for Tool...
#include "control/jobs/AutosaveJob.h" // for Auto...
Expand Down Expand Up @@ -50,7 +51,9 @@
#include "gui/dialog/SettingsDialog.h" // for Sett...
#include "gui/dialog/ToolbarManageDialog.h" // for Tool...
#include "gui/dialog/toolbarCustomize/ToolbarDragDropHandler.h" // for Tool...
#include "gui/inputdevices/GeometryToolInputHandler.h" // for Geom...
#include "gui/inputdevices/HandRecognition.h" // for Hand...
#include "gui/inputdevices/SetsquareInputHandler.h" // for Sets...
#include "gui/sidebar/Sidebar.h" // for Sidebar
#include "gui/toolbarMenubar/ToolMenuHandler.h" // for Tool...
#include "gui/toolbarMenubar/model/ToolbarData.h" // for Tool...
Expand Down Expand Up @@ -87,6 +90,7 @@
#include "util/serializing/InputStreamException.h" // for Inpu...
#include "util/serializing/ObjectInputStream.h" // for Obje...
#include "view/SetsquareView.h" // for Sets...
#include "view/overlays/OverlayView.h" // for Over...

#include "CrashHandler.h" // for emer...
#include "FullscreenHandler.h" // for Full...
Expand Down Expand Up @@ -344,7 +348,7 @@ void Control::initWindow(MainWindow* win) {

fireActionSelected(GROUP_SNAPPING, settings->isSnapRotation() ? ACTION_ROTATION_SNAPPING : ACTION_NONE);
fireActionSelected(GROUP_GRID_SNAPPING, settings->isSnapGrid() ? ACTION_GRID_SNAPPING : ACTION_NONE);
fireActionSelected(GROUP_SETSQUARE, ACTION_NONE);
fireActionSelected(GROUP_GEOMETRY_TOOL, ACTION_NONE);
}

auto Control::autosaveCallback(Control* control) -> bool {
Expand Down Expand Up @@ -645,23 +649,15 @@ void Control::actionPerformed(ActionType type, ActionGroup group, GtkToolButton*
selectTool(TOOL_HAND);
}
break;
case ACTION_SETSQUARE:
if (!this->win->getXournal()->getSetsquareView()) {
// bring up setsquare in page center
auto setsquare = std::make_unique<Setsquare>();
auto view = win->getXournal()->getViewFor(getCurrentPageNo());
std::unique_ptr<SetsquareView> setsquareView = std::make_unique<SetsquareView>(view, setsquare);
if (!view) {
setsquareView.reset(nullptr);
}
this->win->getXournal()->setSetsquareView(std::move(setsquareView));
fireActionSelected(GROUP_SETSQUARE, ACTION_SETSQUARE);
} else {
// hide setsquare
this->win->getXournal()->resetSetsquareView();
case ACTION_SETSQUARE: {
bool needsNewSetsquare = !this->geometryToolController ||
this->geometryToolController->getType() != GeometryToolType::SETSQUARE;
resetGeometryTool();
if (needsNewSetsquare) {
makeGeometryTool(GeometryToolType::SETSQUARE);
}
win->getXournal()->repaintSetsquare(true);
break;
}
case ACTION_TOOL_FLOATING_TOOLBOX:
if (enabled) {
selectTool(TOOL_FLOATING_TOOLBOX);
Expand Down Expand Up @@ -1065,6 +1061,45 @@ void Control::actionPerformed(ActionType type, ActionGroup group, GtkToolButton*
}
}

void Control::makeGeometryTool(GeometryToolType tool) {
auto view = this->win->getXournal()->getViewFor(getCurrentPageNo());
auto* xournal = GTK_XOURNAL(this->win->getXournal()->getWidget());
switch (tool) {
case SETSQUARE: {
auto setsquare = new Setsquare();
view->addOverlayView(std::make_unique<xoj::view::SetsquareView>(setsquare, view, zoom));
this->geometryTool = std::unique_ptr<GeometryTool>(setsquare);
this->geometryToolController = std::make_unique<SetsquareController>(view, setsquare);
std::unique_ptr<GeometryToolInputHandler> geometryToolInputHandler =
std::make_unique<SetsquareInputHandler>(this->win->getXournal(), geometryToolController.get());
geometryToolInputHandler->registerToPool(setsquare->getHandlerPool());
xournal->input->setGeometryToolInputHandler(std::move(geometryToolInputHandler));
fireActionSelected(GROUP_GEOMETRY_TOOL, ACTION_SETSQUARE);
geometryTool->notify();
break;
}
default:
g_warning("Unknown geometry tool type %d", tool);
}
}

void Control::resetGeometryTool() {
Range rg;
bool hasGeometryTool = false;
if (this->geometryTool) {
hasGeometryTool = true;
rg = this->geometryTool->getToolRange(true);
}
this->geometryToolController.reset();
this->geometryTool.reset();
auto* xournal = GTK_XOURNAL(this->win->getXournal()->getWidget());
xournal->input->resetGeometryToolInputHandler();
if (win && hasGeometryTool) {
(win->getXournal()->getViewFor(getCurrentPageNo()))->rerenderRange(rg);
}
fireActionSelected(GROUP_GEOMETRY_TOOL, ACTION_NONE);
}

auto Control::copy() -> bool {
if (this->win && this->win->getXournal()->copy()) {
return true;
Expand Down Expand Up @@ -1363,11 +1398,15 @@ void Control::updateDeletePageButton() {
void Control::deletePage() {
clearSelectionEndText();

// if the current page contains the Setsquare, reset it
// if the current page contains the geometry tool, reset it
size_t pNr = getCurrentPageNo();
auto setsquareView = win->getXournal()->getSetsquareView();
if (setsquareView && doc->indexOf(setsquareView->getPage()) == pNr) {
win->getXournal()->resetSetsquareView();
if (geometryToolController) {
doc->lock();
auto page = doc->indexOf(geometryToolController->getPage());
doc->unlock();
if (page == pNr) {
resetGeometryTool();
}
}
// don't allow delete pages if we have less than 2 pages,
// so we can be (more or less) sure there is at least one page.
Expand Down Expand Up @@ -2247,8 +2286,8 @@ auto Control::openFile(fs::path filepath, int scrollToPage, bool forceOpen) -> b
parentFolderPath = missingFilePath.parent_path().string();
filename = missingFilePath.filename().string();
#else
// since POSIX systems detect the whole Windows path as a filename, this checks whether missingFilePath contains
// a Windows path
// since POSIX systems detect the whole Windows path as a filename, this checks whether missingFilePath
// contains a Windows path
std::regex regex(R"([A-Z]:\\(?:.*\\)*(.*))");
std::cmatch matchInfo;

Expand Down Expand Up @@ -2785,7 +2824,7 @@ auto Control::close(const bool allowDestroy, const bool allowCancel) -> bool {
if (allowDestroy && discard) {
this->closeDocument();
}
win->getXournal()->resetSetsquareView();
resetGeometryTool();
return true;
}

Expand Down
8 changes: 8 additions & 0 deletions src/core/control/Control.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "enums/ActionGroup.enum.h" // for ActionGroup
#include "enums/ActionType.enum.h" // for ActionType
#include "model/DocumentHandler.h" // for DocumentHandler
#include "model/GeometryTool.h" // for GeometryTool
#include "model/PageRef.h" // for PageRef
#include "undo/UndoRedoHandler.h" // for UndoRedoHandler (ptr only)

Expand All @@ -35,6 +36,7 @@
#include "ToolHandler.h" // for ToolListener
#include "filesystem.h" // for path

class GeometryToolController;
class AudioController;
class FullscreenHandler;
class Sidebar;
Expand Down Expand Up @@ -349,6 +351,9 @@ class Control:
bool loadPdf(fs::path const& filepath, int scrollToPage);

private:
void makeGeometryTool(GeometryToolType tool);
void resetGeometryTool();

/**
* "Closes" the document, preparing the editor for a new document.
*/
Expand Down Expand Up @@ -441,6 +446,9 @@ class Control:

LayerController* layerController;

std::unique_ptr<GeometryTool> geometryTool;
std::unique_ptr<GeometryToolController> geometryToolController;

/**
* Manage all Xournal++ plugins
*/
Expand Down
123 changes: 123 additions & 0 deletions src/core/control/GeometryToolController.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#include "GeometryToolController.h"

#include "control/Control.h"
#include "control/layer/LayerController.h"
#include "gui/XournalView.h"
#include "gui/XournalppCursor.h"
#include "model/Document.h"
#include "model/GeometryTool.h"
#include "model/Stroke.h"
#include "model/XojPage.h"
#include "undo/InsertUndoAction.h"

using xoj::util::Rectangle;

constexpr double MARK_SIZE = 2.;

GeometryToolController::GeometryToolController(XojPageView* view, GeometryTool* geometryTool):
view(view), geometryTool(geometryTool) {}

GeometryToolController::~GeometryToolController() = default;

void GeometryToolController::translate(double x, double y) {
geometryTool->setTranslationX(geometryTool->getTranslationX() + x);
geometryTool->setTranslationY(geometryTool->getTranslationY() + y);
geometryTool->notify();
}

void GeometryToolController::rotate(double da, double cx, double cy) {
geometryTool->setRotation(geometryTool->getRotation() + da);
const auto offsetX = geometryTool->getTranslationX() - cx;
const auto offsetY = geometryTool->getTranslationY() - cy;
const auto mx = offsetX * cos(da) - offsetY * sin(da);
const auto my = offsetX * sin(da) + offsetY * cos(da);
geometryTool->setTranslationX(cx + mx);
geometryTool->setTranslationY(cy + my);
geometryTool->notify();
}

void GeometryToolController::scale(double f, double cx, double cy) {
geometryTool->setHeight(geometryTool->getHeight() * f);
const auto offsetX = geometryTool->getTranslationX() - cx;
const auto offsetY = geometryTool->getTranslationY() - cy;
const auto mx = offsetX * f;
const auto my = offsetY * f;
geometryTool->setTranslationX(cx + mx);
geometryTool->setTranslationY(cy + my);
geometryTool->notify(true);
}

void GeometryToolController::markPoint(double x, double y) {
const auto control = view->getXournal()->getControl();
const auto h = control->getToolHandler();
Stroke* cross = new Stroke();
cross->setWidth(h->getToolThickness(TOOL_PEN)[TOOL_SIZE_FINE]);
cross->setColor(h->getTool(TOOL_PEN).getColor());
cross->addPoint(Point(x + MARK_SIZE, y + MARK_SIZE));
cross->addPoint(Point(x - MARK_SIZE, y - MARK_SIZE));
cross->addPoint(Point(x, y));
cross->addPoint(Point(x + MARK_SIZE, y - MARK_SIZE));
cross->addPoint(Point(x - MARK_SIZE, y + MARK_SIZE));

const auto doc = control->getDocument();
const auto page = view->getPage();
doc->lock();
control->getLayerController()->ensureLayerExists(page);
const auto layer = page->getSelectedLayer();
layer->addElement(cross);
doc->unlock();

const auto undo = control->getUndoRedoHandler();
undo->addUndoAction(std::make_unique<InsertUndoAction>(page, layer, cross));

const Rectangle<double> rect{cross->getX(), cross->getY(), cross->getElementWidth(), cross->getElementHeight()};
view->rerenderRect(rect.x, rect.y, rect.width, rect.height);
}

void GeometryToolController::addStrokeToLayer() {
bhennion marked this conversation as resolved.
Show resolved Hide resolved
const auto xournal = view->getXournal();
const auto control = xournal->getControl();
const auto doc = control->getDocument();
const auto page = view->getPage();

doc->lock();
control->getLayerController()->ensureLayerExists(page);
const auto layer = page->getSelectedLayer();
layer->addElement(stroke.get());
doc->unlock();
const auto undo = control->getUndoRedoHandler();
undo->addUndoAction(std::make_unique<InsertUndoAction>(page, layer, stroke.get()));
const Rectangle<double> rect{stroke->getX(), stroke->getY(), stroke->getElementWidth(), stroke->getElementHeight()};
view->rerenderRect(rect.x, rect.y, rect.width, rect.height);
stroke.release();
geometryTool->setStroke(nullptr);
xournal->getCursor()->updateCursor();
}

void GeometryToolController::initializeStroke() {
const auto h = view->getXournal()->getControl()->getToolHandler();
stroke = std::make_unique<Stroke>();
geometryTool->setStroke(stroke.get());
stroke->setWidth(h->getThickness());
stroke->setColor(h->getColor());
stroke->setFill(h->getFill());
stroke->setLineStyle(h->getLineStyle());
switch (h->getToolType()) {
case TOOL_PEN:
stroke->setToolType(StrokeTool::PEN);
break;
case TOOL_HIGHLIGHTER:
stroke->setToolType(StrokeTool::HIGHLIGHTER);
break;
case TOOL_ERASER:
stroke->setToolType(StrokeTool::ERASER);
break;
default:
g_warning("Unhandled tool when initializing stroke in geometry tool controller");
break;
}
}

auto GeometryToolController::getPage() const -> const PageRef { return view->getPage(); }

auto GeometryToolController::getView() const -> XojPageView* { return view; }