src/document.cpp

changeset 191
d355d4c52d51
parent 188
64ea7282611e
child 197
0e729e681a2c
equal deleted inserted replaced
190:3dbdc243f053 191:d355d4c52d51
20 #include <QMessageBox> 20 #include <QMessageBox>
21 #include "document.h" 21 #include "document.h"
22 #include "ui_document.h" 22 #include "ui_document.h"
23 #include "model.h" 23 #include "model.h"
24 #include "modeleditor.h" 24 #include "modeleditor.h"
25 #include "tools/basetool.h" 25 #include "ui/objecteditor.h"
26 #include "tools/drawtool.h"
27 #include "tools/pathtool.h"
28 #include "tools/selecttool.h"
29 #include "tools/transformtool.h"
30 #include "tools/circletool.h"
31 26
32 Document::Document( 27 Document::Document(
33 Model* model, 28 Model* model,
34 DocumentManager* documents, 29 DocumentManager* documents,
35 const ldraw::ColorTable& colorTable, 30 const ldraw::ColorTable& colorTable,
36 QWidget* parent) : 31 QWidget* parent) :
37 QWidget{parent}, 32 QWidget{parent},
38 colorTable{colorTable}, 33 colorTable{colorTable},
34 canvas{new Canvas{model, this, documents, colorTable, this}},
39 model{model}, 35 model{model},
40 documents{documents}, 36 documents{documents},
41 vertexMap{model}, 37 vertexMap{model},
42 renderer{new Canvas{model, documents, colorTable, this}}, 38 ui{*new Ui_Document},
43 ui{*new Ui::Document}, 39 toolsBar{new QToolBar{this}},
44 toolsBar{new QToolBar{this}} 40 objectEditor{new ObjectEditor{this}}
45 { 41 {
46 this->ui.setupUi(this); 42 this->ui.setupUi(this);
47 const int listWidth = static_cast<int>(this->width() / 3); 43 const int listWidth = static_cast<int>(this->width() / 3);
48 this->ui.viewportListSplitter->setSizes({listWidth * 2, listWidth}); 44 this->ui.viewportListSplitter->setSizes({listWidth * 2, listWidth});
49 this->ui.toolsBarContainer->setLayout(new QVBoxLayout{this->ui.toolsBarContainer}); 45 this->ui.toolsBarContainer->setLayout(new QVBoxLayout{this->ui.toolsBarContainer});
50 this->ui.toolsBarContainer->layout()->addWidget(this->toolsBar); 46 this->ui.toolsBarContainer->layout()->addWidget(this->toolsBar);
51 this->ui.listView->setModel(model); 47 this->ui.listView->setModel(model);
52 this->ui.viewportFrame->setLayout(new QVBoxLayout{this->ui.listView}); 48 this->ui.viewportFrame->setLayout(new QVBoxLayout{this->ui.listView});
53 this->ui.viewportFrame->layout()->addWidget(this->renderer); 49 this->ui.viewportFrame->layout()->addWidget(this->canvas);
54 this->toolsBar->setOrientation(Qt::Vertical); 50 this->toolsBar->setOrientation(Qt::Vertical);
55 this->setMouseTracking(true); 51 this->setMouseTracking(true);
56 connect(this->ui.viewportListSplitter, &QSplitter::splitterMoved, this, &Document::splitterChanged); 52 connect(this->ui.viewportListSplitter, &QSplitter::splitterMoved, this, &Document::splitterChanged);
57 connect(this->renderer, &Canvas::newStatusText, this, &Document::newStatusText); 53 connect(this->canvas, &Canvas::newStatusText, this, &Document::newStatusText);
58 connect(this->renderer, &Canvas::selectionChanged, [&](const QSet<ldraw::id_t>& newSelection) 54 connect(this->canvas, &Canvas::selectionChanged, [&](const QSet<ldraw::id_t>& newSelection)
59 { 55 {
60 QItemSelectionModel* selectionModel = this->ui.listView->selectionModel(); 56 QItemSelectionModel* selectionModel = this->ui.listView->selectionModel();
61 QItemSelection selection; 57 QItemSelection selection;
62 for (ldraw::id_t id : newSelection) 58 for (const ldraw::id_t id : newSelection)
63 { 59 {
64 QModelIndex index = this->model->find(id); 60 QModelIndex index = this->model->find(id);
65 if (index != QModelIndex{}) 61 if (index != QModelIndex{})
66 { 62 {
67 selection.select(index, index); 63 selection.select(index, index);
68 } 64 }
69 } 65 }
70 QSignalBlocker blocker{this}; 66 QSignalBlocker blocker{this};
71 selectionModel->select(selection, QItemSelectionModel::ClearAndSelect); 67 selectionModel->select(selection, QItemSelectionModel::ClearAndSelect);
72 this->selectionChanged(newSelection);
73 }); 68 });
74 connect(this->ui.listView->selectionModel(), &QItemSelectionModel::selectionChanged, 69 connect(this->ui.listView->selectionModel(), &QItemSelectionModel::selectionChanged,
75 [&](const QItemSelection& selected, const QItemSelection& deselected) 70 [&](const QItemSelection& selected, const QItemSelection& deselected)
76 { 71 {
77 auto resolveIndex = [this](const QModelIndex& index){ return (*this->model)[index.row()]->id; }; 72 auto resolveIndex = [this](const QModelIndex& index){ return (*this->model)[index.row()]->id; };
78 auto resolve = [resolveIndex](const QItemSelection& selection) 73 auto resolve = [resolveIndex](const QItemSelection& selection)
79 { 74 {
80 return fn::map<QSet<ldraw::id_t>>(selection.indexes(), resolveIndex); 75 return fn::map<QSet<ldraw::id_t>>(selection.indexes(), resolveIndex);
81 }; 76 };
82 this->renderer->handleSelectionChange(resolve(selected), resolve(deselected)); 77 this->canvas->handleSelectionChange(resolve(selected), resolve(deselected));
83 this->selectionChanged(resolve(this->ui.listView->selectionModel()->selection()));
84 }); 78 });
85 connect(this->model, &Model::dataChanged, this->renderer, qOverload<>(&Canvas::update)); 79 connect(this->model, &Model::dataChanged, this->canvas, qOverload<>(&Canvas::update));
86 connect(this->renderer, &Canvas::mouseClick, this, [this](Canvas* canvas, QMouseEvent* event)
87 {
88 if (this->selectedTool != nullptr)
89 {
90 this->selectedTool->mouseClick(canvas, event);
91 }
92 });
93 connect(this->renderer, &Canvas::mouseMove, this, [this](Canvas* canvas, QMouseEvent* event)
94 {
95 if (this->selectedTool != nullptr)
96 {
97 this->selectedTool->mouseMove(this, canvas, event);
98 }
99 });
100 connect(&this->vertexMap, &VertexMap::verticesChanged, [&]() 80 connect(&this->vertexMap, &VertexMap::verticesChanged, [&]()
101 { 81 {
102 this->renderer->rebuildVertices(this); 82 this->canvas->rebuildVertices(this);
103 });
104 this->setCanvasOverpaintCallback([&](Canvas* canvas, QPainter* painter)
105 {
106 if (this->selectedTool != nullptr)
107 {
108 this->selectedTool->overpaint(canvas, painter);
109 }
110 }); 83 });
111 this->initializeTools(); 84 this->initializeTools();
112 } 85 }
113 86
114 Document::~Document() 87 Document::~Document()
124 void Document::restoreSplitterState(const QByteArray& state) 97 void Document::restoreSplitterState(const QByteArray& state)
125 { 98 {
126 this->ui.viewportListSplitter->restoreState(state); 99 this->ui.viewportListSplitter->restoreState(state);
127 } 100 }
128 101
129 void Document::setRenderPreferences(const gl::RenderPreferences& newPreferences)
130 {
131 this->renderer->setRenderPreferences(newPreferences);
132 }
133
134 void Document::setCanvasOverpaintCallback(Canvas::OverpaintCallback fn)
135 {
136 this->renderer->setOverpaintCallback(fn);
137 }
138
139 std::unique_ptr<ModelEditor> Document::editModel() 102 std::unique_ptr<ModelEditor> Document::editModel()
140 { 103 {
141 std::unique_ptr<ModelEditor> editorPointer = std::make_unique<ModelEditor>(*this->model); 104 std::unique_ptr<ModelEditor> editorPointer = std::make_unique<ModelEditor>(*this->model);
142 connect(editorPointer.get(), &ModelEditor::objectModified, [&](int position){ 105 connect(editorPointer.get(), &ModelEditor::objectModified, [&](int position){
143 this->model->emitDataChangedSignal(position); 106 this->model->emitDataChangedSignal(position);
148 void Document::applyToVertices(VertexMap::ApplyFunction fn) const 111 void Document::applyToVertices(VertexMap::ApplyFunction fn) const
149 { 112 {
150 this->vertexMap.apply(fn); 113 this->vertexMap.apply(fn);
151 } 114 }
152 115
153 void Document::selectionChanged(const QSet<ldraw::id_t>& newSelection) 116 const char INDEX_PROPERTY[] = "_editing_mode_index";
117
118 void Document::initializeTools()
154 { 119 {
155 for (BaseTool* tool : this->tools) 120 const struct
156 { 121 {
157 tool->selectionChanged(newSelection); 122 QString name, tooltip;
123 QPixmap icon;
124 QWidget* widget;
125 } editingModesInfo[] = {
126 {
127 .name = tr("Select"),
128 .tooltip = tr("Select elements from the model."),
129 .icon = {":/icons/navigate-outline.png"},
130 .widget = this->objectEditor,
131 },
132 {
133 .name = tr("Draw"),
134 .tooltip = tr("Draw new elements into the model."),
135 .icon = {":/icons/pencil-outline.png"},
136 .widget = nullptr,
137 },
138 };
139 for (int i = 0; i < countof(editingModesInfo); ++i) {
140 const auto& editingModeInfo = editingModesInfo[i];
141 QAction* action = new QAction{editingModeInfo.name, this};
142 action->setCheckable(true);
143 action->setChecked(i == 0);
144 action->setToolTip(editingModeInfo.tooltip);
145 action->setIcon(QPixmap{editingModeInfo.icon});
146 action->setProperty(INDEX_PROPERTY, i);
147 this->toolsBar->addAction(action);
148 QWidget* widget = editingModeInfo.widget;
149 if (widget == nullptr) {
150 widget = new QWidget{this};
151 }
152 this->ui.toolWidgetStack->addWidget(widget);
153 this->toolActions.push_back(action);
154 connect(action, &QAction::triggered, this, &Document::editingModeTriggered);
158 } 155 }
159 } 156 }
160 157
161 void Document::initializeTools() 158 void Document::editingModeTriggered()
162 { 159 {
163 this->tools.clear(); 160 QAction* triggeredAction = qobject_cast<QAction*>(this->sender());
164 this->tools.reserve(3); 161 if (triggeredAction != nullptr)
165 this->tools.push_back(new SelectTool{this});
166 this->tools.push_back(new DrawTool{this});
167 this->tools.push_back(new CircleTool{this});
168 this->tools.push_back(new PathTool{this});
169 this->tools.push_back(new TransformTool{this});
170 for (BaseTool* toolInstance : this->tools)
171 { 162 {
172 QAction* action = new QAction{toolInstance->name(), this}; 163 const int index = triggeredAction->property(INDEX_PROPERTY).toInt();
173 action->setCheckable(true); 164 this->canvas->mode = static_cast<EditingMode>(index);
174 this->toolActions[toolInstance] = action; 165 this->ui.toolWidgetStack->setCurrentIndex(index);
175 action->setToolTip(toolInstance->toolTip()); 166 for (QAction* action : this->toolActions) {
176 action->setIcon(QPixmap{toolInstance->iconName()}); 167 action->setChecked(action == triggeredAction);
177 connect(action, &QAction::triggered, this, &Document::toolActionTriggered);
178 this->toolsBar->addAction(action);
179 QWidget* const widget = toolInstance->toolWidget();
180 if (widget)
181 {
182 this->ui.toolWidgetStack->addWidget(widget);
183 }
184 else
185 {
186 this->ui.toolWidgetStack->addWidget(new QWidget{this});
187 }
188 connect(toolInstance, &BaseTool::desiredGridChange, this->renderer, &Canvas::setGridMatrix);
189 }
190 this->selectTool(this->tools[0]);
191 }
192
193 void Document::toolActionTriggered()
194 {
195 QAction* action = qobject_cast<QAction*>(sender());
196 if (action != nullptr)
197 {
198 BaseTool* tool = nullptr;
199 for (auto&& pair : items(this->toolActions))
200 {
201 if (pair.value == action)
202 {
203 tool = pair.key;
204 }
205 }
206 this->selectTool(tool);
207 }
208 }
209
210 void Document::selectTool(BaseTool* tool)
211 {
212 if (tool != nullptr && tool != this->selectedTool)
213 {
214 if (this->selectedTool != nullptr)
215 {
216 this->selectedTool->reset();
217 }
218 this->selectedTool = tool;
219 for (auto&& pair : items(this->toolActions))
220 {
221 pair.value->setChecked(pair.key == tool);
222 }
223 const int index = this->tools.indexOf(tool);
224 if (index != -1)
225 {
226 this->ui.toolWidgetStack->setCurrentIndex(index);
227 } 168 }
228 } 169 }
229 }
230
231 void Document::handleKeyPress(QKeyEvent* event)
232 {
233 if (this->selectedTool != nullptr)
234 {
235 this->selectedTool->keyReleased(this, this->renderer, event);
236 }
237 }
238
239 void Document::adjustGridToView()
240 {
241 this->renderer->adjustGridToView();
242 }
243
244 const glm::mat4 &Document::currentGrid() const
245 {
246 return this->renderer->getGridMatrix();
247 } 170 }
248 171
249 const Model &Document::getModel() const 172 const Model &Document::getModel() const
250 { 173 {
251 return *this->model; 174 return *this->model;
252 } 175 }
253 176
254 const QSet<ldraw::id_t> Document::selectedObjects() const 177 const QSet<ldraw::id_t> Document::selectedObjects() const
255 { 178 {
256 return this->renderer->selectedObjects(); 179 return this->canvas->selectedObjects();
257 } 180 }

mercurial