src/gui_actions.cpp

changeset 183
f1b8cb53d2a2
child 188
4e686b771996
equal deleted inserted replaced
182:9374fea8f77f 183:f1b8cb53d2a2
1 /*
2 * LDForge: LDraw parts authoring CAD
3 * Copyright (C) 2013 Santeri Piippo
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <qfiledialog.h>
20 #include <qmessagebox.h>
21 #include "gui.h"
22 #include "file.h"
23 #include "history.h"
24 #include "newPartDialog.h"
25 #include "configDialog.h"
26 #include "addObjectDialog.h"
27 #include "aboutDialog.h"
28 #include "misc.h"
29 #include "ldrawPathDialog.h"
30
31 // =============================================================================
32 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
33 // =============================================================================
34 MAKE_ACTION (newFile, "&New", "brick", "Create a new part model.", CTRL (N)) {
35 NewPartDialog::StaticDialog ();
36 }
37
38 // =============================================================================
39 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
40 // =============================================================================
41 MAKE_ACTION (open, "&Open", "file-open", "Load a part model from a file.", CTRL (O)) {
42 str zName;
43 zName += QFileDialog::getOpenFileName (g_win, "Open File",
44 "", "LDraw files (*.dat *.ldr)");
45
46 if (~zName)
47 openMainFile (zName);
48 }
49
50 // =============================================================================
51 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
52 // =============================================================================
53 void doSave (bool saveAs) {
54 str path = g_curfile->m_filename;
55
56 if (~path == 0 || saveAs) {
57 path = QFileDialog::getSaveFileName (g_win, "Save As",
58 "", "LDraw files (*.dat *.ldr)");
59
60 if (~path == 0) {
61 // User didn't give a file name. This happens if the user cancelled
62 // saving in the save file dialog. Abort.
63 return;
64 }
65 }
66
67 if (g_curfile->save (path)) {
68 g_curfile->m_filename = path;
69 g_win->setTitle ();
70
71 logf ("Saved successfully to %s\n", path.chars ());
72 } else {
73 setlocale (LC_ALL, "C");
74
75 // Tell the user the save failed, and give the option for saving as with it.
76 QMessageBox dlg (QMessageBox::Critical, "Save Failure",
77 fmt ("Failed to save to %s\nReason: %s", path.chars(), strerror (g_curfile->lastError)),
78 QMessageBox::Close, g_win);
79
80 QPushButton* saveAsBtn = new QPushButton ("Save As");
81 saveAsBtn->setIcon (getIcon ("file-save-as"));
82 dlg.addButton (saveAsBtn, QMessageBox::ActionRole);
83 dlg.setDefaultButton (QMessageBox::Close);
84 dlg.exec ();
85
86 if (dlg.clickedButton () == saveAsBtn)
87 doSave (true); // yay recursion!
88 }
89 }
90
91 // =============================================================================
92 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
93 // =============================================================================
94 MAKE_ACTION (save, "&Save", "file-save", "Save the part model.", CTRL (S)) {
95 doSave (false);
96 }
97
98 // =============================================================================
99 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
100 // =============================================================================
101 MAKE_ACTION (saveAs, "Save &As", "file-save-as", "Save the part model to a specific file.", CTRL_SHIFT (S)) {
102 doSave (true);
103 }
104
105 // =============================================================================
106 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
107 // =============================================================================
108 MAKE_ACTION (settings, "Settin&gs", "settings", "Edit the settings of " APPNAME ".", (0)) {
109 ConfigDialog::staticDialog ();
110 }
111
112 MAKE_ACTION (setLDrawPath, "Set LDraw Path", "settings", "Change the LDraw directory path.", (0)) {
113 LDrawPathDialog dlg (true);
114 dlg.exec ();
115 }
116
117 // =============================================================================
118 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
119 // =============================================================================
120 MAKE_ACTION (exit, "&Exit", "exit", "Close " APPNAME ".", CTRL (Q)) {
121 exit (0);
122 }
123
124 // =============================================================================
125 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
126 // =============================================================================
127 MAKE_ACTION (newSubfile, "New Subfile", "add-subfile", "Creates a new subfile reference.", 0) {
128 AddObjectDialog::staticDialog (LDObject::Subfile, null);
129 }
130
131 MAKE_ACTION (newLine, "New Line", "add-line", "Creates a new line.", 0) {
132 AddObjectDialog::staticDialog (LDObject::Line, null);
133 }
134
135 MAKE_ACTION (newTriangle, "New Triangle", "add-triangle", "Creates a new triangle.", 0) {
136 AddObjectDialog::staticDialog (LDObject::Triangle, null);
137 }
138
139 MAKE_ACTION (newQuad, "New Quadrilateral", "add-quad", "Creates a new quadrilateral.", 0) {
140 AddObjectDialog::staticDialog (LDObject::Quad, null);
141 }
142
143 MAKE_ACTION (newCondLine, "New Conditional Line", "add-condline", "Creates a new conditional line.", 0) {
144 AddObjectDialog::staticDialog (LDObject::CondLine, null);
145 }
146
147 MAKE_ACTION (newComment, "New Comment", "add-comment", "Creates a new comment.", 0) {
148 AddObjectDialog::staticDialog (LDObject::Comment, null);
149 }
150
151 MAKE_ACTION (newBFC, "New BFC Statement", "add-bfc", "Creates a new BFC statement.", 0) {
152 AddObjectDialog::staticDialog (LDObject::BFC, null);
153 }
154
155 MAKE_ACTION (newVertex, "New Vertex", "add-vertex", "Creates a new vertex.", 0) {
156 AddObjectDialog::staticDialog (LDObject::Vertex, null);
157 }
158
159 MAKE_ACTION (newRadial, "New Radial", "add-radial", "Creates a new radial.", 0) {
160 AddObjectDialog::staticDialog (LDObject::Radial, null);
161 }
162
163 MAKE_ACTION (editObject, "Edit Object", "edit-object", "Edits this object.", 0) {
164 if (g_win->sel ().size () != 1)
165 return;
166
167 LDObject* obj = g_win->sel ()[0];
168 AddObjectDialog::staticDialog (obj->getType (), obj);
169 }
170
171 MAKE_ACTION (help, "Help", "help", "Shows the " APPNAME " help manual.", KEY (F1)) {
172
173 }
174
175 // =============================================================================
176 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
177 // =============================================================================
178 MAKE_ACTION (about, "About " APPNAME, "ldforge",
179 "Shows information about " APPNAME ".", (0))
180 {
181 AboutDialog dlg;
182 dlg.exec ();
183 }
184
185 MAKE_ACTION (aboutQt, "About Qt", "qt", "Shows information about Qt.", (0)) {
186 QMessageBox::aboutQt (g_win);
187 }
188
189 // =============================================================================
190 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
191 // =============================================================================
192 MAKE_ACTION (selectAll, "Select All", "select-all", "Selects all objects.", CTRL (A)) {
193 g_win->sel ().clear ();
194
195 for (LDObject* obj : g_curfile->m_objs)
196 g_win->sel ().push_back (obj);
197
198 g_win->updateSelection ();
199 }
200
201 // =============================================================================
202 MAKE_ACTION (selectByColor, "Select by Color", "select-color",
203 "Select all objects by the given color.", CTRL_SHIFT (A))
204 {
205 short dColor = g_win->getSelectedColor ();
206
207 if (dColor == -1)
208 return; // no consensus on color
209
210 g_win->sel ().clear ();
211 for (LDObject* obj : g_curfile->m_objs)
212 if (obj->dColor == dColor)
213 g_win->sel ().push_back (obj);
214
215 g_win->updateSelection ();
216 }
217
218 // =============================================================================
219 MAKE_ACTION (selectByType, "Select by Type", "select-type",
220 "Select all objects by the given type.", (0))
221 {
222 if (g_win->sel ().size () == 0)
223 return;
224
225 LDObject::Type eType = g_win->uniformSelectedType ();
226
227 if (eType == LDObject::Unidentified)
228 return;
229
230 // If we're selecting subfile references, the reference filename must also
231 // be uniform.
232 str zRefName;
233
234 if (eType == LDObject::Subfile) {
235 zRefName = static_cast<LDSubfile*> (g_win->sel ()[0])->zFileName;
236
237 for (LDObject* pObj : g_win->sel ())
238 if (static_cast<LDSubfile*> (pObj)->zFileName != zRefName)
239 return;
240 }
241
242 g_win->sel ().clear ();
243 for (LDObject* obj : g_curfile->m_objs) {
244 if (obj->getType() != eType)
245 continue;
246
247 if (eType == LDObject::Subfile && static_cast<LDSubfile*> (obj)->zFileName != zRefName)
248 continue;
249
250 g_win->sel ().push_back (obj);
251 }
252
253 g_win->updateSelection ();
254 }
255
256 // =============================================================================
257 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
258 // =============================================================================
259 MAKE_ACTION (gridCoarse, "Coarse Grid", "grid-coarse", "Set the grid to Coarse", CTRL (1)) {
260 grid = Grid::Coarse;
261 g_win->updateGridToolBar ();
262 }
263
264 MAKE_ACTION (gridMedium, "Medium Grid", "grid-medium", "Set the grid to Medium", CTRL (2)) {
265 grid = Grid::Medium;
266 g_win->updateGridToolBar ();
267 }
268
269 MAKE_ACTION (gridFine, "Fine Grid", "grid-fine", "Set the grid to Fine", CTRL (3)) {
270 grid = Grid::Fine;
271 g_win->updateGridToolBar ();
272 }
273
274 // =============================================================================
275 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
276 // =============================================================================
277 MAKE_ACTION (resetView, "Reset View", "reset-view", "Reset view angles, pan and zoom", CTRL (0)) {
278 g_win->R ()->resetAngles ();
279 g_win->R ()->update ();
280 }
281
282 // =============================================================================
283 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
284 // =============================================================================
285 MAKE_ACTION (insertFrom, "Insert from File", "insert-from", "Insert LDraw data from a file.", (0)) {
286 str fname = QFileDialog::getOpenFileName ();
287 ulong idx = g_win->getInsertionPoint ();
288
289 if (!~fname)
290 return;
291
292 FILE* fp = fopen (fname, "r");
293 if (!fp) {
294 critical (fmt ("Couldn't open %s\n%s", fname.chars(), strerror (errno)));
295 return;
296 }
297
298 std::vector<LDObject*> historyCopies;
299 std::vector<ulong> historyIndices;
300 std::vector<LDObject*> objs = loadFileContents (fp, null);
301
302 g_win->sel ().clear ();
303
304 for (LDObject* obj : objs) {
305 historyCopies.push_back (obj->clone ());
306 historyIndices.push_back (idx);
307 g_curfile->insertObj (idx, obj);
308 g_win->sel ().push_back (obj);
309
310 idx++;
311 }
312
313 if (historyCopies.size() > 0) {
314 History::addEntry (new AddHistory (historyIndices, historyCopies));
315 g_win->refresh ();
316 g_win->scrollToSelection ();
317 }
318 }
319
320 // =============================================================================
321 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
322 // =============================================================================
323 MAKE_ACTION (insertRaw, "Insert Raw", "insert-raw", "Type in LDraw code to insert.", (0)) {
324 ulong idx = g_win->getInsertionPoint ();
325
326 QDialog* const dlg = new QDialog;
327 QVBoxLayout* const layout = new QVBoxLayout;
328 QTextEdit* const te_edit = new QTextEdit;
329 QDialogButtonBox* const bbx_buttons = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
330 std::vector<LDObject*> historyCopies;
331 std::vector<ulong> historyIndices;
332
333 layout->addWidget (te_edit);
334 layout->addWidget (bbx_buttons);
335 dlg->setLayout (layout);
336 dlg->setWindowTitle (APPNAME ": Insert Raw");
337 dlg->connect (bbx_buttons, SIGNAL (accepted ()), dlg, SLOT (accept ()));
338 dlg->connect (bbx_buttons, SIGNAL (rejected ()), dlg, SLOT (reject ()));
339
340 if (dlg->exec () == false)
341 return;
342
343 g_win->sel ().clear ();
344
345 for (str line : str (te_edit->toPlainText ()).split ("\n")) {
346 LDObject* obj = parseLine (line);
347
348 g_curfile->insertObj (idx, obj);
349 historyIndices.push_back (idx);
350 historyCopies.push_back (obj->clone ());
351 g_win->sel ().push_back (obj);
352 idx++;
353 }
354
355 if (historyCopies.size () > 0) {
356 History::addEntry (new AddHistory (historyIndices, historyCopies));
357 g_win->refresh ();
358 g_win->scrollToSelection ();
359 }
360 }
361
362 // =============================================================================
363 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
364 // =============================================================================
365 MAKE_ACTION (screencap, "Screencap Part", "screencap", "Save a picture of the model", (0)) {
366 setlocale (LC_ALL, "C");
367
368 ushort w, h;
369 uchar* imagedata = g_win->R ()->screencap (w, h);
370
371 // GL and Qt formats have R and B swapped. Also, GL flips Y - correct it as well.
372 QImage img = QImage (imagedata, w, h, QImage::Format_ARGB32).rgbSwapped ().mirrored ();
373
374 str root = basename (g_curfile->m_filename.chars ());
375 if (root.substr (~root - 4, -1) == ".dat")
376 root -= 4;
377
378 str defaultname = (~root > 0) ? fmt ("%s.png", root.chars ()) : "";
379 str fname = QFileDialog::getSaveFileName (g_win, "Save Screencap", defaultname,
380 "PNG images (*.png);;JPG images (*.jpg);;BMP images (*.bmp);;All Files (*.*)");
381
382 if (~fname > 0 && !img.save (fname))
383 critical (fmt ("Couldn't open %s for writing to save screencap: %s", fname.chars(), strerror (errno)));
384
385 delete[] imagedata;
386 }
387
388 // =============================================================================
389 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
390 // =============================================================================
391 extern_cfg (bool, gl_axes);
392 MAKE_ACTION (axes, "Draw Axes", "axes", "Toggles drawing of axes", (0)) {
393 gl_axes = !gl_axes;
394 ACTION (axes)->setChecked (gl_axes);
395 g_win->R ()->update ();
396 }
397
398 // =============================================================================
399 MAKE_ACTION (beginDraw, "Begin Drawing", "draw", "Begin drawing geometry", KEY (Insert)) {
400 g_win->R ()->beginPlaneDraw ();
401 }
402
403 MAKE_ACTION (cancelDraw, "Cancel Drawing", "draw-cancel", "Cancel drawing geometry", KEY (Escape)) {
404 g_win->R ()->endPlaneDraw (false);
405 }
406
407 MAKE_ACTION (doneDraw, "Done Drawing", "draw-done", "Done drawing geometry", KEY (Enter)) {
408 g_win->R ()->endPlaneDraw (true);
409 }
410
411 // =============================================================================
412 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
413 // =============================================================================
414 MAKE_ACTION (visibility, "Toggle Visibility", "visibility", "Toggles visibility/hiding on objects.", (0)) {
415 for (LDObject* obj : g_win->sel ())
416 obj->setHidden (!obj->hidden ());
417
418 g_win->refresh ();
419 }

mercurial