Skip to content

Commit c8f6dc0

Browse files
committed
Render guides via Rectangle
This brings the FPS up when panning (on a MacBook) by about 5. Helps with #160.
1 parent 82a211a commit c8f6dc0

15 files changed

+355
-282
lines changed

app/qml/qml.qbs

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Group {
3838
"ui/ErrorPopup.qml",
3939
"ui/FillToolMenu.qml",
4040
"ui/FpsCounter.qml",
41+
"ui/Guide.qml",
4142
"ui/HexColourRowLayout.qml",
4243
"ui/HorizontalGradientRectangle.qml",
4344
"ui/HslSimplePicker.qml",

app/qml/qml.qrc

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
<file>ui/ErrorPopup.qml</file>
3434
<file>ui/FillToolMenu.qml</file>
3535
<file>ui/FpsCounter.qml</file>
36+
<file>ui/Guide.qml</file>
3637
<file>ui/HexColourRowLayout.qml</file>
3738
<file>ui/HorizontalGradientRectangle.qml</file>
3839
<file>ui/HslSimplePicker.qml</file>

app/qml/ui/CanvasPaneRepeater.qml

+19-5
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ Repeater {
6969
visible: isFirstPane || canvas.splitScreen
7070
clip: true
7171

72+
required property int index
73+
7274
readonly property bool isFirstPane: paneIndex === 0
7375
readonly property string indexAsWord: isFirstPane ? "first" : "second"
7476

@@ -79,13 +81,25 @@ Repeater {
7981
z: -1
8082
}
8183

82-
GuidesItem {
83-
id: guidesItem
84-
anchors.fill: parent
84+
GuideModel {
85+
id: guideModel
86+
project: root.canvas.project
8587
canvas: root.canvas
88+
}
89+
90+
Repeater {
91+
model: root.canvas.guidesVisible ? guideModel : null
92+
delegate: Guide {
93+
pane: paneItem.pane
94+
}
95+
}
96+
97+
// Draws a guide being dragged out from the ruler.
98+
Guide {
8699
pane: paneItem.pane
87-
paneIndex: paneItem.paneIndex
88-
visible: root.canvas.guidesVisible
100+
orientation: root.canvas.pressedRuler?.orientation ?? Qt.Horizontal
101+
position: horizontal ? root.canvas.cursorSceneY : root.canvas.cursorSceneX
102+
visible: root.canvas.pressedRuler
89103
}
90104

91105
NotesItem {

app/qml/ui/Guide.qml

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import QtQuick
2+
3+
import App
4+
5+
Rectangle {
6+
x: horizontal ? 0 : (pane.integerZoomLevel * position) + pane.integerOffset.x
7+
y: horizontal ? (pane.integerZoomLevel * position) + pane.integerOffset.y : 0
8+
width: horizontal ? parent.width : 1
9+
height: horizontal ? 1 : parent.height
10+
color: "cyan"
11+
// TODO: hide if not visible
12+
13+
required property CanvasPane pane
14+
15+
// From model.
16+
required property int orientation
17+
required property int position
18+
19+
readonly property bool horizontal: orientation === Qt.Horizontal
20+
}

app/qml/ui/TilesetTypeCanvas.qml

+19-5
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ TileCanvas {
4444
anchors.fill: parent
4545
visible: index === 0 || canvas.splitScreen
4646

47+
required property int index
48+
4749
readonly property bool isFirstPane: paneIndex === 0
4850
readonly property string indexAsWord: isFirstPane ? "first" : "second"
4951

@@ -55,13 +57,25 @@ TileCanvas {
5557
z: -1
5658
}
5759

58-
GuidesItem {
59-
id: guidesItem
60-
anchors.fill: parent
60+
GuideModel {
61+
id: guideModel
62+
project: tileCanvas.project
6163
canvas: tileCanvas
64+
}
65+
66+
Repeater {
67+
model: tileCanvas.guidesVisible ? guideModel : null
68+
delegate: Guide {
69+
pane: paneItem.pane
70+
}
71+
}
72+
73+
// Draws a guide being dragged out from the ruler.
74+
Guide {
6275
pane: paneItem.pane
63-
paneIndex: paneItem.paneIndex
64-
visible: tileCanvas.guidesVisible
76+
orientation: tileCanvas.pressedRuler?.orientation ?? Qt.Horizontal
77+
position: horizontal ? tileCanvas.cursorSceneY : tileCanvas.cursorSceneX
78+
visible: tileCanvas.pressedRuler
6579
}
6680

6781
Ruler {

lib/guidemodel.cpp

+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
/*
2+
Copyright 2021, Mitch Curtis
3+
4+
This file is part of Slate.
5+
6+
Slate is free software: you can redistribute it and/or modify
7+
it under the terms of the GNU General Public License as published by
8+
the Free Software Foundation, either version 3 of the License, or
9+
(at your option) any later version.
10+
11+
Slate is distributed in the hope that it will be useful,
12+
but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
GNU General Public License for more details.
15+
16+
You should have received a copy of the GNU General Public License
17+
along with Slate. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
#include "guidemodel.h"
21+
22+
#include <QLoggingCategory>
23+
24+
#include "imagecanvas.h"
25+
#include "project.h"
26+
27+
Q_LOGGING_CATEGORY(lcGuideModel, "app.guideModel")
28+
29+
GuideModel::GuideModel(QObject *parent) :
30+
QAbstractListModel(parent)
31+
{
32+
}
33+
34+
GuideModel::~GuideModel()
35+
{
36+
}
37+
38+
Project *GuideModel::project() const
39+
{
40+
return mProject;
41+
}
42+
43+
void GuideModel::setProject(Project *project)
44+
{
45+
qCDebug(lcGuideModel) << "project changed to" << project;
46+
47+
if (project == mProject)
48+
return;
49+
50+
if (mProject)
51+
mProject->disconnect(this);
52+
53+
beginResetModel();
54+
55+
mProject = project;
56+
57+
endResetModel();
58+
emit projectChanged();
59+
60+
if (mProject) {
61+
connect(mProject, &Project::preGuidesAdded, this, &GuideModel::onPreGuidesAdded);
62+
connect(mProject, &Project::postGuidesAdded, this, &GuideModel::onPostGuidesAdded);
63+
connect(mProject, &Project::guideMoved, this, &GuideModel::onGuideMoved);
64+
connect(mProject, &Project::preGuidesRemoved, this, &GuideModel::onPreGuidesRemoved);
65+
connect(mProject, &Project::postGuidesRemoved, this, &GuideModel::onPostGuidesRemoved);
66+
}
67+
}
68+
69+
ImageCanvas *GuideModel::canvas() const
70+
{
71+
return mCanvas;
72+
}
73+
74+
void GuideModel::setCanvas(ImageCanvas *canvas)
75+
{
76+
if (canvas == mCanvas)
77+
return;
78+
79+
if (mCanvas)
80+
disconnect(mCanvas, &ImageCanvas::existingGuideDragged, this, &GuideModel::onGuideMoved);
81+
82+
mCanvas = canvas;
83+
84+
if (mCanvas)
85+
connect(mCanvas, &ImageCanvas::existingGuideDragged, this, &GuideModel::onGuideMoved);
86+
87+
emit canvasChanged();
88+
}
89+
90+
QVariant GuideModel::data(const QModelIndex &index, int role) const
91+
{
92+
if (!mProject || !checkIndex(index, CheckIndexOption::IndexIsValid))
93+
return QVariant();
94+
95+
const Guide guide = mProject->guides().at(index.row());
96+
97+
switch (role) {
98+
case OrientationRole:
99+
return QVariant::fromValue(guide.orientation());
100+
case PositionRole: {
101+
// If this is an existing guide that is currently being dragged, draw it in its dragged position.
102+
// It's OK if canvas is null; the user can't drag while things are starting up.
103+
const bool draggingExistingGuide = mCanvas && mCanvas->pressedGuideIndex() != -1 && mCanvas->pressedGuideIndex() == index.row();
104+
const bool vertical = guide.orientation() == Qt::Vertical;
105+
const int guidePosition = draggingExistingGuide
106+
? (vertical ? mCanvas->cursorSceneX() : mCanvas->cursorSceneY()) : guide.position();
107+
return QVariant::fromValue(guidePosition);
108+
} default:
109+
break;
110+
}
111+
112+
return QVariant();
113+
}
114+
115+
int GuideModel::rowCount(const QModelIndex &) const
116+
{
117+
if (!mProject)
118+
return 0;
119+
120+
return mProject->guides().size();
121+
}
122+
123+
int GuideModel::columnCount(const QModelIndex &) const
124+
{
125+
return 1;
126+
}
127+
128+
QHash<int, QByteArray> GuideModel::roleNames() const
129+
{
130+
QHash<int, QByteArray> names;
131+
names.insert(OrientationRole, "orientation");
132+
names.insert(PositionRole, "position");
133+
return names;
134+
}
135+
136+
void GuideModel::onProjectChanged()
137+
{
138+
}
139+
140+
void GuideModel::onPreGuidesAdded(int index, int count)
141+
{
142+
beginInsertRows(QModelIndex(), index, index + count - 1);
143+
}
144+
145+
void GuideModel::onPostGuidesAdded()
146+
{
147+
endInsertRows();
148+
}
149+
150+
void GuideModel::onPreGuidesRemoved()
151+
{
152+
qCDebug(lcGuideModel) << "guides about to be removed (" << this << "); about to call beginResetModel()...";
153+
beginResetModel();
154+
qCDebug(lcGuideModel) << "... called beginResetModel()";
155+
}
156+
157+
void GuideModel::onPostGuidesRemoved()
158+
{
159+
qCDebug(lcGuideModel) << "guides removed (" << this << "); about to call endResetModel()...";
160+
endResetModel();
161+
qCDebug(lcGuideModel) << "... called endResetModel()";
162+
}
163+
164+
void GuideModel::onGuideMoved(int index)
165+
{
166+
QVector<int> roles;
167+
roles.append(PositionRole);
168+
const QModelIndex modelIndex(createIndex(index, 0));
169+
emit dataChanged(modelIndex, modelIndex, roles);
170+
}

lib/guidemodel.h

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
Copyright 2021, Mitch Curtis
3+
4+
This file is part of Slate.
5+
6+
Slate is free software: you can redistribute it and/or modify
7+
it under the terms of the GNU General Public License as published by
8+
the Free Software Foundation, either version 3 of the License, or
9+
(at your option) any later version.
10+
11+
Slate is distributed in the hope that it will be useful,
12+
but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
GNU General Public License for more details.
15+
16+
You should have received a copy of the GNU General Public License
17+
along with Slate. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
#ifndef GUIDEMODEL_H
21+
#define GUIDEMODEL_H
22+
23+
#include <QAbstractListModel>
24+
#include <QColor>
25+
#include <QImage>
26+
#include <QQmlEngine>
27+
#include <QVector>
28+
29+
#include "slate-global.h"
30+
31+
class ImageCanvas;
32+
class Project;
33+
class Swatch;
34+
35+
class SLATE_EXPORT GuideModel : public QAbstractListModel
36+
{
37+
Q_OBJECT
38+
Q_PROPERTY(Project *project READ project WRITE setProject NOTIFY projectChanged)
39+
Q_PROPERTY(ImageCanvas *canvas READ canvas WRITE setCanvas NOTIFY canvasChanged)
40+
QML_ELEMENT
41+
Q_MOC_INCLUDE("imagecanvas.h")
42+
Q_MOC_INCLUDE("project.h")
43+
44+
public:
45+
enum {
46+
OrientationRole = Qt::UserRole,
47+
PositionRole
48+
};
49+
50+
explicit GuideModel(QObject *parent = nullptr);
51+
~GuideModel() override;
52+
53+
Project *project() const;
54+
void setProject(Project *project);
55+
56+
ImageCanvas *canvas() const;
57+
void setCanvas(ImageCanvas *canvas);
58+
59+
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
60+
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
61+
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
62+
QHash<int, QByteArray> roleNames() const override;
63+
64+
signals:
65+
void projectChanged();
66+
void canvasChanged();
67+
68+
private slots:
69+
void onProjectChanged();
70+
void onPreGuidesAdded(int index, int count);
71+
void onPostGuidesAdded();
72+
void onGuideMoved(int index);
73+
void onPreGuidesRemoved();
74+
void onPostGuidesRemoved();
75+
76+
protected:
77+
Project *mProject = nullptr;
78+
ImageCanvas *mCanvas = nullptr;
79+
};
80+
81+
#endif // GUIDEMODEL_H

0 commit comments

Comments
 (0)