64 #define act(N) extern_cfg (KeySequence, key_##N); |
65 #define act(N) extern_cfg (KeySequence, key_##N); |
65 #include "actions.h" |
66 #include "actions.h" |
66 |
67 |
67 // ============================================================================= |
68 // ============================================================================= |
68 // ----------------------------------------------------------------------------- |
69 // ----------------------------------------------------------------------------- |
69 ForgeWindow::ForgeWindow() { |
70 ForgeWindow::ForgeWindow() |
70 g_win = this; |
71 { g_win = this; |
71 m_renderer = new GLRenderer; |
72 m_renderer = new GLRenderer; |
72 |
73 |
73 ui = new Ui_LDForgeUI; |
74 ui = new Ui_LDForgeUI; |
74 ui->setupUi (this); |
75 ui->setupUi (this); |
75 |
76 |
76 // Stuff the renderer into its frame |
77 // Stuff the renderer into its frame |
77 QVBoxLayout* rendererLayout = new QVBoxLayout (ui->rendererFrame); |
78 QVBoxLayout* rendererLayout = new QVBoxLayout (ui->rendererFrame); |
78 rendererLayout->addWidget (R()); |
79 rendererLayout->addWidget (R()); |
79 |
80 |
80 connect (ui->objectList, SIGNAL (itemSelectionChanged()), this, SLOT (slot_selectionChanged())); |
81 connect (ui->objectList, SIGNAL (itemSelectionChanged()), this, SLOT (slot_selectionChanged())); |
81 connect (ui->objectList, SIGNAL (itemDoubleClicked (QListWidgetItem*)), this, SLOT (slot_editObject (QListWidgetItem*))); |
82 connect (ui->objectList, SIGNAL (itemDoubleClicked (QListWidgetItem*)), this, SLOT (slot_editObject (QListWidgetItem*))); |
82 connect (ui->fileList, SIGNAL (currentItemChanged (QListWidgetItem*, QListWidgetItem*)), this, SLOT (changeCurrentFile())); |
83 connect (ui->fileList, SIGNAL (currentItemChanged (QListWidgetItem*, QListWidgetItem*)), this, SLOT (changeCurrentFile())); |
83 |
84 |
84 // Init message log manager |
85 // Init message log manager |
85 m_msglog = new MessageManager; |
86 m_msglog = new MessageManager; |
86 m_msglog->setRenderer (R()); |
87 m_msglog->setRenderer (R()); |
87 m_renderer->setMessageLog (m_msglog); |
88 m_renderer->setMessageLog (m_msglog); |
88 m_quickColors = quickColorsFromConfig(); |
89 m_quickColors = quickColorsFromConfig(); |
89 slot_selectionChanged(); |
90 slot_selectionChanged(); |
90 setStatusBar (new QStatusBar); |
91 setStatusBar (new QStatusBar); |
91 |
92 |
92 // Init primitive loader task stuff |
93 // Init primitive loader task stuff |
93 m_primLoaderBar = new QProgressBar; |
94 m_primLoaderBar = new QProgressBar; |
94 m_primLoaderWidget = new QWidget; |
95 m_primLoaderWidget = new QWidget; |
95 QHBoxLayout* primLoaderLayout = new QHBoxLayout (m_primLoaderWidget); |
96 QHBoxLayout* primLoaderLayout = new QHBoxLayout (m_primLoaderWidget); |
96 primLoaderLayout->addWidget (new QLabel ("Loading primitives:")); |
97 primLoaderLayout->addWidget (new QLabel ("Loading primitives:")); |
97 primLoaderLayout->addWidget (m_primLoaderBar); |
98 primLoaderLayout->addWidget (m_primLoaderBar); |
98 statusBar()->addPermanentWidget (m_primLoaderWidget); |
99 statusBar()->addPermanentWidget (m_primLoaderWidget); |
99 m_primLoaderWidget->hide(); |
100 m_primLoaderWidget->hide(); |
100 |
101 |
101 // Make certain actions checkable |
102 // Make certain actions checkable |
102 ui->actionAxes->setChecked (gl_axes); |
103 ui->actionAxes->setChecked (gl_axes); |
103 ui->actionWireframe->setChecked (gl_wireframe); |
104 ui->actionWireframe->setChecked (gl_wireframe); |
104 ui->actionBFCView->setChecked (gl_colorbfc); |
105 ui->actionBFCView->setChecked (gl_colorbfc); |
105 updateGridToolBar(); |
106 updateGridToolBar(); |
106 updateEditModeActions(); |
107 updateEditModeActions(); |
107 updateRecentFilesMenu(); |
108 updateRecentFilesMenu(); |
108 updateToolBars(); |
109 updateToolBars(); |
109 updateTitle(); |
110 updateTitle(); |
110 |
111 |
111 setMinimumSize (300, 200); |
112 setMinimumSize (300, 200); |
112 |
113 |
113 connect (qApp, SIGNAL (aboutToQuit()), this, SLOT (slot_lastSecondCleanup())); |
114 connect (qApp, SIGNAL (aboutToQuit()), this, SLOT (slot_lastSecondCleanup())); |
114 |
115 |
115 // Connect all actions and set shortcuts |
116 // Connect all actions and set shortcuts |
116 #define act(N) \ |
117 #define act(N) \ |
117 connect (ui->action##N, SIGNAL (triggered()), this, SLOT (slot_action())); \ |
118 connect (ui->action##N, SIGNAL (triggered()), this, SLOT (slot_action())); \ |
118 ui->action##N->setShortcut (key_##N); |
119 ui->action##N->setShortcut (key_##N); |
119 #include "actions.h" |
120 #include "actions.h" |
120 } |
121 } |
121 |
122 |
122 // ============================================================================= |
123 // ============================================================================= |
123 // ----------------------------------------------------------------------------- |
124 // ----------------------------------------------------------------------------- |
124 void ForgeWindow::slot_action() { |
125 void ForgeWindow::slot_action() |
125 // Find out which action triggered this |
126 { // Find out which action triggered this |
126 #define act(N) if (sender() == ui->action##N) invokeAction (ui->action##N, &actiondef_##N); |
127 #define act(N) if (sender() == ui->action##N) invokeAction (ui->action##N, &actiondef_##N); |
127 #include "actions.h" |
128 #include "actions.h" |
128 } |
129 } |
129 |
130 |
130 // ============================================================================= |
131 // ============================================================================= |
131 // ----------------------------------------------------------------------------- |
132 // ----------------------------------------------------------------------------- |
132 void ForgeWindow::invokeAction (QAction* act, void (*func)()) { |
133 void ForgeWindow::invokeAction (QAction* act, void (*func) ()) |
133 beginAction (act); |
134 { beginAction (act); |
134 (*func)(); |
135 (*func) (); |
135 endAction(); |
136 endAction(); |
136 } |
137 } |
137 |
138 |
138 // ============================================================================= |
139 // ============================================================================= |
139 // ----------------------------------------------------------------------------- |
140 // ----------------------------------------------------------------------------- |
140 void ForgeWindow::slot_lastSecondCleanup() { |
141 void ForgeWindow::slot_lastSecondCleanup() |
141 delete m_renderer; |
142 { delete m_renderer; |
142 delete ui; |
143 delete ui; |
143 } |
144 } |
144 |
145 |
145 // ============================================================================= |
146 // ============================================================================= |
146 // ----------------------------------------------------------------------------- |
147 // ----------------------------------------------------------------------------- |
147 void ForgeWindow::updateRecentFilesMenu() { |
148 void ForgeWindow::updateRecentFilesMenu() |
148 // First, clear any items in the recent files menu |
149 { // First, clear any items in the recent files menu |
149 for (QAction* recent : m_recentFiles) |
150 for (QAction * recent : m_recentFiles) |
150 delete recent; |
151 delete recent; |
|
152 |
151 m_recentFiles.clear(); |
153 m_recentFiles.clear(); |
152 |
154 |
153 QAction* first = null; |
155 QAction* first = null; |
154 |
156 |
155 for (const QVariant& it : io_recentfiles) { |
157 for (const QVariant & it : io_recentfiles) |
156 str file = it.toString(); |
158 { str file = it.toString(); |
157 QAction* recent = new QAction (getIcon ("open-recent"), file, this); |
159 QAction* recent = new QAction (getIcon ("open-recent"), file, this); |
158 |
160 |
159 connect (recent, SIGNAL (triggered()), this, SLOT (slot_recentFile())); |
161 connect (recent, SIGNAL (triggered()), this, SLOT (slot_recentFile())); |
160 ui->menuOpenRecent->insertAction (first, recent); |
162 ui->menuOpenRecent->insertAction (first, recent); |
161 m_recentFiles << recent; |
163 m_recentFiles << recent; |
162 first = recent; |
164 first = recent; |
163 } |
165 } |
164 } |
166 } |
165 |
167 |
166 // ============================================================================= |
168 // ============================================================================= |
167 // ----------------------------------------------------------------------------- |
169 // ----------------------------------------------------------------------------- |
168 List<LDQuickColor> quickColorsFromConfig() { |
170 List<LDQuickColor> quickColorsFromConfig() |
169 List<LDQuickColor> colors; |
171 { List<LDQuickColor> colors; |
170 |
172 |
171 for (str colorname : gui_colortoolbar.value.split (":")) { |
173 for (str colorname : gui_colortoolbar.value.split (":")) |
172 if (colorname == "|") |
174 { if (colorname == "|") |
173 colors << LDQuickColor::getSeparator(); |
175 colors << LDQuickColor::getSeparator(); |
174 else { |
176 else |
175 LDColor* col = getColor (colorname.toLong()); |
177 { LDColor* col = getColor (colorname.toLong()); |
176 |
178 |
177 if (col != null) |
179 if (col != null) |
178 colors << LDQuickColor (col, null); |
180 colors << LDQuickColor (col, null); |
179 } |
181 } |
180 } |
182 } |
181 |
183 |
182 return colors; |
184 return colors; |
183 } |
185 } |
184 |
186 |
185 // ============================================================================= |
187 // ============================================================================= |
186 // ----------------------------------------------------------------------------- |
188 // ----------------------------------------------------------------------------- |
187 void ForgeWindow::updateToolBars() { |
189 void ForgeWindow::updateToolBars() |
188 m_colorButtons.clear(); |
190 { m_colorButtons.clear(); |
189 ui->colorToolbar->clear(); |
191 ui->colorToolbar->clear(); |
190 |
192 |
191 for (LDQuickColor& entry : m_quickColors) { |
193 for (LDQuickColor & entry : m_quickColors) |
192 if (entry.isSeparator()) |
194 { if (entry.isSeparator()) |
193 ui->colorToolbar->addSeparator(); |
195 ui->colorToolbar->addSeparator(); |
194 else { |
196 else |
195 QToolButton* colorButton = new QToolButton; |
197 { QToolButton* colorButton = new QToolButton; |
196 colorButton->setIcon (makeColorIcon (entry.color(), 22)); |
198 colorButton->setIcon (makeColorIcon (entry.color(), 22)); |
197 colorButton->setIconSize (QSize (22, 22)); |
199 colorButton->setIconSize (QSize (22, 22)); |
198 colorButton->setToolTip (entry.color()->name); |
200 colorButton->setToolTip (entry.color()->name); |
199 |
201 |
200 connect (colorButton, SIGNAL (clicked()), this, SLOT (slot_quickColor())); |
202 connect (colorButton, SIGNAL (clicked()), this, SLOT (slot_quickColor())); |
201 ui->colorToolbar->addWidget (colorButton); |
203 ui->colorToolbar->addWidget (colorButton); |
202 m_colorButtons << colorButton; |
204 m_colorButtons << colorButton; |
203 |
205 |
204 entry.setToolButton (colorButton); |
206 entry.setToolButton (colorButton); |
205 } |
207 } |
206 } |
208 } |
207 |
209 |
208 updateGridToolBar(); |
210 updateGridToolBar(); |
209 } |
211 } |
210 |
212 |
211 // ============================================================================= |
213 // ============================================================================= |
212 // ----------------------------------------------------------------------------- |
214 // ----------------------------------------------------------------------------- |
213 void ForgeWindow::updateGridToolBar() { |
215 void ForgeWindow::updateGridToolBar() |
214 // Ensure that the current grid - and only the current grid - is selected. |
216 { // Ensure that the current grid - and only the current grid - is selected. |
215 ui->actionGridCoarse->setChecked (grid == Grid::Coarse); |
217 ui->actionGridCoarse->setChecked (grid == Grid::Coarse); |
216 ui->actionGridMedium->setChecked (grid == Grid::Medium); |
218 ui->actionGridMedium->setChecked (grid == Grid::Medium); |
217 ui->actionGridFine->setChecked (grid == Grid::Fine); |
219 ui->actionGridFine->setChecked (grid == Grid::Fine); |
218 } |
220 } |
219 |
221 |
220 // ============================================================================= |
222 // ============================================================================= |
221 // ----------------------------------------------------------------------------- |
223 // ----------------------------------------------------------------------------- |
222 void ForgeWindow::updateTitle() { |
224 void ForgeWindow::updateTitle() |
223 str title = fmt (APPNAME " %1", fullVersionString()); |
225 { str title = fmt (APPNAME " %1", fullVersionString()); |
224 |
226 |
225 // Append our current file if we have one |
227 // Append our current file if we have one |
226 if (LDFile::current()) { |
228 if (LDFile::current()) |
227 if (LDFile::current()->name().length() > 0) |
229 { if (LDFile::current()->name().length() > 0) |
228 title += fmt (": %1", basename (LDFile::current()->name())); |
230 title += fmt (": %1", basename (LDFile::current()->name())); |
229 else |
231 else |
230 title += fmt (": <anonymous>"); |
232 title += fmt (": <anonymous>"); |
231 |
233 |
232 if (LDFile::current()->numObjs() > 0 && |
234 if (LDFile::current()->numObjs() > 0 && |
233 LDFile::current()->obj (0)->getType() == LDObject::Comment) |
235 LDFile::current()->obj (0)->getType() == LDObject::Comment) |
234 { |
236 { // Append title |
235 // Append title |
|
236 LDComment* comm = static_cast<LDComment*> (LDFile::current()->obj (0)); |
237 LDComment* comm = static_cast<LDComment*> (LDFile::current()->obj (0)); |
237 title += fmt (": %1", comm->text); |
238 title += fmt (": %1", comm->text); |
238 } |
239 } |
239 |
240 |
240 if (LDFile::current()->history().pos() != LDFile::current()->savePos()) |
241 if (LDFile::current()->history().pos() != LDFile::current()->savePos()) |
241 title += '*'; |
242 title += '*'; |
242 } |
243 } |
243 |
244 |
244 setWindowTitle (title); |
245 setWindowTitle (title); |
245 } |
246 } |
246 |
247 |
247 // ============================================================================= |
248 // ============================================================================= |
248 // ----------------------------------------------------------------------------- |
249 // ----------------------------------------------------------------------------- |
249 int ForgeWindow::deleteSelection() { |
250 int ForgeWindow::deleteSelection() |
250 if (m_sel.size() == 0) |
251 { if (m_sel.size() == 0) |
251 return 0; |
252 return 0; |
252 |
253 |
253 List<LDObject*> selCopy = m_sel; |
254 List<LDObject*> selCopy = m_sel; |
254 int num = 0; |
255 int num = 0; |
255 |
256 |
256 // Delete the objects that were being selected |
257 // Delete the objects that were being selected |
257 for (LDObject* obj : selCopy) { |
258 for (LDObject * obj : selCopy) |
258 LDFile::current()->forgetObject (obj); |
259 { LDFile::current()->forgetObject (obj); |
259 ++num; |
260 ++num; |
260 delete obj; |
261 delete obj; |
261 } |
262 } |
262 |
263 |
263 refresh(); |
264 refresh(); |
264 return num; |
265 return num; |
265 } |
266 } |
266 |
267 |
267 // ============================================================================= |
268 // ============================================================================= |
268 // ----------------------------------------------------------------------------- |
269 // ----------------------------------------------------------------------------- |
269 void ForgeWindow::buildObjList() { |
270 void ForgeWindow::buildObjList() |
270 if (!LDFile::current()) |
271 { if (!LDFile::current()) |
271 return; |
272 return; |
272 |
273 |
273 // Lock the selection while we do this so that refreshing the object list |
274 // Lock the selection while we do this so that refreshing the object list |
274 // doesn't trigger selection updating so that the selection doesn't get lost |
275 // doesn't trigger selection updating so that the selection doesn't get lost |
275 // while this is done. |
276 // while this is done. |
276 g_bSelectionLocked = true; |
277 g_bSelectionLocked = true; |
277 |
278 |
278 for (int i = 0; i < ui->objectList->count(); ++i) |
279 for (int i = 0; i < ui->objectList->count(); ++i) |
279 delete ui->objectList->item (i); |
280 delete ui->objectList->item (i); |
280 |
281 |
281 ui->objectList->clear(); |
282 ui->objectList->clear(); |
282 |
283 |
283 for (LDObject* obj : LDFile::current()->objects()) { |
284 for (LDObject * obj : LDFile::current()->objects()) |
284 str descr; |
285 { str descr; |
285 |
286 |
286 switch (obj->getType()) { |
287 switch (obj->getType()) |
287 case LDObject::Comment: |
288 { case LDObject::Comment: |
288 descr = static_cast<LDComment*> (obj)->text; |
289 descr = static_cast<LDComment*> (obj)->text; |
289 |
290 |
290 // Remove leading whitespace |
291 // Remove leading whitespace |
291 while (descr[0] == ' ') |
292 while (descr[0] == ' ') |
292 descr.remove (0, 1); |
293 descr.remove (0, 1); |
293 break; |
294 |
294 |
295 break; |
295 case LDObject::Empty: |
296 |
296 break; // leave it empty |
297 case LDObject::Empty: |
297 |
298 break; // leave it empty |
298 case LDObject::Line: |
299 |
299 case LDObject::Triangle: |
300 case LDObject::Line: |
300 case LDObject::Quad: |
301 case LDObject::Triangle: |
301 case LDObject::CndLine: |
302 case LDObject::Quad: |
302 for (short i = 0; i < obj->vertices(); ++i) { |
303 case LDObject::CndLine: |
303 if (i != 0) |
304 |
304 descr += ", "; |
305 for (short i = 0; i < obj->vertices(); ++i) |
305 |
306 { if (i != 0) |
306 descr += obj->getVertex (i).stringRep (true); |
307 descr += ", "; |
307 } |
308 |
308 break; |
309 descr += obj->getVertex (i).stringRep (true); |
309 |
310 } |
310 case LDObject::Error: |
311 |
311 descr = fmt ("ERROR: %1", obj->raw()); |
312 break; |
312 break; |
313 |
313 |
314 case LDObject::Error: |
314 case LDObject::Vertex: |
315 descr = fmt ("ERROR: %1", obj->raw()); |
315 descr = static_cast<LDVertex*> (obj)->pos.stringRep (true); |
316 break; |
316 break; |
317 |
317 |
318 case LDObject::Vertex: |
318 case LDObject::Subfile: |
319 descr = static_cast<LDVertex*> (obj)->pos.stringRep (true); |
319 { |
320 break; |
320 LDSubfile* ref = static_cast<LDSubfile*> (obj); |
321 |
321 |
322 case LDObject::Subfile: |
|
323 { LDSubfile* ref = static_cast<LDSubfile*> (obj); |
|
324 |
322 descr = fmt ("%1 %2, (", ref->fileInfo()->name(), |
325 descr = fmt ("%1 %2, (", ref->fileInfo()->name(), |
323 ref->position().stringRep (true)); |
326 ref->position().stringRep (true)); |
324 |
327 |
325 for (short i = 0; i < 9; ++i) |
328 for (short i = 0; i < 9; ++i) |
326 descr += fmt ("%1%2", ftoa (ref->transform()[i]), |
329 descr += fmt ("%1%2", ftoa (ref->transform() [i]), |
327 (i != 8) ? " " : ""); |
330 (i != 8) ? " " : ""); |
328 |
331 |
329 descr += ')'; |
332 descr += ')'; |
330 } |
333 } |
331 break; |
334 break; |
332 |
335 |
333 case LDObject::BFC: |
336 case LDObject::BFC: |
334 descr = LDBFC::statements[static_cast<LDBFC*> (obj)->type]; |
337 descr = LDBFC::statements[static_cast<LDBFC*> (obj)->type]; |
335 break; |
338 break; |
336 |
339 |
337 case LDObject::Overlay: |
340 case LDObject::Overlay: |
338 { |
341 { LDOverlay* ovl = static_cast<LDOverlay*> (obj); |
339 LDOverlay* ovl = static_cast<LDOverlay*> (obj); |
|
340 descr = fmt ("[%1] %2 (%3, %4), %5 x %6", g_CameraNames[ovl->camera()], |
342 descr = fmt ("[%1] %2 (%3, %4), %5 x %6", g_CameraNames[ovl->camera()], |
341 basename (ovl->filename()), ovl->x(), ovl->y(), ovl->width(), ovl->height()); |
343 basename (ovl->filename()), ovl->x(), ovl->y(), ovl->width(), ovl->height()); |
342 } |
344 } |
343 break; |
345 break; |
344 |
346 |
345 default: |
347 default: |
346 descr = obj->typeName(); |
348 descr = obj->typeName(); |
347 break; |
349 break; |
348 } |
350 } |
349 |
351 |
350 // Put it into brackets if it's hidden |
352 // Put it into brackets if it's hidden |
351 if (obj->hidden()) |
353 if (obj->hidden()) |
352 descr = fmt ("[[ %1 ]]", descr); |
354 descr = fmt ("[[ %1 ]]", descr); |
353 |
355 |
354 QListWidgetItem* item = new QListWidgetItem (descr); |
356 QListWidgetItem* item = new QListWidgetItem (descr); |
355 item->setIcon (getIcon (obj->typeName())); |
357 item->setIcon (getIcon (obj->typeName())); |
356 |
358 |
357 // Color gibberish orange on red so it stands out. |
359 // Color gibberish orange on red so it stands out. |
358 if (obj->getType() == LDObject::Error) { |
360 if (obj->getType() == LDObject::Error) |
359 item->setBackground (QColor ("#AA0000")); |
361 { item->setBackground (QColor ("#AA0000")); |
360 item->setForeground (QColor ("#FFAA00")); |
362 item->setForeground (QColor ("#FFAA00")); |
361 } elif (lv_colorize && obj->isColored() && |
363 } elif (lv_colorize && obj->isColored() && |
362 obj->color() != maincolor && obj->color() != edgecolor) |
364 |
363 { |
365 obj->color() != maincolor && obj->color() != edgecolor) |
364 // If the object isn't in the main or edge color, draw this |
366 { // If the object isn't in the main or edge color, draw this |
365 // list entry in said color. |
367 // list entry in said color. |
366 LDColor* col = getColor (obj->color()); |
368 LDColor* col = getColor (obj->color()); |
|
369 |
367 if (col) |
370 if (col) |
368 item->setForeground (col->faceColor); |
371 item->setForeground (col->faceColor); |
369 } |
372 } |
370 |
373 |
371 obj->qObjListEntry = item; |
374 obj->qObjListEntry = item; |
372 ui->objectList->insertItem (ui->objectList->count(), item); |
375 ui->objectList->insertItem (ui->objectList->count(), item); |
373 } |
376 } |
374 |
377 |
375 g_bSelectionLocked = false; |
378 g_bSelectionLocked = false; |
376 updateSelection(); |
379 updateSelection(); |
377 scrollToSelection(); |
380 scrollToSelection(); |
378 } |
381 } |
379 |
382 |
380 // ============================================================================= |
383 // ============================================================================= |
381 // ----------------------------------------------------------------------------- |
384 // ----------------------------------------------------------------------------- |
382 void ForgeWindow::scrollToSelection() { |
385 void ForgeWindow::scrollToSelection() |
383 if (m_sel.size() == 0) |
386 { if (m_sel.size() == 0) |
384 return; |
387 return; |
385 |
388 |
386 LDObject* obj = m_sel[m_sel.size() - 1]; |
389 LDObject* obj = m_sel[m_sel.size() - 1]; |
387 ui->objectList->scrollToItem (obj->qObjListEntry); |
390 ui->objectList->scrollToItem (obj->qObjListEntry); |
388 } |
391 } |
389 |
392 |
390 // ============================================================================= |
393 // ============================================================================= |
391 // ----------------------------------------------------------------------------- |
394 // ----------------------------------------------------------------------------- |
392 void ForgeWindow::slot_selectionChanged() { |
395 void ForgeWindow::slot_selectionChanged() |
393 if (g_bSelectionLocked == true || LDFile::current() == null) |
396 { if (g_bSelectionLocked == true || LDFile::current() == null) |
394 return; |
397 return; |
395 |
398 |
396 // Update the shared selection array, though don't do this if this was |
399 // Update the shared selection array, though don't do this if this was |
397 // called during GL picking, in which case the GL renderer takes care |
400 // called during GL picking, in which case the GL renderer takes care |
398 // of the selection. |
401 // of the selection. |
399 if (m_renderer->picking()) |
402 if (m_renderer->picking()) |
400 return; |
403 return; |
401 |
404 |
402 List<LDObject*> priorSelection = m_sel; |
405 List<LDObject*> priorSelection = m_sel; |
403 |
406 |
404 // Get the objects from the object list selection |
407 // Get the objects from the object list selection |
405 m_sel.clear(); |
408 m_sel.clear(); |
406 const QList<QListWidgetItem*> items = ui->objectList->selectedItems(); |
409 const QList<QListWidgetItem*> items = ui->objectList->selectedItems(); |
407 |
410 |
408 for (LDObject* obj : LDFile::current()->objects()) |
411 for (LDObject * obj : LDFile::current()->objects()) |
409 for (QListWidgetItem* item : items) { |
412 for (QListWidgetItem * item : items) |
410 if (item == obj->qObjListEntry) { |
413 { if (item == obj->qObjListEntry) |
411 m_sel << obj; |
414 { m_sel << obj; |
|
415 break; |
|
416 } |
|
417 } |
|
418 |
|
419 // Update the GL renderer |
|
420 for (LDObject * obj : priorSelection) |
|
421 { obj->setSelected (false); |
|
422 m_renderer->compileObject (obj); |
|
423 } |
|
424 |
|
425 for (LDObject * obj : m_sel) |
|
426 { obj->setSelected (true); |
|
427 m_renderer->compileObject (obj); |
|
428 } |
|
429 |
|
430 m_renderer->update(); |
|
431 } |
|
432 |
|
433 // ============================================================================= |
|
434 // ----------------------------------------------------------------------------- |
|
435 void ForgeWindow::slot_recentFile() |
|
436 { QAction* qAct = static_cast<QAction*> (sender()); |
|
437 openMainFile (qAct->text()); |
|
438 } |
|
439 |
|
440 // ============================================================================= |
|
441 // ----------------------------------------------------------------------------- |
|
442 void ForgeWindow::slot_quickColor() |
|
443 { beginAction (null); |
|
444 QToolButton* button = static_cast<QToolButton*> (sender()); |
|
445 LDColor* col = null; |
|
446 |
|
447 for (const LDQuickColor & entry : m_quickColors) |
|
448 { if (entry.toolButton() == button) |
|
449 { col = entry.color(); |
412 break; |
450 break; |
413 } |
451 } |
414 } |
452 } |
415 |
453 |
416 // Update the GL renderer |
|
417 for (LDObject* obj : priorSelection) { |
|
418 obj->setSelected (false); |
|
419 m_renderer->compileObject (obj); |
|
420 } |
|
421 |
|
422 for (LDObject* obj : m_sel) { |
|
423 obj->setSelected (true); |
|
424 m_renderer->compileObject (obj); |
|
425 } |
|
426 |
|
427 m_renderer->update(); |
|
428 } |
|
429 |
|
430 // ============================================================================= |
|
431 // ----------------------------------------------------------------------------- |
|
432 void ForgeWindow::slot_recentFile() { |
|
433 QAction* qAct = static_cast<QAction*> (sender()); |
|
434 openMainFile (qAct->text()); |
|
435 } |
|
436 |
|
437 // ============================================================================= |
|
438 // ----------------------------------------------------------------------------- |
|
439 void ForgeWindow::slot_quickColor() { |
|
440 beginAction (null); |
|
441 QToolButton* button = static_cast<QToolButton*> (sender()); |
|
442 LDColor* col = null; |
|
443 |
|
444 for (const LDQuickColor& entry : m_quickColors) { |
|
445 if (entry.toolButton() == button) { |
|
446 col = entry.color(); |
|
447 break; |
|
448 } |
|
449 } |
|
450 |
|
451 if (col == null) |
454 if (col == null) |
452 return; |
455 return; |
453 |
456 |
454 short newColor = col->index; |
457 short newColor = col->index; |
455 |
458 |
456 for (LDObject* obj : m_sel) { |
459 for (LDObject * obj : m_sel) |
457 if (obj->isColored() == false) |
460 { if (obj->isColored() == false) |
458 continue; // uncolored object |
461 continue; // uncolored object |
459 |
462 |
460 obj->setColor (newColor); |
463 obj->setColor (newColor); |
461 R()->compileObject (obj); |
464 R()->compileObject (obj); |
462 } |
465 } |
463 |
466 |
464 refresh(); |
467 refresh(); |
465 endAction(); |
468 endAction(); |
466 } |
469 } |
467 |
470 |
468 // ============================================================================= |
471 // ============================================================================= |
469 // ----------------------------------------------------------------------------- |
472 // ----------------------------------------------------------------------------- |
470 ulong ForgeWindow::getInsertionPoint() { |
473 ulong ForgeWindow::getInsertionPoint() |
471 if (m_sel.size() > 0) { |
474 { if (m_sel.size() > 0) |
472 // If we have a selection, put the item after it. |
475 { // If we have a selection, put the item after it. |
473 return (m_sel[m_sel.size() - 1]->getIndex()) + 1; |
476 return (m_sel[m_sel.size() - 1]->getIndex()) + 1; |
474 } |
477 } |
475 |
478 |
476 // Otherwise place the object at the end. |
479 // Otherwise place the object at the end. |
477 return LDFile::current()->numObjs(); |
480 return LDFile::current()->numObjs(); |
478 } |
481 } |
479 |
482 |
480 // ============================================================================= |
483 // ============================================================================= |
481 // ----------------------------------------------------------------------------- |
484 // ----------------------------------------------------------------------------- |
482 void ForgeWindow::fullRefresh() { |
485 void ForgeWindow::fullRefresh() |
483 buildObjList(); |
486 { buildObjList(); |
484 m_renderer->hardRefresh(); |
487 m_renderer->hardRefresh(); |
485 } |
488 } |
486 |
489 |
487 // ============================================================================= |
490 // ============================================================================= |
488 // ----------------------------------------------------------------------------- |
491 // ----------------------------------------------------------------------------- |
489 void ForgeWindow::refresh() { |
492 void ForgeWindow::refresh() |
490 buildObjList(); |
493 { buildObjList(); |
491 m_renderer->update(); |
494 m_renderer->update(); |
492 } |
495 } |
493 |
496 |
494 // ============================================================================= |
497 // ============================================================================= |
495 // ----------------------------------------------------------------------------- |
498 // ----------------------------------------------------------------------------- |
496 void ForgeWindow::updateSelection() { |
499 void ForgeWindow::updateSelection() |
497 g_bSelectionLocked = true; |
500 { g_bSelectionLocked = true; |
498 |
501 |
499 for (LDObject* obj : LDFile::current()->objects()) |
502 for (LDObject * obj : LDFile::current()->objects()) |
500 obj->setSelected (false); |
503 obj->setSelected (false); |
501 |
504 |
502 ui->objectList->clearSelection(); |
505 ui->objectList->clearSelection(); |
503 for (LDObject* obj : m_sel) { |
506 |
504 if (obj->qObjListEntry == null) |
507 for (LDObject * obj : m_sel) |
|
508 { if (obj->qObjListEntry == null) |
505 continue; |
509 continue; |
506 |
510 |
507 obj->qObjListEntry->setSelected (true); |
511 obj->qObjListEntry->setSelected (true); |
508 obj->setSelected (true); |
512 obj->setSelected (true); |
509 } |
513 } |
510 |
514 |
511 g_bSelectionLocked = false; |
515 g_bSelectionLocked = false; |
512 slot_selectionChanged(); |
516 slot_selectionChanged(); |
513 } |
517 } |
514 |
518 |
515 // ============================================================================= |
519 // ============================================================================= |
516 // ----------------------------------------------------------------------------- |
520 // ----------------------------------------------------------------------------- |
517 bool ForgeWindow::isSelected (LDObject* obj) { |
521 bool ForgeWindow::isSelected (LDObject* obj) |
518 LDObject* needle = obj->topLevelParent(); |
522 { LDObject* needle = obj->topLevelParent(); |
519 |
523 |
520 for (LDObject* hay : m_sel) |
524 for (LDObject * hay : m_sel) |
521 if (hay == needle) |
525 if (hay == needle) |
522 return true; |
526 return true; |
523 |
527 |
524 return false; |
528 return false; |
525 } |
529 } |
526 |
530 |
527 short ForgeWindow::getSelectedColor() { |
531 short ForgeWindow::getSelectedColor() |
528 short result = -1; |
532 { short result = -1; |
529 |
533 |
530 for (LDObject* obj : m_sel) { |
534 for (LDObject * obj : m_sel) |
531 if (obj->isColored() == false) |
535 { if (obj->isColored() == false) |
532 continue; // doesn't use color |
536 continue; // doesn't use color |
533 |
537 |
534 if (result != -1 && obj->color() != result) |
538 if (result != -1 && obj->color() != result) |
535 return -1; // No consensus in object color |
539 return -1; // No consensus in object color |
536 |
540 |
537 if (result == -1) |
541 if (result == -1) |
538 result = obj->color(); |
542 result = obj->color(); |
539 } |
543 } |
540 |
544 |
541 return result; |
545 return result; |
542 } |
546 } |
543 |
547 |
544 // ============================================================================= |
548 // ============================================================================= |
545 // ----------------------------------------------------------------------------- |
549 // ----------------------------------------------------------------------------- |
546 LDObject::Type ForgeWindow::uniformSelectedType() { |
550 LDObject::Type ForgeWindow::uniformSelectedType() |
547 LDObject::Type result = LDObject::Unidentified; |
551 { LDObject::Type result = LDObject::Unidentified; |
548 |
552 |
549 for (LDObject* obj : m_sel) { |
553 for (LDObject * obj : m_sel) |
550 if (result != LDObject::Unidentified && obj->color() != result) |
554 { if (result != LDObject::Unidentified && obj->color() != result) |
551 return LDObject::Unidentified; |
555 return LDObject::Unidentified; |
552 |
556 |
553 if (result == LDObject::Unidentified) |
557 if (result == LDObject::Unidentified) |
554 result = obj->getType(); |
558 result = obj->getType(); |
555 } |
559 } |
556 |
560 |
557 return result; |
561 return result; |
558 } |
562 } |
559 |
563 |
560 // ============================================================================= |
564 // ============================================================================= |
561 // ----------------------------------------------------------------------------- |
565 // ----------------------------------------------------------------------------- |
562 void ForgeWindow::closeEvent (QCloseEvent* ev) { |
566 void ForgeWindow::closeEvent (QCloseEvent* ev) |
563 // Check whether it's safe to close all files. |
567 { // Check whether it's safe to close all files. |
564 if (!safeToCloseAll()) { |
568 if (!safeToCloseAll()) |
565 ev->ignore(); |
569 { ev->ignore(); |
566 return; |
570 return; |
567 } |
571 } |
568 |
572 |
569 // Save the configuration before leaving so that, for instance, grid choice |
573 // Save the configuration before leaving so that, for instance, grid choice |
570 // is preserved across instances. |
574 // is preserved across instances. |
571 Config::save(); |
575 Config::save(); |
572 |
576 |
573 ev->accept(); |
577 ev->accept(); |
574 } |
578 } |
575 |
579 |
576 // ============================================================================= |
580 // ============================================================================= |
577 // ----------------------------------------------------------------------------- |
581 // ----------------------------------------------------------------------------- |
578 void ForgeWindow::spawnContextMenu (const QPoint pos) { |
582 void ForgeWindow::spawnContextMenu (const QPoint pos) |
579 const bool single = (g_win->sel().size() == 1); |
583 { const bool single = (g_win->sel().size() == 1); |
580 LDObject* singleObj = (single) ? g_win->sel()[0] : null; |
584 LDObject* singleObj = (single) ? g_win->sel() [0] : null; |
581 |
585 |
582 QMenu* contextMenu = new QMenu; |
586 QMenu* contextMenu = new QMenu; |
583 |
587 |
584 if (single && singleObj->getType() != LDObject::Empty) { |
588 if (single && singleObj->getType() != LDObject::Empty) |
585 contextMenu->addAction (ACTION (Edit)); |
589 { contextMenu->addAction (ACTION (Edit)); |
586 contextMenu->addSeparator(); |
590 contextMenu->addSeparator(); |
587 } |
591 } |
588 |
592 |
589 contextMenu->addAction (ACTION (Cut)); |
593 contextMenu->addAction (ACTION (Cut)); |
590 contextMenu->addAction (ACTION (Copy)); |
594 contextMenu->addAction (ACTION (Copy)); |
591 contextMenu->addAction (ACTION (Paste)); |
595 contextMenu->addAction (ACTION (Paste)); |
592 contextMenu->addAction (ACTION (Delete)); |
596 contextMenu->addAction (ACTION (Delete)); |
593 contextMenu->addSeparator(); |
597 contextMenu->addSeparator(); |
594 contextMenu->addAction (ACTION (SetColor)); |
598 contextMenu->addAction (ACTION (SetColor)); |
595 |
599 |
596 if (single) |
600 if (single) |
597 contextMenu->addAction (ACTION (EditRaw)); |
601 contextMenu->addAction (ACTION (EditRaw)); |
598 |
602 |
599 contextMenu->addAction (ACTION (Borders)); |
603 contextMenu->addAction (ACTION (Borders)); |
600 contextMenu->addAction (ACTION (SetOverlay)); |
604 contextMenu->addAction (ACTION (SetOverlay)); |
601 contextMenu->addAction (ACTION (ClearOverlay)); |
605 contextMenu->addAction (ACTION (ClearOverlay)); |
602 contextMenu->addAction (ACTION (ModeSelect)); |
606 contextMenu->addAction (ACTION (ModeSelect)); |
603 contextMenu->addAction (ACTION (ModeDraw)); |
607 contextMenu->addAction (ACTION (ModeDraw)); |
604 contextMenu->addAction (ACTION (ModeCircle)); |
608 contextMenu->addAction (ACTION (ModeCircle)); |
605 |
609 |
606 if (R()->camera() != GL::Free) { |
610 if (R()->camera() != GL::Free) |
607 contextMenu->addSeparator(); |
611 { contextMenu->addSeparator(); |
608 contextMenu->addAction (ACTION (SetDrawDepth)); |
612 contextMenu->addAction (ACTION (SetDrawDepth)); |
609 } |
613 } |
610 |
614 |
611 contextMenu->exec (pos); |
615 contextMenu->exec (pos); |
612 } |
616 } |
613 |
617 |
614 // ============================================================================= |
618 // ============================================================================= |
615 // ----------------------------------------------------------------------------- |
619 // ----------------------------------------------------------------------------- |
616 void ForgeWindow::deleteObjVector (List<LDObject*> objs) { |
620 void ForgeWindow::deleteObjVector (List<LDObject*> objs) |
617 for (LDObject* obj : objs) { |
621 { for (LDObject * obj : objs) |
618 LDFile::current()->forgetObject (obj); |
622 { LDFile::current()->forgetObject (obj); |
619 delete obj; |
623 delete obj; |
620 } |
624 } |
621 } |
625 } |
622 |
626 |
623 // ============================================================================= |
627 // ============================================================================= |
624 // ----------------------------------------------------------------------------- |
628 // ----------------------------------------------------------------------------- |
625 void ForgeWindow::deleteByColor (const short colnum) { |
629 void ForgeWindow::deleteByColor (const short colnum) |
626 List<LDObject*> objs; |
630 { List<LDObject*> objs; |
627 for (LDObject* obj : LDFile::current()->objects()) { |
631 |
628 if (!obj->isColored() || obj->color() != colnum) |
632 for (LDObject * obj : LDFile::current()->objects()) |
|
633 { if (!obj->isColored() || obj->color() != colnum) |
629 continue; |
634 continue; |
630 |
635 |
631 objs << obj; |
636 objs << obj; |
632 } |
637 } |
633 |
638 |
634 deleteObjVector (objs); |
639 deleteObjVector (objs); |
635 } |
640 } |
636 |
641 |
637 // ============================================================================= |
642 // ============================================================================= |
638 // ----------------------------------------------------------------------------- |
643 // ----------------------------------------------------------------------------- |
639 void ForgeWindow::updateEditModeActions() { |
644 void ForgeWindow::updateEditModeActions() |
640 const EditMode mode = R()->editMode(); |
645 { const EditMode mode = R()->editMode(); |
641 ACTION (ModeSelect)->setChecked (mode == Select); |
646 ACTION (ModeSelect)->setChecked (mode == Select); |
642 ACTION (ModeDraw)->setChecked (mode == Draw); |
647 ACTION (ModeDraw)->setChecked (mode == Draw); |
643 ACTION (ModeCircle)->setChecked (mode == CircleMode); |
648 ACTION (ModeCircle)->setChecked (mode == CircleMode); |
644 } |
649 } |
645 |
650 |
646 // ============================================================================= |
651 // ============================================================================= |
647 // ----------------------------------------------------------------------------- |
652 // ----------------------------------------------------------------------------- |
648 void ForgeWindow::slot_editObject (QListWidgetItem* listitem) { |
653 void ForgeWindow::slot_editObject (QListWidgetItem* listitem) |
649 LDObject* obj = null; |
654 { LDObject* obj = null; |
650 for (LDObject* it : LDFile::current()->objects()) { |
655 |
651 if (it->qObjListEntry == listitem) { |
656 for (LDObject * it : LDFile::current()->objects()) |
652 obj = it; |
657 { if (it->qObjListEntry == listitem) |
|
658 { obj = it; |
653 break; |
659 break; |
654 } |
660 } |
655 } |
661 } |
656 |
662 |
657 AddObjectDialog::staticDialog (obj->getType(), obj); |
663 AddObjectDialog::staticDialog (obj->getType(), obj); |
658 } |
664 } |
659 |
665 |
660 // ============================================================================= |
666 // ============================================================================= |
661 // ----------------------------------------------------------------------------- |
667 // ----------------------------------------------------------------------------- |
662 void ForgeWindow::primitiveLoaderStart (ulong max) { |
668 void ForgeWindow::primitiveLoaderStart (ulong max) |
663 m_primLoaderWidget->show(); |
669 { m_primLoaderWidget->show(); |
664 m_primLoaderBar->setRange (0, max); |
670 m_primLoaderBar->setRange (0, max); |
665 m_primLoaderBar->setValue (0); |
671 m_primLoaderBar->setValue (0); |
666 m_primLoaderBar->setFormat ("%p%"); |
672 m_primLoaderBar->setFormat ("%p%"); |
667 } |
673 } |
668 |
674 |
669 // ============================================================================= |
675 // ============================================================================= |
670 // ----------------------------------------------------------------------------- |
676 // ----------------------------------------------------------------------------- |
671 void ForgeWindow::primitiveLoaderUpdate (ulong prog) { |
677 void ForgeWindow::primitiveLoaderUpdate (ulong prog) |
672 m_primLoaderBar->setValue (prog); |
678 { m_primLoaderBar->setValue (prog); |
673 } |
679 } |
674 |
680 |
675 // ============================================================================= |
681 // ============================================================================= |
676 // ----------------------------------------------------------------------------- |
682 // ----------------------------------------------------------------------------- |
677 void ForgeWindow::primitiveLoaderEnd() { |
683 void ForgeWindow::primitiveLoaderEnd() |
678 QTimer* hidetimer = new QTimer; |
684 { QTimer* hidetimer = new QTimer; |
679 connect (hidetimer, SIGNAL (timeout()), m_primLoaderWidget, SLOT (hide())); |
685 connect (hidetimer, SIGNAL (timeout()), m_primLoaderWidget, SLOT (hide())); |
680 hidetimer->setSingleShot (true); |
686 hidetimer->setSingleShot (true); |
681 hidetimer->start (1500); |
687 hidetimer->start (1500); |
682 m_primLoaderBar->setFormat (tr ("Done")); |
688 m_primLoaderBar->setFormat (tr ("Done")); |
683 log (tr ("Primitives scanned: %1 primitives listed"), m_primLoaderBar->value()); |
689 log (tr ("Primitives scanned: %1 primitives listed"), m_primLoaderBar->value()); |
684 } |
690 } |
685 |
691 |
686 // ============================================================================= |
692 // ============================================================================= |
687 // ----------------------------------------------------------------------------- |
693 // ----------------------------------------------------------------------------- |
688 void ForgeWindow::save (LDFile* f, bool saveAs) { |
694 void ForgeWindow::save (LDFile* f, bool saveAs) |
689 str path = f->name(); |
695 { str path = f->name(); |
690 |
696 |
691 if (path.length() == 0 || saveAs) { |
697 if (path.length() == 0 || saveAs) |
692 path = QFileDialog::getSaveFileName (g_win, tr ("Save As"), |
698 { path = QFileDialog::getSaveFileName (g_win, tr ("Save As"), |
693 LDFile::current()->name(), tr ("LDraw files (*.dat *.ldr)")); |
699 LDFile::current()->name(), tr ("LDraw files (*.dat *.ldr)")); |
694 |
700 |
695 if (path.length() == 0) { |
701 if (path.length() == 0) |
696 // User didn't give a file name. This happens if the user cancelled |
702 { // User didn't give a file name. This happens if the user cancelled |
697 // saving in the save file dialog. Abort. |
703 // saving in the save file dialog. Abort. |
698 return; |
704 return; |
699 } |
705 } |
700 } |
706 } |
701 |
707 |
702 if (f->save (path)) { |
708 if (f->save (path)) |
703 f->setName (path); |
709 { f->setName (path); |
704 |
710 |
705 if (f == LDFile::current()) |
711 if (f == LDFile::current()) |
706 g_win->updateTitle(); |
712 g_win->updateTitle(); |
707 |
713 |
708 log ("Saved to %1.", path); |
714 log ("Saved to %1.", path); |
709 |
715 |
710 // Add it to recent files |
716 // Add it to recent files |
711 addRecentFile (path); |
717 addRecentFile (path); |
712 } else { |
718 } |
713 str message = fmt (tr ("Failed to save to %1: %2"), path, strerror (errno)); |
719 else |
714 |
720 { str message = fmt (tr ("Failed to save to %1: %2"), path, strerror (errno)); |
|
721 |
715 // Tell the user the save failed, and give the option for saving as with it. |
722 // Tell the user the save failed, and give the option for saving as with it. |
716 QMessageBox dlg (QMessageBox::Critical, tr ("Save Failure"), message, QMessageBox::Close, g_win); |
723 QMessageBox dlg (QMessageBox::Critical, tr ("Save Failure"), message, QMessageBox::Close, g_win); |
717 |
724 |
718 // Add a save-as button |
725 // Add a save-as button |
719 QPushButton* saveAsBtn = new QPushButton (tr ("Save As")); |
726 QPushButton* saveAsBtn = new QPushButton (tr ("Save As")); |
720 saveAsBtn->setIcon (getIcon ("file-save-as")); |
727 saveAsBtn->setIcon (getIcon ("file-save-as")); |
721 dlg.addButton (saveAsBtn, QMessageBox::ActionRole); |
728 dlg.addButton (saveAsBtn, QMessageBox::ActionRole); |
722 dlg.setDefaultButton (QMessageBox::Close); |
729 dlg.setDefaultButton (QMessageBox::Close); |
723 dlg.exec(); |
730 dlg.exec(); |
724 |
731 |
725 if (dlg.clickedButton() == saveAsBtn) |
732 if (dlg.clickedButton() == saveAsBtn) |
726 save (f, true); // yay recursion! |
733 save (f, true); // yay recursion! |
727 } |
734 } |
728 } |
735 } |
729 |
736 |
730 void ForgeWindow::addMessage (str msg) { |
737 void ForgeWindow::addMessage (str msg) |
731 m_msglog->addLine (msg); |
738 { m_msglog->addLine (msg); |
732 } |
739 } |
733 |
740 |
734 // ============================================================================ |
741 // ============================================================================ |
735 void ObjectList::contextMenuEvent (QContextMenuEvent* ev) { |
742 void ObjectList::contextMenuEvent (QContextMenuEvent* ev) |
736 g_win->spawnContextMenu (ev->globalPos()); |
743 { g_win->spawnContextMenu (ev->globalPos()); |
737 } |
744 } |
738 |
745 |
739 // ============================================================================= |
746 // ============================================================================= |
740 // ----------------------------------------------------------------------------- |
747 // ----------------------------------------------------------------------------- |
741 QPixmap getIcon (str iconName) { |
748 QPixmap getIcon (str iconName) |
742 return (QPixmap (fmt (":/icons/%1.png", iconName))); |
749 { return (QPixmap (fmt (":/icons/%1.png", iconName))); |
743 } |
750 } |
744 |
751 |
745 // ============================================================================= |
752 // ============================================================================= |
746 bool confirm (str msg) { |
753 bool confirm (str msg) |
747 return confirm (ForgeWindow::tr ("Confirm"), msg); |
754 { return confirm (ForgeWindow::tr ("Confirm"), msg); |
748 } |
755 } |
749 |
756 |
750 bool confirm (str title, str msg) { |
757 bool confirm (str title, str msg) |
751 return QMessageBox::question (g_win, title, msg, |
758 { return QMessageBox::question (g_win, title, msg, |
752 (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::Yes; |
759 (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::Yes; |
753 } |
760 } |
754 |
761 |
755 // ============================================================================= |
762 // ============================================================================= |
756 void critical (str msg) { |
763 void critical (str msg) |
757 QMessageBox::critical (g_win, ForgeWindow::tr("Error"), msg, |
764 { QMessageBox::critical (g_win, ForgeWindow::tr ("Error"), msg, |
758 (QMessageBox::Close), QMessageBox::Close); |
765 (QMessageBox::Close), QMessageBox::Close); |
759 } |
766 } |
760 |
767 |
761 // ============================================================================= |
768 // ============================================================================= |
762 QIcon makeColorIcon (LDColor* colinfo, const ushort size) { |
769 QIcon makeColorIcon (LDColor* colinfo, const ushort size) |
763 // Create an image object and link a painter to it. |
770 { // Create an image object and link a painter to it. |
764 QImage img (size, size, QImage::Format_ARGB32); |
771 QImage img (size, size, QImage::Format_ARGB32); |
765 QPainter paint (&img); |
772 QPainter paint (&img); |
766 |
773 |
767 QColor col = colinfo->faceColor; |
774 QColor col = colinfo->faceColor; |
768 if (colinfo->index == maincolor) { |
775 |
769 // Use the user preferences for main color here |
776 if (colinfo->index == maincolor) |
|
777 { // Use the user preferences for main color here |
770 col = gl_maincolor.value; |
778 col = gl_maincolor.value; |
771 col.setAlphaF (gl_maincolor_alpha); |
779 col.setAlphaF (gl_maincolor_alpha); |
772 } |
780 } |
773 |
781 |
774 // Paint the icon |
782 // Paint the icon |
775 paint.fillRect (QRect (0, 0, size, size), colinfo->edgeColor); |
783 paint.fillRect (QRect (0, 0, size, size), colinfo->edgeColor); |
776 paint.drawPixmap (QRect (1, 1, size - 2, size - 2), getIcon ("checkerboard"), QRect (0, 0, 8, 8)); |
784 paint.drawPixmap (QRect (1, 1, size - 2, size - 2), getIcon ("checkerboard"), QRect (0, 0, 8, 8)); |
777 paint.fillRect (QRect (1, 1, size - 2, size - 2), col); |
785 paint.fillRect (QRect (1, 1, size - 2, size - 2), col); |
778 return QIcon (QPixmap::fromImage (img)); |
786 return QIcon (QPixmap::fromImage (img)); |
779 } |
787 } |
780 |
788 |
781 // ============================================================================= |
789 // ============================================================================= |
782 void makeColorSelector (QComboBox* box) { |
790 void makeColorSelector (QComboBox* box) |
783 std::map<short, ulong> counts; |
791 { std::map<short, ulong> counts; |
784 |
792 |
785 for (LDObject* obj : LDFile::current()->objects()) { |
793 for (LDObject * obj : LDFile::current()->objects()) |
786 if (!obj->isColored()) |
794 { if (!obj->isColored()) |
787 continue; |
795 continue; |
788 |
796 |
789 if (counts.find (obj->color()) == counts.end()) |
797 if (counts.find (obj->color()) == counts.end()) |
790 counts[obj->color()] = 1; |
798 counts[obj->color()] = 1; |
791 else |
799 else |
792 counts[obj->color()]++; |
800 counts[obj->color()]++; |
793 } |
801 } |
794 |
802 |
795 box->clear(); |
803 box->clear(); |
796 ulong row = 0; |
804 ulong row = 0; |
797 for (const auto& pair : counts) { |
805 |
798 LDColor* col = getColor (pair.first); |
806 for (const auto & pair : counts) |
|
807 { LDColor* col = getColor (pair.first); |
799 assert (col != null); |
808 assert (col != null); |
800 |
809 |
801 QIcon ico = makeColorIcon (col, 16); |
810 QIcon ico = makeColorIcon (col, 16); |
802 box->addItem (ico, fmt ("[%1] %2 (%3 object%4)", |
811 box->addItem (ico, fmt ("[%1] %2 (%3 object%4)", |
803 pair.first, col->name, pair.second, plural (pair.second))); |
812 pair.first, col->name, pair.second, plural (pair.second))); |
804 box->setItemData (row, pair.first); |
813 box->setItemData (row, pair.first); |
805 |
814 |
806 ++row; |
815 ++row; |
807 } |
816 } |
808 } |
817 } |
809 |
818 |
810 void ForgeWindow::setStatusBarText (str text) { |
819 void ForgeWindow::setStatusBarText (str text) |
811 statusBar()->showMessage (text); |
820 { statusBar()->showMessage (text); |
812 } |
821 } |
813 |
822 |
814 void ForgeWindow::clearSelection() { |
823 void ForgeWindow::clearSelection() |
815 m_sel.clear(); |
824 { m_sel.clear(); |
816 } |
825 } |
817 |
826 |
818 Ui_LDForgeUI* ForgeWindow::interface() const { |
827 Ui_LDForgeUI* ForgeWindow::interface() const |
819 return ui; |
828 { return ui; |
820 } |
829 } |
821 |
830 |
822 #define act(N) QAction* ForgeWindow::action##N() { return ui->action##N; } |
831 #define act(N) QAction* ForgeWindow::action##N() { return ui->action##N; } |
823 #include "actions.h" |
832 #include "actions.h" |
824 |
833 |
825 void ForgeWindow::updateFileList() { |
834 void ForgeWindow::updateFileList() |
826 ui->fileList->clear(); |
835 { ui->fileList->clear(); |
827 |
836 |
828 for (LDFile* f : g_loadedFiles) { |
837 for (LDFile * f : g_loadedFiles) |
829 // Don't list implicit files unless explicitly desired. |
838 { // Don't list implicit files unless explicitly desired. |
830 if (f->implicit() && !gui_implicitfiles) |
839 if (f->implicit() && !gui_implicitfiles) |
831 continue; |
840 continue; |
832 |
841 |
833 // Add an item to the list for this file and store a pointer to it in |
842 // Add an item to the list for this file and store a pointer to it in |
834 // the file, so we can find files by the list item. |
843 // the file, so we can find files by the list item. |
835 ui->fileList->addItem (""); |
844 ui->fileList->addItem (""); |
836 QListWidgetItem* item = ui->fileList->item (ui->fileList->count() - 1); |
845 QListWidgetItem* item = ui->fileList->item (ui->fileList->count() - 1); |
837 f->setListItem (item); |
846 f->setListItem (item); |
838 |
847 |
839 updateFileListItem (f); |
848 updateFileListItem (f); |
840 } |
849 } |
841 } |
850 } |
842 |
851 |
843 void ForgeWindow::updateFileListItem (LDFile* f) { |
852 void ForgeWindow::updateFileListItem (LDFile* f) |
844 if (f->listItem() == null) { |
853 { if (f->listItem() == null) |
845 // We don't have a list item for this file, so the list either doesn't |
854 { // We don't have a list item for this file, so the list either doesn't |
846 // exist yet or is out of date. Build the list now. |
855 // exist yet or is out of date. Build the list now. |
847 updateFileList(); |
856 updateFileList(); |
848 return; |
857 return; |
849 } |
858 } |
850 |
859 |
851 // If this is the current file, it also needs to be the selected item on |
860 // If this is the current file, it also needs to be the selected item on |
852 // the list. |
861 // the list. |
853 if (f == LDFile::current()) |
862 if (f == LDFile::current()) |
854 ui->fileList->setCurrentItem (f->listItem()); |
863 ui->fileList->setCurrentItem (f->listItem()); |
855 |
864 |
856 // If we list implicit files, draw them with a shade of gray to make them |
865 // If we list implicit files, draw them with a shade of gray to make them |
857 // distinct. |
866 // distinct. |
858 if (f->implicit()) |
867 if (f->implicit()) |
859 f->listItem()->setForeground (QColor (96, 96, 96)); |
868 f->listItem()->setForeground (QColor (96, 96, 96)); |
860 |
869 |
861 f->listItem()->setText (f->getShortName()); |
870 f->listItem()->setText (f->getShortName()); |
862 |
871 |
863 // If the file has unsaved changes, draw a little icon next to it to mark that. |
872 // If the file has unsaved changes, draw a little icon next to it to mark that. |
864 f->listItem()->setIcon (f->hasUnsavedChanges() ? getIcon ("file-save") : QIcon()); |
873 f->listItem()->setIcon (f->hasUnsavedChanges() ? getIcon ("file-save") : QIcon()); |
865 } |
874 } |
866 |
875 |
867 void ForgeWindow::beginAction (QAction* act) { |
876 void ForgeWindow::beginAction (QAction* act) |
868 // Open the history so we can record the edits done during this action. |
877 { // Open the history so we can record the edits done during this action. |
869 if (act != ACTION (Undo) && act != ACTION (Redo) && act != ACTION (Open)) |
878 if (act != ACTION (Undo) && act != ACTION (Redo) && act != ACTION (Open)) |
870 LDFile::current()->openHistory(); |
879 LDFile::current()->openHistory(); |
871 } |
880 } |
872 |
881 |
873 void ForgeWindow::endAction() { |
882 void ForgeWindow::endAction() |
874 // Close the history now. |
883 { // Close the history now. |
875 LDFile::current()->closeHistory(); |
884 LDFile::current()->closeHistory(); |
876 |
885 |
877 // Update the list item of the current file - we may need to draw an icon |
886 // Update the list item of the current file - we may need to draw an icon |
878 // now that marks it as having unsaved changes. |
887 // now that marks it as having unsaved changes. |
879 updateFileListItem (LDFile::current()); |
888 updateFileListItem (LDFile::current()); |
880 } |
889 } |
881 |
890 |
882 // ============================================================================= |
891 // ============================================================================= |
883 // A file is selected from the list of files on the left of the screen. Find out |
892 // A file is selected from the list of files on the left of the screen. Find out |
884 // which file was picked and change to it. |
893 // which file was picked and change to it. |
885 void ForgeWindow::changeCurrentFile() { |
894 void ForgeWindow::changeCurrentFile() |
886 LDFile* f = null; |
895 { LDFile* f = null; |
887 QListWidgetItem* item = ui->fileList->currentItem(); |
896 QListWidgetItem* item = ui->fileList->currentItem(); |
888 |
897 |
889 // Find the file pointer of the item that was selected. |
898 // Find the file pointer of the item that was selected. |
890 for (LDFile* it : g_loadedFiles) { |
899 for (LDFile * it : g_loadedFiles) |
891 if (it->listItem() == item) { |
900 { if (it->listItem() == item) |
892 f = it; |
901 { f = it; |
893 break; |
902 break; |
894 } |
903 } |
895 } |
904 } |
896 |
905 |
897 // If we picked the same file we're currently on, we don't need to do |
906 // If we picked the same file we're currently on, we don't need to do |
898 // anything. |
907 // anything. |
899 if (!f || f == LDFile::current()) |
908 if (!f || f == LDFile::current()) |
900 return; |
909 return; |
901 |
910 |
902 LDFile::setCurrent (f); |
911 LDFile::setCurrent (f); |
903 } |
912 } |
904 |
913 |
905 void ForgeWindow::refreshObjectList() { |
914 void ForgeWindow::refreshObjectList() |
|
915 { |
906 #if 0 |
916 #if 0 |
907 ui->objectList->clear(); |
917 ui->objectList->clear(); |
908 LDFile* f = LDFile::current(); |
918 LDFile* f = LDFile::current(); |
909 |
919 |
910 for (LDObject* obj : *f) |
920 for (LDObject * obj : *f) |
911 ui->objectList->addItem (obj->qObjListEntry); |
921 ui->objectList->addItem (obj->qObjListEntry); |
|
922 |
912 #endif |
923 #endif |
913 |
924 |
914 buildObjList(); |
925 buildObjList(); |
915 } |
926 } |
916 |
927 |
917 QImage imageFromScreencap (uchar* data, ushort w, ushort h) { |
928 QImage imageFromScreencap (uchar* data, ushort w, ushort h) |
918 // GL and Qt formats have R and B swapped. Also, GL flips Y - correct it as well. |
929 { // GL and Qt formats have R and B swapped. Also, GL flips Y - correct it as well. |
919 return QImage (data, w, h, QImage::Format_ARGB32).rgbSwapped().mirrored(); |
930 return QImage (data, w, h, QImage::Format_ARGB32).rgbSwapped().mirrored(); |
920 } |
931 } |
921 |
932 |
922 // ============================================================================= |
933 // ============================================================================= |
923 // ----------------------------------------------------------------------------- |
934 // ----------------------------------------------------------------------------- |
924 LDQuickColor::LDQuickColor (LDColor* color, QToolButton* toolButton) : |
935 LDQuickColor::LDQuickColor (LDColor* color, QToolButton* toolButton) : |
925 m_color (color), |
936 m_color (color), |
926 m_toolButton (toolButton) {} |
937 m_toolButton (toolButton) {} |
927 |
938 |
928 LDQuickColor LDQuickColor::getSeparator() { |
939 LDQuickColor LDQuickColor::getSeparator() |
929 return LDQuickColor (null, null); |
940 { return LDQuickColor (null, null); |
930 } |
941 } |
931 |
942 |
932 bool LDQuickColor::isSeparator() const { |
943 bool LDQuickColor::isSeparator() const |
933 return color() == null; |
944 { return color() == null; |
934 } |
945 } |
935 #include "moc_gui.cpp" |
|