1 /* BurrTools
2 *
3 * BurrTools is the legal property of its developers, whose
4 * names are listed in the COPYRIGHT file, which is included
5 * within the source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21 #include "mainwindow.h"
22
23 #include "configuration.h"
24 #include "groupseditor.h"
25 #include "placementbrowser.h"
26 #include "movementbrowser.h"
27 #include "imageexport.h"
28 #include "stlexport.h"
29 #include "guigridtype.h"
30 #include "grideditor.h"
31 #include "gridtypegui.h"
32 #include "statuswindow.h"
33 #include "tooltabs.h"
34 #include "WindowWidgets.h"
35 #include "BlockList.h"
36 #include "Images.h"
37
38 #include "multilinewindow.h"
39 #include "assertwindow.h"
40 #include "togglebutton.h"
41 #include "voxeleditgroup.h"
42 #include "view3dgroup.h"
43 #include "statusline.h"
44 #include "resultviewer.h"
45 #include "separator.h"
46 #include "buttongroup.h"
47 #include "constraintsgroup.h"
48 #include "blocklistgroup.h"
49 #include "vectorexportwindow.h"
50 #include "convertwindow.h"
51 #include "assmimportwindow.h"
52
53 #include "LFl_Tile.h"
54
55 #include <config.h>
56
57 #include "../lib/ps3dloader.h"
58 #include "../lib/voxel.h"
59 #include "../lib/puzzle.h"
60 #include "../lib/problem.h"
61 #include "../lib/assembler.h"
62 #include "../lib/solvethread.h"
63 #include "../lib/disassembly.h"
64 #include "../lib/disassembler_0.h"
65 #include "../lib/gridtype.h"
66 #include "../lib/disasmtomoves.h"
67 #include "../lib/assembly.h"
68 #include "../lib/converter.h"
69 #include "../lib/millable.h"
70 #include "../lib/voxeltable.h"
71 #include "../lib/solution.h"
72
73 #include "../tools/gzstream.h"
74 #include "../tools/xml.h"
75
76 #include "../flu/Flu_File_Chooser.h"
77
78 #include "../help/Fl_Help_Dialog.h"
79
80 #include <FL/Fl_Color_Chooser.H>
81 #include <FL/Fl_Tooltip.H>
82 #include <FL/Fl_Choice.H>
83 #include <FL/Fl_Pixmap.H>
84 #include <FL/Fl.H>
85 #include <FL/Fl_Group.H>
86 #include <FL/Fl_Tile.H>
87 #include <FL/Fl_Tabs.H>
88 #include <FL/Fl_Value_Output.H>
89 #include <FL/Fl_Check_Button.H>
90 #include <FL/Fl_Progress.H>
91 #include <FL/Fl_Output.H>
92 #include <FL/Fl_Value_Slider.H>
93 #include <FL/Fl_Menu_Bar.H>
94 #include <FL/Fl_File_Chooser.H>
95 #include <FL/Fl_Choice.H>
96 #include <FL/Fl_Value_Input.H>
97 #include <FL/fl_ask.H>
98
99 #include <fstream>
100
101 /* returns true, if file exists, this is not the
102 optimal way to do this. It would be better to open
103 the directory the file is supposed to be in and look there
104 but this is not really portable so this
105 */
fileExists(const char * n)106 bool fileExists(const char *n) {
107
108 FILE *f = fopen(n, "r");
109
110 if (f) {
111 fclose(f);
112 return true;
113 } else
114 return false;
115 }
116
cb_AddColor_stub(Fl_Widget *,void * v)117 static void cb_AddColor_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_AddColor(); }
cb_AddColor(void)118 void mainWindow_c::cb_AddColor(void) {
119
120 unsigned char r, g, b;
121
122 if (colorSelector->getSelection() == 0)
123 r = g = b = 128;
124 else
125 puzzle->getColor(colorSelector->getSelection()-1, &r, &g, &b);
126
127 if (fl_color_chooser("New colour", r, g, b)) {
128 puzzle->addColor(r, g, b);
129
130 // add this color as a default to the matrix, so that
131 // pieces of color x can be plces into cubes of color x
132 int col = puzzle->colorNumber();
133 for (unsigned int p = 0; p < puzzle->problemNumber(); p++)
134 puzzle->getProblem(p)->allowPlacement(col, col);
135
136 colorSelector->setSelection(puzzle->colorNumber());
137 changed = true;
138 View3D->getView()->showColors(puzzle, StatusLine->getColorMode());
139 updateInterface();
140 }
141 }
142
cb_RemoveColor_stub(Fl_Widget *,void * v)143 static void cb_RemoveColor_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_RemoveColor(); }
cb_RemoveColor(void)144 void mainWindow_c::cb_RemoveColor(void) {
145
146 if (colorSelector->getSelection() == 0)
147 fl_message("Can not delete the Neutral colour, this colour has to be there");
148 else {
149 changeColor(colorSelector->getSelection());
150 puzzle->removeColor(colorSelector->getSelection());
151
152 unsigned int current = colorSelector->getSelection();
153
154 while ((current > 0) && (current > puzzle->colorNumber()))
155 current--;
156
157 colorSelector->setSelection(current);
158
159 changed = true;
160 View3D->getView()->showColors(puzzle, StatusLine->getColorMode());
161 activateShape(PcSel->getSelection());
162 updateInterface();
163 }
164 }
165
cb_ChangeColor_stub(Fl_Widget *,void * v)166 static void cb_ChangeColor_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_ChangeColor(); }
cb_ChangeColor(void)167 void mainWindow_c::cb_ChangeColor(void) {
168
169 if (colorSelector->getSelection() == 0)
170 fl_message("Can not edit the Neutral colour");
171 else {
172 unsigned char r, g, b;
173 puzzle->getColor(colorSelector->getSelection()-1, &r, &g, &b);
174 if (fl_color_chooser("Change colour", r, g, b)) {
175 puzzle->changeColor(colorSelector->getSelection()-1, r, g, b);
176 changed = true;
177 View3D->getView()->showColors(puzzle, StatusLine->getColorMode());
178 updateInterface();
179 }
180 }
181 }
182
cb_NewShape_stub(Fl_Widget *,void * v)183 static void cb_NewShape_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_NewShape(); }
cb_NewShape(void)184 void mainWindow_c::cb_NewShape(void) {
185
186 if (PcSel->getSelection() < puzzle->shapeNumber()) {
187 const voxel_c * v = puzzle->getShape(PcSel->getSelection());
188 PcSel->setSelection(puzzle->addShape(v->getX(), v->getY(), v->getZ()));
189 } else
190 PcSel->setSelection(puzzle->addShape(ggt->defaultSize(), ggt->defaultSize(), ggt->defaultSize()));
191 pieceEdit->setZ(0);
192 updateInterface();
193 StatPieceInfo(PcSel->getSelection());
194 changed = true;
195 }
196
cb_DeleteShape_stub(Fl_Widget *,void * v)197 static void cb_DeleteShape_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_DeleteShape(); }
cb_DeleteShape(void)198 void mainWindow_c::cb_DeleteShape(void) {
199
200 unsigned int current = PcSel->getSelection();
201
202 if (current < puzzle->shapeNumber()) {
203
204 puzzle->removeShape(current);
205
206 if (puzzle->shapeNumber() == 0)
207 current = (unsigned int)-1;
208 else
209 while (current >= puzzle->shapeNumber())
210 current--;
211
212 activateShape(current);
213
214 PcSel->setSelection(current);
215 updateInterface();
216 StatPieceInfo(PcSel->getSelection());
217
218 changed = true;
219
220 } else
221
222 fl_message("No shape to delete selected!");
223
224 }
225
cb_CopyShape_stub(Fl_Widget *,void * v)226 static void cb_CopyShape_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_CopyShape(); }
cb_CopyShape(void)227 void mainWindow_c::cb_CopyShape(void) {
228
229 unsigned int current = PcSel->getSelection();
230
231 if (current < puzzle->shapeNumber()) {
232
233 PcSel->setSelection(puzzle->addShape(puzzle->getGridType()->getVoxel(puzzle->getShape(current))));
234 changed = true;
235
236 updateInterface();
237 StatPieceInfo(PcSel->getSelection());
238
239 } else
240
241 fl_message("No shape to copy selected!");
242
243 }
244
cb_NameShape_stub(Fl_Widget *,void * v)245 static void cb_NameShape_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_NameShape(); }
cb_NameShape(void)246 void mainWindow_c::cb_NameShape(void) {
247
248 if (PcSel->getSelection() < puzzle->shapeNumber()) {
249
250 const char * name = fl_input("Enter name for the shape", puzzle->getShape(PcSel->getSelection())->getName().c_str());
251
252 if (name) {
253 puzzle->getShape(PcSel->getSelection())->setName(name);
254 changed = true;
255 updateInterface();
256 }
257 }
258 }
259
cb_WeightInc_stub(Fl_Widget *,void * v)260 static void cb_WeightInc_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_WeightChange(1); }
cb_WeightDec_stub(Fl_Widget *,void * v)261 static void cb_WeightDec_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_WeightChange(-1); }
cb_WeightChange(int by)262 void mainWindow_c::cb_WeightChange(int by) {
263
264 if (PcSel->getSelection() < puzzle->shapeNumber()) {
265
266 voxel_c * v = puzzle->getShape(PcSel->getSelection());
267 v->setWeight(v->getWeight() + by);
268 changed = true;
269 updateInterface();
270 }
271 }
272
273
cb_TaskSelectionTab_stub(Fl_Widget * o,void * v)274 static void cb_TaskSelectionTab_stub(Fl_Widget* o, void* v) { ((mainWindow_c*)v)->cb_TaskSelectionTab((Fl_Tabs*)o); }
cb_TaskSelectionTab(Fl_Tabs * o)275 void mainWindow_c::cb_TaskSelectionTab(Fl_Tabs* o) {
276
277 if (o->value() == TabPieces) {
278 activateShape(PcSel->getSelection());
279 StatPieceInfo(PcSel->getSelection());
280 if (!shapeEditorWithBig3DView)
281 Small3DView();
282 else
283 Big3DView();
284 ViewSizes[currentTab] = View3D->getZoom();
285 if (ViewSizes[0] >= 0)
286 View3D->setZoom(ViewSizes[0]);
287 currentTab = 0;
288 } else if(o->value() == TabProblems) {
289
290 // make sure the selector has a valid problem selected, when there is one
291 if (puzzle->problemNumber() && (problemSelector->getSelection() >= puzzle->problemNumber()))
292 problemSelector->setSelection(puzzle->problemNumber()-1);
293
294 if (problemSelector->getSelection() < puzzle->problemNumber()) {
295 activateProblem(problemSelector->getSelection());
296 }
297 StatProblemInfo(problemSelector->getSelection());
298 Big3DView();
299 ViewSizes[currentTab] = View3D->getZoom();
300 if (ViewSizes[1] >= 0)
301 View3D->setZoom(ViewSizes[1]);
302 currentTab = 1;
303 } else if(o->value() == TabSolve) {
304
305 // make sure the selector has a valid problem selected, when there is one
306 if (puzzle->problemNumber() && (solutionProblem->getSelection() >= puzzle->problemNumber()))
307 solutionProblem->setSelection(puzzle->problemNumber()-1);
308
309 if ((solutionProblem->getSelection() < puzzle->problemNumber()) &&
310 (SolutionSel->value()-1 < puzzle->getProblem(solutionProblem->getSelection())->solutionNumber())) {
311 activateSolution(solutionProblem->getSelection(), int(SolutionSel->value()-1));
312 }
313 Big3DView();
314 StatusLine->setText("");
315 ViewSizes[currentTab] = View3D->getZoom();
316 if (ViewSizes[2] >= 0)
317 View3D->setZoom(ViewSizes[2]);
318 currentTab = 2;
319 }
320
321 updateInterface();
322 }
323
cb_TransformPiece_stub(Fl_Widget *,void * v)324 static void cb_TransformPiece_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_TransformPiece(); }
cb_TransformPiece(void)325 void mainWindow_c::cb_TransformPiece(void) {
326
327 if (pieceTools->operationToAll()) {
328 for (unsigned int i = 0; i < puzzle->shapeNumber(); i++)
329 changeShape(i);
330 } else {
331 changeShape(PcSel->getSelection());
332 }
333
334 StatPieceInfo(PcSel->getSelection());
335 activateShape(PcSel->getSelection());
336
337 changed = true;
338 }
339
cb_EditSym_stub(Fl_Widget * o,void * v)340 static void cb_EditSym_stub(Fl_Widget* o, void* v) {
341 ((mainWindow_c*)v)->cb_EditSym(((LToggleButton_c*)o)->value(), ((LToggleButton_c*)o)->ButtonVal());
342 }
cb_EditSym(int onoff,int value)343 void mainWindow_c::cb_EditSym(int onoff, int value) {
344 if (onoff) {
345 editSymmetries |= value;
346 } else {
347 editSymmetries &= ~value;
348 }
349
350 pieceEdit->editSymmetries(editSymmetries);
351 }
352
cb_EditChoice_stub(Fl_Widget *,void * v)353 static void cb_EditChoice_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_EditChoice(); }
cb_EditChoice(void)354 void mainWindow_c::cb_EditChoice(void) {
355 switch(editChoice->getSelected()) {
356 case 0:
357 pieceEdit->editChoice(gridEditor_c::TSK_SET);
358 break;
359 case 1:
360 pieceEdit->editChoice(gridEditor_c::TSK_VAR);
361 break;
362 case 2:
363 pieceEdit->editChoice(gridEditor_c::TSK_RESET);
364 break;
365 case 3:
366 pieceEdit->editChoice(gridEditor_c::TSK_COLOR);
367 break;
368 }
369 }
370
cb_EditMode_stub(Fl_Widget *,void * v)371 static void cb_EditMode_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_EditMode(); }
cb_EditMode(void)372 void mainWindow_c::cb_EditMode(void) {
373 switch(editMode->getSelected()) {
374 case 0:
375 pieceEdit->editType(gridEditor_c::EDT_RUBBER);
376 config.useRubberband(true);
377 break;
378 case 1:
379 pieceEdit->editType(gridEditor_c::EDT_SINGLE);
380 config.useRubberband(false);
381 break;
382 }
383 }
384
cb_PcSel_stub(Fl_Widget * o,void * v)385 static void cb_PcSel_stub(Fl_Widget* o, void* v) { ((mainWindow_c*)v)->cb_PcSel((LBlockListGroup_c*)o); }
cb_PcSel(LBlockListGroup_c * grp)386 void mainWindow_c::cb_PcSel(LBlockListGroup_c* grp) {
387 int reason = grp->getReason();
388
389 switch(reason) {
390 case PieceSelector::RS_CHANGEDSELECTION:
391 activateShape(PcSel->getSelection());
392 updateInterface();
393 StatPieceInfo(PcSel->getSelection());
394 break;
395 }
396 }
397
cb_SolProbSel_stub(Fl_Widget * o,void * v)398 static void cb_SolProbSel_stub(Fl_Widget* o, void* v) { ((mainWindow_c*)v)->cb_SolProbSel((LBlockListGroup_c*)o); }
cb_SolProbSel(LBlockListGroup_c * grp)399 void mainWindow_c::cb_SolProbSel(LBlockListGroup_c* grp) {
400 int reason = grp->getReason();
401
402 switch(reason) {
403 case ProblemSelector::RS_CHANGEDSELECTION:
404
405 unsigned int prob = solutionProblem->getSelection();
406
407 if (prob < puzzle->problemNumber()) {
408
409 /* check the number of solutions on this tab and lower the slider value if necessary */
410 if (SolutionSel->value() > puzzle->getProblem(prob)->solutionNumber())
411 SolutionSel->value(puzzle->getProblem(prob)->solutionNumber());
412
413 updateInterface();
414 activateSolution(prob, (int)SolutionSel->value()-1);
415 }
416 break;
417 }
418 }
419
cb_ColSel_stub(Fl_Widget * o,void * v)420 static void cb_ColSel_stub(Fl_Widget* o, void* v) { ((mainWindow_c*)v)->cb_ColSel((LBlockListGroup_c*)o); }
cb_ColSel(LBlockListGroup_c * grp)421 void mainWindow_c::cb_ColSel(LBlockListGroup_c* grp) {
422 int reason = grp->getReason();
423
424 switch(reason) {
425 case PieceSelector::RS_CHANGEDSELECTION:
426 pieceEdit->setColor(colorSelector->getSelection());
427 updateInterface();
428 activateShape(PcSel->getSelection());
429 break;
430 }
431 }
432
cb_ProbSel_stub(Fl_Widget * o,void * v)433 static void cb_ProbSel_stub(Fl_Widget* o, void* v) { ((mainWindow_c*)v)->cb_ProbSel((LBlockListGroup_c*)o); }
cb_ProbSel(LBlockListGroup_c * grp)434 void mainWindow_c::cb_ProbSel(LBlockListGroup_c* grp) {
435 int reason = grp->getReason();
436
437 switch(reason) {
438 case PieceSelector::RS_CHANGEDSELECTION:
439 updateInterface();
440 activateProblem(problemSelector->getSelection());
441 StatProblemInfo(problemSelector->getSelection());
442 break;
443 }
444 }
445
cb_pieceEdit_stub(Fl_Widget * o,void * v)446 static void cb_pieceEdit_stub(Fl_Widget* o, void* v) { ((mainWindow_c*)v)->cb_pieceEdit((VoxelEditGroup_c*)o); }
cb_pieceEdit(VoxelEditGroup_c * o)447 void mainWindow_c::cb_pieceEdit(VoxelEditGroup_c* o) {
448
449 switch (o->getReason()) {
450 case gridEditor_c::RS_MOUSEMOVE:
451 if (o->getMouse())
452 View3D->getView()->setMarker(o->getMouseX1(), o->getMouseY1(), o->getMouseX2(), o->getMouseY2(), o->getMouseZ(), editSymmetries);
453 else
454 View3D->getView()->hideMarker();
455 break;
456 case gridEditor_c::RS_CHANGESQUARE:
457 View3D->getView()->showSingleShape(puzzle, PcSel->getSelection());
458 StatPieceInfo(PcSel->getSelection());
459 changeShape(PcSel->getSelection());
460 changed = true;
461 break;
462 }
463
464 View3D->redraw();
465 }
466
cb_NewProblem_stub(Fl_Widget *,void * v)467 static void cb_NewProblem_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_NewProblem(); }
cb_NewProblem(void)468 void mainWindow_c::cb_NewProblem(void) {
469
470 unsigned int prob = puzzle->addProblem();
471
472 for (unsigned int c = 0; c < puzzle->colorNumber(); c++)
473 puzzle->getProblem(prob)->allowPlacement(c+1, c+1);
474
475 problemSelector->setSelection(prob);
476
477 changed = true;
478 updateInterface();
479 activateProblem(problemSelector->getSelection());
480 StatProblemInfo(problemSelector->getSelection());
481 }
482
cb_DeleteProblem_stub(Fl_Widget *,void * v)483 static void cb_DeleteProblem_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_DeleteProblem(); }
cb_DeleteProblem(void)484 void mainWindow_c::cb_DeleteProblem(void) {
485
486 if (problemSelector->getSelection() < puzzle->problemNumber()) {
487
488 puzzle->removeProblem(problemSelector->getSelection());
489
490 changed = true;
491
492 while ((problemSelector->getSelection() >= puzzle->problemNumber()) &&
493 (problemSelector->getSelection() > 0))
494 problemSelector->setSelection(problemSelector->getSelection()-1);
495
496 updateInterface();
497 if (problemSelector->getSelection() < puzzle->problemNumber())
498 activateProblem(problemSelector->getSelection());
499 else
500 activateClear();
501 StatProblemInfo(problemSelector->getSelection());
502 }
503 }
504
cb_CopyProblem_stub(Fl_Widget *,void * v)505 static void cb_CopyProblem_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_CopyProblem(); }
cb_CopyProblem(void)506 void mainWindow_c::cb_CopyProblem(void) {
507
508 if (problemSelector->getSelection() < puzzle->problemNumber()) {
509
510 unsigned int prob = puzzle->addProblem(puzzle->getProblem(problemSelector->getSelection()));
511 problemSelector->setSelection(prob);
512
513 changed = true;
514 updateInterface();
515 activateProblem(problemSelector->getSelection());
516 StatProblemInfo(problemSelector->getSelection());
517 }
518 }
519
cb_RenameProblem_stub(Fl_Widget *,void * v)520 static void cb_RenameProblem_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_RenameProblem(); }
cb_RenameProblem(void)521 void mainWindow_c::cb_RenameProblem(void) {
522
523 if (problemSelector->getSelection() < puzzle->problemNumber()) {
524
525 const char * name = fl_input("Enter name for the problem",
526 puzzle->getProblem(problemSelector->getSelection())->getName().c_str());
527
528 if (name) {
529
530 puzzle->getProblem(problemSelector->getSelection())->setName(name);
531 changed = true;
532 updateInterface();
533 activateProblem(problemSelector->getSelection());
534 }
535 }
536 }
537
cb_ProblemLeft_stub(Fl_Widget *,void * v)538 static void cb_ProblemLeft_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_ProblemExchange(-1); }
cb_ProblemRight_stub(Fl_Widget *,void * v)539 static void cb_ProblemRight_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_ProblemExchange(+1); }
cb_ProblemExchange(int with)540 void mainWindow_c::cb_ProblemExchange(int with) {
541
542 unsigned int current = problemSelector->getSelection();
543 unsigned int other = current + with;
544
545 if ((current < puzzle->problemNumber()) && (other < puzzle->problemNumber())) {
546 puzzle->exchangeProblem(current, other);
547 changed = true;
548 problemSelector->setSelection(other);
549 }
550 }
551
cb_ShapeLeft_stub(Fl_Widget *,void * v)552 static void cb_ShapeLeft_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_ShapeExchange(-1); }
cb_ShapeRight_stub(Fl_Widget *,void * v)553 static void cb_ShapeRight_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_ShapeExchange(+1); }
cb_ShapeExchange(int with)554 void mainWindow_c::cb_ShapeExchange(int with) {
555
556 unsigned int current = PcSel->getSelection();
557 unsigned int other = current + with;
558
559 if ((current < puzzle->shapeNumber()) && (other < puzzle->shapeNumber())) {
560 puzzle->exchangeShape(current, other);
561 changed = true;
562 PcSel->setSelection(other);
563 }
564 }
565
cb_ProbShapeLeft_stub(Fl_Widget *,void * v)566 static void cb_ProbShapeLeft_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_ProbShapeExchange(-1); }
cb_ProbShapeRight_stub(Fl_Widget *,void * v)567 static void cb_ProbShapeRight_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_ProbShapeExchange(+1); }
cb_ProbShapeExchange(int with)568 void mainWindow_c::cb_ProbShapeExchange(int with) {
569
570 unsigned int p = problemSelector->getSelection();
571 unsigned int s = shapeAssignmentSelector->getSelection();
572
573 problem_c * pr = puzzle->getProblem(p);
574
575 // find out the index in the problem table
576 unsigned int current;
577
578 for (current = 0; current < pr->partNumber(); current++)
579 if (pr->getShape(current) == s)
580 break;
581
582 unsigned int other = current + with;
583
584 if ((current < pr->partNumber()) && (other < pr->partNumber())) {
585 pr->exchangeShape(current, other);
586 changed = true;
587 updateInterface();
588 activateProblem(problemSelector->getSelection());
589 }
590 }
591
cb_ColorAssSel_stub(Fl_Widget *,void * v)592 static void cb_ColorAssSel_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_ColorAssSel(); }
cb_ColorAssSel(void)593 void mainWindow_c::cb_ColorAssSel(void) {
594 updateInterface();
595 }
596
cb_ColorConstrSel_stub(Fl_Widget *,void * v)597 static void cb_ColorConstrSel_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_ColorConstrSel(); }
cb_ColorConstrSel(void)598 void mainWindow_c::cb_ColorConstrSel(void) {
599 updateInterface();
600 }
601
cb_ShapeToResult_stub(Fl_Widget *,void * v)602 static void cb_ShapeToResult_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_ShapeToResult(); }
cb_ShapeToResult(void)603 void mainWindow_c::cb_ShapeToResult(void) {
604
605 if (problemSelector->getSelection() >= puzzle->problemNumber()) {
606 fl_message("First create a problem");
607 return;
608 }
609
610 if (shapeAssignmentSelector->getSelection() >= puzzle->shapeNumber())
611 return;
612
613 unsigned int prob = problemSelector->getSelection();
614 problem_c * pr = puzzle->getProblem(prob);
615
616 // check if this shape is already a piece of the problem
617 pr->setShapeMaximum(shapeAssignmentSelector->getSelection(), 0);
618
619 pr->setResultId(shapeAssignmentSelector->getSelection());
620 problemResult->setPuzzle(puzzle->getProblem(prob));
621 activateProblem(prob);
622 StatProblemInfo(prob);
623 updateInterface();
624
625 changed = true;
626 }
627
cb_ShapeSel_stub(Fl_Widget *,void * v)628 static void cb_ShapeSel_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_SelectProblemShape(); }
cb_SelectProblemShape(void)629 void mainWindow_c::cb_SelectProblemShape(void) {
630 updateInterface();
631 activateProblem(problemSelector->getSelection());
632 }
633
cb_PiecesClicked_stub(Fl_Widget *,void * v)634 static void cb_PiecesClicked_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_PiecesClicked(); }
cb_PiecesClicked(void)635 void mainWindow_c::cb_PiecesClicked(void) {
636
637 problem_c * pr = puzzle->getProblem(problemSelector->getSelection());
638
639 shapeAssignmentSelector->setSelection(pr->getShape(PiecesCountList->getClicked()));
640
641 updateInterface();
642 activateProblem(problemSelector->getSelection());
643 }
644
cb_AddShapeToProblem_stub(Fl_Widget *,void * v)645 static void cb_AddShapeToProblem_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_AddShapeToProblem(); }
cb_AddShapeToProblem(void)646 void mainWindow_c::cb_AddShapeToProblem(void) {
647
648 if (problemSelector->getSelection() >= puzzle->problemNumber()) {
649 fl_message("First create a problem");
650 return;
651 }
652 unsigned int shape = shapeAssignmentSelector->getSelection();
653 if (shape >= puzzle->shapeNumber())
654 return;
655
656 unsigned int prob = problemSelector->getSelection();
657
658 changed = true;
659 PiecesCountList->redraw();
660
661 problem_c * pr = puzzle->getProblem(prob);
662
663 // first see, if there is already a selected shape inside
664 pr->setShapeMaximum(shape, pr->getShapeMaximum(shape) + 1);
665 pr->setShapeMinimum(shape, pr->getShapeMinimum(shape) + 1);
666
667 activateProblem(problemSelector->getSelection());
668 updateInterface();
669 StatProblemInfo(problemSelector->getSelection());
670 }
671
cb_AddAllShapesToProblem_stub(Fl_Widget *,void * v)672 static void cb_AddAllShapesToProblem_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_AddAllShapesToProblem(); }
cb_AddAllShapesToProblem(void)673 void mainWindow_c::cb_AddAllShapesToProblem(void) {
674
675 if (problemSelector->getSelection() >= puzzle->problemNumber()) {
676 fl_message("First create a problem");
677 return;
678 }
679
680 unsigned int prob = problemSelector->getSelection();
681
682 changed = true;
683 PiecesCountList->redraw();
684
685 problem_c * pr = puzzle->getProblem(prob);
686
687 for (unsigned int j = 0; j < puzzle->shapeNumber(); j++) {
688
689 // we don't add the result shape
690 if (pr->resultValid() && j == pr->getResultId())
691 continue;
692
693 pr->setShapeMaximum(j, pr->getShapeMaximum(j) + 1);
694 pr->setShapeMinimum(j, pr->getShapeMinimum(j) + 1);
695 }
696
697 activateProblem(problemSelector->getSelection());
698 PcVis->setPuzzle(puzzle->getProblem(solutionProblem->getSelection()));
699 updateInterface();
700 StatProblemInfo(problemSelector->getSelection());
701 }
702
cb_RemoveShapeFromProblem_stub(Fl_Widget *,void * v)703 static void cb_RemoveShapeFromProblem_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_RemoveShapeFromProblem(); }
cb_RemoveShapeFromProblem(void)704 void mainWindow_c::cb_RemoveShapeFromProblem(void) {
705
706 if (problemSelector->getSelection() >= puzzle->problemNumber()) {
707 fl_message("First create a problem");
708 return;
709 }
710
711 unsigned int shape = shapeAssignmentSelector->getSelection();
712
713 if (shape >= puzzle->shapeNumber())
714 return;
715
716 unsigned int prob = problemSelector->getSelection();
717
718 problem_c * pr = puzzle->getProblem(prob);
719
720 if (pr->getShapeMinimum(shape) > 0) pr->setShapeMinimum(shape, pr->getShapeMinimum(shape)-1);
721 if (pr->getShapeMaximum(shape) > 0) pr->setShapeMaximum(shape, pr->getShapeMaximum(shape)-1);
722
723 changed = true;
724 PiecesCountList->redraw();
725 PcVis->setPuzzle(puzzle->getProblem(solutionProblem->getSelection()));
726
727 activateProblem(problemSelector->getSelection());
728 StatProblemInfo(problemSelector->getSelection());
729 }
730
731
cb_SetShapeMinimumToZero_stub(Fl_Widget *,void * v)732 static void cb_SetShapeMinimumToZero_stub (Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_SetShapeMinimumToZero(); }
cb_SetShapeMinimumToZero(void)733 void mainWindow_c::cb_SetShapeMinimumToZero(void) {
734
735 if (problemSelector->getSelection() >= puzzle->problemNumber()) {
736 fl_message("First create a problem");
737 return;
738 }
739
740 unsigned int shape = shapeAssignmentSelector->getSelection();
741
742 if (shape >= puzzle->shapeNumber())
743 return;
744
745 unsigned int prob = problemSelector->getSelection();
746 changeProblem(prob);
747
748 problem_c * pr = puzzle->getProblem(prob);
749
750 pr->setShapeMinimum(shape, 0);
751
752 changed = true;
753 PiecesCountList->redraw();
754 PcVis->setPuzzle(puzzle->getProblem(solutionProblem->getSelection()));
755
756 activateProblem(problemSelector->getSelection());
757 StatProblemInfo(problemSelector->getSelection());
758 }
759
760
cb_RemoveAllShapesFromProblem_stub(Fl_Widget *,void * v)761 static void cb_RemoveAllShapesFromProblem_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_RemoveAllShapesFromProblem(); }
cb_RemoveAllShapesFromProblem(void)762 void mainWindow_c::cb_RemoveAllShapesFromProblem(void) {
763
764 if (problemSelector->getSelection() >= puzzle->problemNumber()) {
765 fl_message("First create a problem");
766 return;
767 }
768
769 unsigned int prob = problemSelector->getSelection();
770 changeProblem(prob);
771
772 problem_c * pr = puzzle->getProblem(prob);
773
774 for (unsigned int i = 0; i < puzzle->shapeNumber(); i++)
775 pr->setShapeMaximum(i, 0);
776
777 changed = true;
778 PiecesCountList->redraw();
779 PcVis->setPuzzle(puzzle->getProblem(solutionProblem->getSelection()));
780
781 activateProblem(problemSelector->getSelection());
782 StatProblemInfo(problemSelector->getSelection());
783 }
784
cb_ShapeGroup_stub(Fl_Widget *,void * v)785 static void cb_ShapeGroup_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_ShapeGroup(); }
cb_ShapeGroup(void)786 void mainWindow_c::cb_ShapeGroup(void) {
787
788 unsigned int prob = problemSelector->getSelection();
789
790 groupsEditor_c * groupEditWin = new groupsEditor_c(puzzle, prob);
791
792 groupEditWin->show();
793
794 while (groupEditWin->visible())
795 Fl::wait();
796
797 if (groupEditWin->changed()) {
798
799 problem_c * pr = puzzle->getProblem(prob);
800
801 /* if the user added the result shape to the problem, we inform him and
802 * remove that shape again
803 */
804 if (pr->resultValid() && pr->getShapeMaximum(pr->getResultId()) > 0)
805 pr->setShapeMaximum(pr->getResultId(), 0);
806
807 /* as the user may have reset the counts of one shape to zero, go
808 * through the list and remove entries of zero count */
809 PiecesCountList->redraw();
810 PcVis->setPuzzle(puzzle->getProblem(solutionProblem->getSelection()));
811 changed = true;
812 activateProblem(problemSelector->getSelection());
813 StatProblemInfo(problemSelector->getSelection());
814 updateInterface();
815 }
816
817 delete groupEditWin;
818 }
819
cb_BtnPlacementBrowser_stub(Fl_Widget *,void * v)820 static void cb_BtnPlacementBrowser_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_BtnPlacementBrowser(); }
cb_BtnPlacementBrowser(void)821 void mainWindow_c::cb_BtnPlacementBrowser(void) {
822
823 unsigned int prob = solutionProblem->getSelection();
824
825 if (prob >= puzzle->problemNumber())
826 return;
827
828 if (!puzzle->getProblem(prob)->getAssembler()->getPiecePlacementSupported()) {
829 fl_message("Sorry no placement browser for this type of puzzle");
830 return;
831 }
832
833 placementBrowser_c * plbr = new placementBrowser_c(puzzle->getProblem(prob));
834
835 plbr->show();
836
837 while (plbr->visible())
838 Fl::wait();
839
840 delete plbr;
841 }
842
cb_BtnMovementBrowser_stub(Fl_Widget *,void * v)843 static void cb_BtnMovementBrowser_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_BtnMovementBrowser(); }
cb_BtnMovementBrowser(void)844 void mainWindow_c::cb_BtnMovementBrowser(void) {
845
846 unsigned int prob = solutionProblem->getSelection();
847
848 if (prob >= puzzle->problemNumber())
849 return;
850
851 unsigned int sol = (int)SolutionSel->value()-1;
852
853 if (sol >= puzzle->getProblem(prob)->solutionNumber())
854 return;
855
856 movementBrowser_c * mvbr = new movementBrowser_c(puzzle->getProblem(prob), sol);
857
858 mvbr->show();
859
860 while (mvbr->visible())
861 Fl::wait();
862
863 delete mvbr;
864 }
865
cb_BtnAssemblerStep_stub(Fl_Widget *,void * v)866 static void cb_BtnAssemblerStep_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_BtnAssemblerStep(); }
cb_BtnAssemblerStep(void)867 void mainWindow_c::cb_BtnAssemblerStep(void) {
868
869 bt_assert(assmThread == 0);
870
871 assembler_c * assm = (assembler_c*)puzzle->getProblem(solutionProblem->getSelection())->getAssembler();
872
873 bt_assert(assm);
874
875 assm->debug_step(1);
876
877 if (assm->getFinished() >= 1)
878 puzzle->getProblem(solutionProblem->getSelection())->finishedSolving();
879
880 updateInterface();
881
882 View3D->getView()->showAssemblerState(puzzle->getProblem(solutionProblem->getSelection()), assm->getAssembly());
883 }
884
cb_AllowColor_stub(Fl_Widget *,void * v)885 static void cb_AllowColor_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_AllowColor(); }
cb_AllowColor(void)886 void mainWindow_c::cb_AllowColor(void) {
887
888 if (problemSelector->getSelection() >= puzzle->problemNumber()) {
889 fl_message("First create a problem");
890 return;
891 }
892
893 unsigned int prob = problemSelector->getSelection();
894 problem_c * pr = puzzle->getProblem(prob);
895
896 if (colconstrList->GetSortByResult())
897 pr->allowPlacement(colorAssignmentSelector->getSelection()+1,
898 colconstrList->getSelection()+1);
899 else
900 pr->allowPlacement(colconstrList->getSelection()+1,
901 colorAssignmentSelector->getSelection()+1);
902 changed = true;
903 changeProblem(problemSelector->getSelection());
904 updateInterface();
905 }
906
cb_DisallowColor_stub(Fl_Widget *,void * v)907 static void cb_DisallowColor_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_DisallowColor(); }
cb_DisallowColor(void)908 void mainWindow_c::cb_DisallowColor(void) {
909
910 if (problemSelector->getSelection() >= puzzle->problemNumber()) {
911 fl_message("First create a problem");
912 return;
913 }
914
915 unsigned int prob = problemSelector->getSelection();
916 problem_c * pr = puzzle->getProblem(prob);
917
918 if (colconstrList->GetSortByResult())
919 pr->disallowPlacement(colorAssignmentSelector->getSelection()+1,
920 colconstrList->getSelection()+1);
921 else
922 pr->disallowPlacement(colconstrList->getSelection()+1,
923 colorAssignmentSelector->getSelection()+1);
924
925 changed = true;
926 changeProblem(problemSelector->getSelection());
927 updateInterface();
928 }
929
cb_CCSortByResult_stub(Fl_Widget *,void * v)930 static void cb_CCSortByResult_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_CCSort(1); }
cb_CCSortByPiece_stub(Fl_Widget *,void * v)931 static void cb_CCSortByPiece_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_CCSort(0); }
cb_CCSort(bool byResult)932 void mainWindow_c::cb_CCSort(bool byResult) {
933 colconstrList->SetSortByResult(byResult);
934
935 if (byResult) {
936 BtnColSrtPc->activate();
937 BtnColSrtRes->deactivate();
938 } else {
939 BtnColSrtPc->deactivate();
940 BtnColSrtRes->activate();
941 }
942 }
943
cb_BtnPrepare_stub(Fl_Widget *,void * v)944 static void cb_BtnPrepare_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_BtnPrepare(); }
cb_BtnPrepare(void)945 void mainWindow_c::cb_BtnPrepare(void) {
946 cb_BtnStart(true);
947 }
948
cb_BtnStart_stub(Fl_Widget *,void * v)949 static void cb_BtnStart_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_BtnStart(false); }
cb_BtnStart(bool prep_only)950 void mainWindow_c::cb_BtnStart(bool prep_only) {
951
952 puzzle->getProblem(solutionProblem->getSelection())->removeAllSolutions();
953 SolutionEmpty = true;
954
955 for (unsigned int i = 0; i < puzzle->shapeNumber(); i++)
956 puzzle->getShape(i)->initHotspot();
957
958 cb_BtnCont(prep_only);
959
960 updateInterface();
961 changed = true;
962 }
963
cb_BtnCont_stub(Fl_Widget *,void * v)964 static void cb_BtnCont_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_BtnCont(false); }
cb_BtnCont(bool prep_only)965 void mainWindow_c::cb_BtnCont(bool prep_only) {
966
967 unsigned int prob = solutionProblem->getSelection();
968
969 if (!(ggt->getGridType()->getCapabilities() & gridType_c::CAP_ASSEMBLE)) {
970 fl_message("Sorry this space grid doesn't have an assembler (yet)!");
971 return;
972 }
973
974 if (SolveDisasm->value() && !(ggt->getGridType()->getCapabilities() & gridType_c::CAP_DISASSEMBLE)) {
975 fl_message("Sorry this space grid doesn't have a disassembler (yet)!\n"
976 "You must disable the disassembler first\n");
977 return;
978 }
979
980 if (prob >= puzzle->problemNumber()) {
981 fl_message("First create a problem");
982 return;
983 }
984
985 if (!puzzle->getProblem(prob)->resultValid()) {
986 fl_message("A result shape must be defined");
987 return;
988 }
989
990 bt_assert(assmThread == 0);
991
992 int par = solveThread_c::PAR_REDUCE;
993 if (KeepMirrors->value() != 0) par |= solveThread_c::PAR_KEEP_MIRROR;
994 if (KeepRotations->value() != 0) par |= solveThread_c::PAR_KEEP_ROTATIONS;
995 if (DropDisassemblies->value() != 0) par |= solveThread_c::PAR_DROP_DISASSEMBLIES;
996 if (SolveDisasm->value() != 0) par |= solveThread_c::PAR_DISASSM;
997 if (JustCount->value() != 0) par |= solveThread_c::PAR_JUST_COUNT;
998 if (CompleteRotations->value() != 0) par |= solveThread_c::PAR_COMPLETE_ROTATIONS;
999
1000 assmThread = new solveThread_c(puzzle->getProblem(prob), par);
1001
1002 assmThread->setSortMethod(sortMethod->value());
1003 assmThread->setSolutionLimits((int)solLimit->value(), (int)solDrop->value());
1004
1005 if (!assmThread->start(prep_only)) {
1006 fl_message("Could not start the solving process, the thread creation failed, sorry.");
1007 delete assmThread;
1008 assmThread = 0;
1009
1010 } else {
1011
1012 updateInterface();
1013 changed = true;
1014 }
1015 }
1016
cb_BtnStop_stub(Fl_Widget *,void * v)1017 static void cb_BtnStop_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_BtnStop(); }
cb_BtnStop(void)1018 void mainWindow_c::cb_BtnStop(void) {
1019
1020 bt_assert(assmThread);
1021
1022 assmThread->stop();
1023 }
1024
cb_SolutionSel_stub(Fl_Widget * o,void * v)1025 static void cb_SolutionSel_stub(Fl_Widget* o, void* v) { ((mainWindow_c*)v)->cb_SolutionSel((Fl_Value_Slider*)o); }
cb_SolutionSel(Fl_Value_Slider * o)1026 void mainWindow_c::cb_SolutionSel(Fl_Value_Slider* o) {
1027 o->take_focus();
1028 activateSolution(solutionProblem->getSelection(), int(o->value()-1));
1029 updateInterface();
1030 }
1031
cb_SolutionAnim_stub(Fl_Widget * o,void * v)1032 static void cb_SolutionAnim_stub(Fl_Widget* o, void* v) { ((mainWindow_c*)v)->cb_SolutionAnim((Fl_Value_Slider*)o); }
cb_SolutionAnim(Fl_Value_Slider * o)1033 void mainWindow_c::cb_SolutionAnim(Fl_Value_Slider* o) {
1034 o->take_focus();
1035 if (disassemble) {
1036 disassemble->setStep(o->value(), config.useBlendedRemoving(), true);
1037 View3D->getView()->updatePositions(disassemble);
1038 }
1039 }
1040
cb_SrtFind_stub(Fl_Widget *,void * v)1041 static void cb_SrtFind_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_SortSolutions(0); }
cb_SrtLevel_stub(Fl_Widget *,void * v)1042 static void cb_SrtLevel_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_SortSolutions(1); }
cb_SrtMoves_stub(Fl_Widget *,void * v)1043 static void cb_SrtMoves_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_SortSolutions(2); }
cb_SrtPieces_stub(Fl_Widget *,void * v)1044 static void cb_SrtPieces_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_SortSolutions(3); }
cb_SortSolutions(unsigned int by)1045 void mainWindow_c::cb_SortSolutions(unsigned int by) {
1046 unsigned int prob = solutionProblem->getSelection();
1047
1048 if (prob >= puzzle->problemNumber())
1049 return;
1050
1051 problem_c * pr = puzzle->getProblem(prob);
1052
1053 unsigned int sol = pr->solutionNumber();
1054
1055 if (sol < 2)
1056 return;
1057
1058 pr->sortSolutions(by);
1059 activateSolution(prob, (int)SolutionSel->value()-1);
1060 updateInterface();
1061 }
1062
cb_DelAll_stub(Fl_Widget *,void * v)1063 static void cb_DelAll_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_DeleteSolutions(0); }
cb_DelBefore_stub(Fl_Widget *,void * v)1064 static void cb_DelBefore_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_DeleteSolutions(1); }
cb_DelAt_stub(Fl_Widget *,void * v)1065 static void cb_DelAt_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_DeleteSolutions(2); }
cb_DelAfter_stub(Fl_Widget *,void * v)1066 static void cb_DelAfter_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_DeleteSolutions(3); }
cb_DelDisasmless_stub(Fl_Widget *,void * v)1067 static void cb_DelDisasmless_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_DeleteSolutions(4); }
cb_DeleteSolutions(unsigned int which)1068 void mainWindow_c::cb_DeleteSolutions(unsigned int which) {
1069
1070 unsigned int prob = solutionProblem->getSelection();
1071
1072 if (prob >= puzzle->problemNumber())
1073 return;
1074
1075 unsigned int sol = (int)SolutionSel->value()-1;
1076
1077 problem_c * pr = puzzle->getProblem(prob);
1078
1079 if (sol >= pr->solutionNumber())
1080 return;
1081
1082 unsigned int cnt;
1083
1084 changed = true;
1085
1086 switch (which) {
1087 case 0:
1088 cnt = pr->solutionNumber();
1089 for (unsigned int i = 0; i < cnt; i++)
1090 pr->removeSolution(0);
1091 break;
1092 case 1:
1093 for (unsigned int i = 0; i < sol; i++)
1094 pr->removeSolution(0);
1095 SolutionSel->value(1);
1096 break;
1097 case 2:
1098 pr->removeSolution(sol);
1099 break;
1100 case 3:
1101 cnt = pr->solutionNumber() - sol - 1;
1102 for (unsigned int i = 0; i < cnt; i++)
1103 pr->removeSolution(sol+1);
1104 break;
1105 case 4:
1106 cnt = pr->solutionNumber();
1107 {
1108 unsigned int i = 0;
1109 while (i < cnt) {
1110 if (pr->getSolution(i)->getDisassembly() || pr->getSolution(i)->getDisassemblyInfo())
1111 i++;
1112 else {
1113 pr->removeSolution(i);
1114 cnt--;
1115 if (SolutionSel->value() > i)
1116 SolutionSel->value(SolutionSel->value()-1);
1117 }
1118 }
1119 }
1120 break;
1121 }
1122
1123 if (SolutionSel->value() > pr->solutionNumber())
1124 SolutionSel->value(pr->solutionNumber());
1125
1126 activateSolution(prob, (int)SolutionSel->value()-1);
1127 updateInterface();
1128 }
1129
cb_DelDisasm_stub(Fl_Widget *,void * v)1130 static void cb_DelDisasm_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_DeleteDisasm(); }
cb_DeleteDisasm(void)1131 void mainWindow_c::cb_DeleteDisasm(void) {
1132 unsigned int prob = solutionProblem->getSelection();
1133
1134 if (prob >= puzzle->problemNumber())
1135 return;
1136
1137 problem_c * pr = puzzle->getProblem(prob);
1138
1139 unsigned int sol = (int)SolutionSel->value()-1;
1140
1141 if (sol >= pr->solutionNumber())
1142 return;
1143
1144 pr->getSolution(sol)->removeDisassembly();
1145
1146 changed = true;
1147
1148 activateSolution(prob, (int)SolutionSel->value()-1);
1149 updateInterface();
1150 }
1151
cb_DelAllDisasm_stub(Fl_Widget *,void * v)1152 static void cb_DelAllDisasm_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_DeleteAllDisasm(); }
cb_DeleteAllDisasm(void)1153 void mainWindow_c::cb_DeleteAllDisasm(void) {
1154 unsigned int prob = solutionProblem->getSelection();
1155
1156 if (prob >= puzzle->problemNumber())
1157 return;
1158
1159 problem_c * pr = puzzle->getProblem(prob);
1160
1161 for (unsigned int i = 0; i < pr->solutionNumber(); i++)
1162 pr->getSolution(i)->removeDisassembly();
1163
1164 changed = true;
1165
1166 activateSolution(prob, (int)SolutionSel->value()-1);
1167 updateInterface();
1168 }
1169
cb_AddDisasm_stub(Fl_Widget *,void * v)1170 static void cb_AddDisasm_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_AddDisasm(); }
cb_AddDisasm(void)1171 void mainWindow_c::cb_AddDisasm(void) {
1172 unsigned int prob = solutionProblem->getSelection();
1173
1174 if (prob >= puzzle->problemNumber())
1175 return;
1176
1177 problem_c * pr = puzzle->getProblem(prob);
1178
1179 unsigned int sol = (int)SolutionSel->value()-1;
1180
1181 if (sol >= pr->solutionNumber())
1182 return;
1183
1184 if (!(ggt->getGridType()->getCapabilities() & gridType_c::CAP_DISASSEMBLE)) {
1185 fl_message("Sorry this space grid doesn't have a disassembler (yet)!");
1186 return;
1187 }
1188
1189 disassembler_c * dis = new disassembler_0_c(pr);
1190
1191 separation_c * d = dis->disassemble(pr->getSolution(sol)->getAssembly());
1192
1193 changed = true;
1194
1195 if (d)
1196 pr->getSolution(sol)->setDisassembly(d);
1197
1198 activateSolution(prob, (int)SolutionSel->value()-1);
1199 updateInterface();
1200
1201 delete dis;
1202 }
1203
cb_AddAllDisasm_stub(Fl_Widget *,void * v)1204 static void cb_AddAllDisasm_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_AddAllDisasm(true); }
cb_AddMissingDisasm_stub(Fl_Widget *,void * v)1205 static void cb_AddMissingDisasm_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_AddAllDisasm(false); }
cb_AddAllDisasm(bool all)1206 void mainWindow_c::cb_AddAllDisasm(bool all) {
1207 unsigned int prob = solutionProblem->getSelection();
1208
1209 if (prob >= puzzle->problemNumber())
1210 return;
1211
1212 if (!(ggt->getGridType()->getCapabilities() & gridType_c::CAP_DISASSEMBLE)) {
1213 fl_message("Sorry this space grid doesn't have a disassembler (yet)!");
1214 return;
1215 }
1216
1217 problem_c * pr = puzzle->getProblem(prob);
1218
1219 changed = true;
1220
1221 disassembler_c * dis = new disassembler_0_c(pr);
1222
1223 Fl_Double_Window * w = new Fl_Double_Window(20, 20, 300, 30);
1224 Fl_Box * b = new Fl_Box(0, 0, 300, 30);
1225 w->end();
1226 w->label("Disassembling...");
1227 w->set_modal();
1228 char txt[100];
1229 w->show();
1230
1231 for (unsigned int sol = 0; sol < pr->solutionNumber(); sol++) {
1232
1233 snprintf(txt, 100, "solved %i of %i disassemblies\n", sol, pr->solutionNumber());
1234 b->label(txt);
1235
1236 Fl::wait(0);
1237
1238 if (all || !pr->getSolution(sol)->getDisassembly()) {
1239
1240 separation_c * d = dis->disassemble(pr->getSolution(sol)->getAssembly());
1241
1242 if (d)
1243 pr->getSolution(sol)->setDisassembly(d);
1244 }
1245 }
1246
1247 delete dis;
1248 delete w;
1249
1250 activateSolution(prob, (int)SolutionSel->value()-1);
1251 updateInterface();
1252 }
1253
1254
cb_PcVis_stub(Fl_Widget *,void * v)1255 static void cb_PcVis_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_PcVis(); }
cb_PcVis(void)1256 void mainWindow_c::cb_PcVis(void) {
1257 View3D->getView()->updateVisibility(PcVis);
1258 }
1259
cb_Status_stub(Fl_Widget *,void * v)1260 static void cb_Status_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_Status(); }
cb_Status(void)1261 void mainWindow_c::cb_Status(void) {
1262 View3D->getView()->showColors(puzzle, StatusLine->getColorMode());
1263 }
1264
cb_3dClick_stub(Fl_Widget *,void * v)1265 static void cb_3dClick_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_3dClick(); }
cb_3dClick(void)1266 void mainWindow_c::cb_3dClick(void) {
1267
1268
1269 if (TaskSelectionTab->value() == TabPieces) {
1270
1271 if (Fl::event_ctrl()) {
1272 unsigned int shape, face;
1273 unsigned long voxel;
1274
1275 voxel_c * sh = puzzle->getShape(PcSel->getSelection());
1276
1277 if (View3D->getView()->pickShape(Fl::event_x(),
1278 View3D->getView()->h()-Fl::event_y(),
1279 &shape, &voxel, &face))
1280 sh->setState(voxel, voxel_c::VX_EMPTY);
1281
1282 View3D->getView()->showSingleShape(puzzle, PcSel->getSelection());
1283 StatPieceInfo(PcSel->getSelection());
1284 changeShape(PcSel->getSelection());
1285 redraw();
1286 changed = true;
1287
1288 } else if (Fl::event_shift() || Fl::event_alt()) {
1289
1290 unsigned int shape, face;
1291 unsigned long voxel;
1292
1293 voxel_c * sh = puzzle->getShape(PcSel->getSelection());
1294
1295 if (View3D->getView()->pickShape(Fl::event_x(),
1296 View3D->getView()->h()-Fl::event_y(),
1297 &shape, &voxel, &face)) {
1298
1299 unsigned int x, y, z;
1300 if (sh->indexToXYZ(voxel, &x, &y, &z)) {
1301
1302 int nx, ny, nz;
1303
1304 if (sh->getNeighbor(face, 0, x, y, z, &nx, &ny, &nz)) {
1305
1306 sh->resizeInclude(nx, ny, nz);
1307
1308 if (Fl::event_alt())
1309 sh->setState(nx, ny, nz, voxel_c::VX_VARIABLE);
1310 else
1311 sh->setState(nx, ny, nz, voxel_c::VX_FILLED);
1312
1313 sh->setColor(nx, ny, nz, colorSelector->getSelection());
1314
1315 View3D->getView()->showSingleShape(puzzle, PcSel->getSelection());
1316 StatPieceInfo(PcSel->getSelection());
1317 changeShape(PcSel->getSelection());
1318 activateShape(PcSel->getSelection());
1319 redraw();
1320 changed = true;
1321 }
1322 }
1323 }
1324 }
1325 } else if (TaskSelectionTab->value() == TabProblems) {
1326
1327 unsigned int shape;
1328
1329 if (View3D->getView()->pickShape(Fl::event_x(),
1330 View3D->getView()->h()-Fl::event_y(),
1331 &shape, 0, 0)) {
1332
1333 if (shape >= 2)
1334 shapeAssignmentSelector->setSelection(puzzle->getProblem(problemSelector->getSelection())->getShape(shape-2));
1335 }
1336 } else if (TaskSelectionTab->value() == TabSolve) {
1337 if (Fl::event_shift()) {
1338 unsigned int shape;
1339
1340 if (View3D->getView()->pickShape(Fl::event_x(),
1341 View3D->getView()->h()-Fl::event_y(),
1342 &shape, 0, 0)) {
1343
1344 PcVis->hidePiece(shape);
1345 View3D->getView()->updateVisibility(PcVis);
1346 redraw();
1347 }
1348 }
1349 }
1350 }
1351
cb_New_stub(Fl_Widget *,void * v)1352 static void cb_New_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_New(); }
cb_New(void)1353 void mainWindow_c::cb_New(void) {
1354
1355 if (threadStopped()) {
1356
1357 if (changed)
1358 if (fl_choice("Puzzle changed are you sure?", "Cancel", "New Puzzle", 0) == 0)
1359 return;
1360
1361 gridTypeSelectorWindow_c w;
1362 w.show();
1363
1364 while (w.visible())
1365 Fl::wait();
1366
1367 ReplacePuzzle(new puzzle_c(w.getGridType()));
1368
1369 if (fname) {
1370 delete [] fname;
1371 fname = 0;
1372 label("BurrTools - unknown");
1373 }
1374
1375 changed = false;
1376
1377 StatusLine->setText("");
1378 updateInterface();
1379 activateShape(0);
1380 }
1381 }
1382
cb_Load_stub(Fl_Widget *,void * v)1383 static void cb_Load_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_Load(); }
cb_Load(void)1384 void mainWindow_c::cb_Load(void) {
1385
1386 if (threadStopped()) {
1387
1388 if (changed)
1389 if (fl_choice("Puzzle changed are you sure?", "Cancel", "Load", 0) == 0)
1390 return;
1391
1392 const char * f = flu_file_chooser("Load Puzzle", "*.xmpuzzle", "");
1393
1394 tryToLoad(f);
1395 }
1396 }
1397
cb_Load_Ps3d_stub(Fl_Widget *,void * v)1398 static void cb_Load_Ps3d_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_Load_Ps3d(); }
cb_Load_Ps3d(void)1399 void mainWindow_c::cb_Load_Ps3d(void) {
1400
1401 if (threadStopped()) {
1402
1403 if (changed)
1404 if (fl_choice("Puzzle changed are you sure?", "Cancel", "Load", 0) == 0)
1405 return;
1406
1407 const char * f = flu_file_chooser("Import PuzzleSolver3D File", "*.puz", "");
1408
1409 if (f) {
1410
1411 std::ifstream in(f);
1412
1413 puzzle_c * newPuzzle = loadPuzzlerSolver3D(&in);
1414 if (!newPuzzle) {
1415 fl_alert("Could not load puzzle, sorry!");
1416 return;
1417 }
1418
1419 if (fname) delete [] fname;
1420 fname = new char[strlen(f)+1];
1421 strcpy(fname, f);
1422
1423 char nm[300];
1424 snprintf(nm, 299, "BurrTools - %s", fname);
1425 label(nm);
1426
1427 ReplacePuzzle(newPuzzle);
1428 updateInterface();
1429
1430 TaskSelectionTab->value(TabPieces);
1431 activateShape(PcSel->getSelection());
1432 StatPieceInfo(PcSel->getSelection());
1433
1434 changed = false;
1435 }
1436 }
1437 }
1438
cb_Save_stub(Fl_Widget *,void * v)1439 static void cb_Save_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_Save(); }
cb_Save(void)1440 void mainWindow_c::cb_Save(void) {
1441
1442 if (threadStopped()) {
1443
1444 if (!fname)
1445 cb_SaveAs();
1446
1447 else {
1448 ogzstream ostr(fname);
1449
1450 if (ostr) {
1451 xmlWriter_c xml(ostr);
1452 puzzle->save(xml);
1453 }
1454
1455 if (!ostr)
1456 fl_alert("puzzle NOT saved!!");
1457 else
1458 changed = false;
1459 }
1460 }
1461 }
1462
cb_Convert_stub(Fl_Widget *,void * v)1463 static void cb_Convert_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_Convert(); }
cb_Convert(void)1464 void mainWindow_c::cb_Convert(void) {
1465
1466 convertWindow_c win(puzzle->getGridType()->getType());
1467
1468 win.show();
1469
1470 while (win.visible())
1471 Fl::wait();
1472
1473 if (win.okSelected())
1474 {
1475 puzzle_c * p = doConvert(puzzle, win.getTargetType());
1476
1477 if (p)
1478 {
1479 ReplacePuzzle(p);
1480 updateInterface();
1481 activateShape(0);
1482 changed = true;
1483 }
1484 }
1485 }
1486
1487 class voxelTableVector_c : public voxelTable_c
1488 {
1489 private:
1490
1491 const std::vector<voxel_c *> *shapes;
1492
1493 public:
1494
voxelTableVector_c(const std::vector<voxel_c * > * s)1495 voxelTableVector_c(const std::vector<voxel_c *> *s) : shapes(s) {}
1496
1497 protected:
1498
findSpace(unsigned int index) const1499 const voxel_c * findSpace(unsigned int index) const { return (*shapes)[index]; }
1500 };
1501
cb_AssembliesToShapes_stub(Fl_Widget *,void * v)1502 static void cb_AssembliesToShapes_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_AssembliesToShapes(); }
cb_AssembliesToShapes(void)1503 void mainWindow_c::cb_AssembliesToShapes(void) {
1504
1505 assmImportWindow_c win(puzzle);
1506
1507 win.show();
1508
1509 while (win.visible())
1510 Fl::wait();
1511
1512 if (win.okSelected())
1513 {
1514 problem_c * pr = puzzle->getProblem(win.getSrcProblem());
1515
1516 std::vector<voxel_c *> sh;
1517
1518 unsigned int filter = win.getFilter();
1519
1520 voxelTableVector_c voxelTab(&sh);
1521
1522 for (unsigned int s = 0; s < pr->solutionNumber(); s++)
1523 {
1524 voxel_c * shape = pr->getSolution(s)->getAssembly()->createSpace(pr);
1525
1526 if ((filter & assmImportWindow_c::dropDisconnected) && !shape->connected(0, true, voxel_c::VX_EMPTY))
1527 {
1528 delete shape;
1529 continue;
1530 }
1531
1532 symmetries_t sym = shape->selfSymmetries();
1533
1534 if ((filter & assmImportWindow_c::dropMirror) && shape->getGridType()->getSymmetries()->symmetryContainsMirror(sym))
1535 {
1536 delete shape;
1537 continue;
1538 }
1539
1540 if ((filter & assmImportWindow_c::dropSymmetric) && !unSymmetric(sym))
1541 {
1542 delete shape;
1543 continue;
1544 }
1545
1546 if ((filter & assmImportWindow_c::dropNonMillable) && !isMillable(shape))
1547 {
1548 delete shape;
1549 continue;
1550 }
1551
1552 if ((filter & assmImportWindow_c::dropNonNotchable) && !isNotchable(shape))
1553 {
1554 delete shape;
1555 continue;
1556 }
1557
1558 unsigned int voxels = shape->countState(voxel_c::VX_FILLED);
1559 if (voxels < win.getShapeMin() || voxels > win.getShapeMax())
1560 {
1561 delete shape;
1562 continue;
1563 }
1564
1565 // if the user wants no identical shapes, we look up the current
1566 // shape in the known shapes table and drop it if we find it
1567 if (filter & assmImportWindow_c::dropIdentical)
1568 {
1569 if (voxelTab.getSpace(shape))
1570 {
1571 delete shape;
1572 continue;
1573 }
1574 }
1575
1576 sh.push_back(shape);
1577
1578 // we only need to add the current shape to the shape table
1579 // if the user wants to drop identical shapes and we use the table
1580 if (filter & assmImportWindow_c::dropIdentical)
1581 {
1582 voxelTab.addSpace(sh.size()-1);
1583 }
1584 }
1585
1586 if (win.getAction() == assmImportWindow_c::A_ADD_NEW)
1587 pr = puzzle->getProblem(puzzle->addProblem());
1588 else if (win.getAction() == assmImportWindow_c::A_ADD_DST)
1589 pr = puzzle->getProblem(win.getDstProblem());
1590
1591 // add the shapes to the problem of the problem tab
1592 for (unsigned int s = 0; s < sh.size(); s++)
1593 {
1594 int i = puzzle->addShape(sh[s]);
1595
1596 if (win.getAction() == assmImportWindow_c::A_ADD_DST || win.getAction() == assmImportWindow_c::A_ADD_NEW)
1597 {
1598 pr->setShapeMaximum(i, win.getMax());
1599 pr->setShapeMinimum(i, win.getMin());
1600 }
1601 }
1602
1603 changed = true;
1604 PiecesCountList->redraw();
1605
1606 updateInterface();
1607 }
1608 }
1609
cb_SaveAs_stub(Fl_Widget *,void * v)1610 static void cb_SaveAs_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_SaveAs(); }
cb_SaveAs(void)1611 void mainWindow_c::cb_SaveAs(void) {
1612
1613 if (threadStopped()) {
1614 const char * f = flu_file_chooser("Save Puzzle As", "*.xmpuzzle", "");
1615
1616 if (f) {
1617
1618 if (!fileExists(f) || fl_choice("File exists overwrite?", "Cancel", "Overwrite", 0)) {
1619
1620 char f2[1000];
1621
1622 // check, if the last characters are ".xmpuzzle"
1623 if (strcmp(f + strlen(f) - strlen(".xmpuzzle"), ".xmpuzzle")) {
1624 snprintf(f2, 1000, "%s.xmpuzzle", f);
1625
1626 } else
1627
1628 snprintf(f2, 1000, "%s", f);
1629
1630 ogzstream ostr(f2);
1631
1632 if (ostr)
1633 {
1634 xmlWriter_c xml(ostr);
1635 puzzle->save(xml);
1636 }
1637
1638 if (!ostr)
1639 fl_alert("puzzle NOT saved!!!");
1640 else
1641 changed = false;
1642
1643 if (fname) delete [] fname;
1644 fname = new char[strlen(f2)+1];
1645 strcpy(fname, f2);
1646
1647 char nm[300];
1648 snprintf(nm, 299, "BurrTools - %s", fname);
1649 label(nm);
1650
1651 } else {
1652
1653 fl_message("File not saved!\n");
1654 }
1655 }
1656 }
1657 }
1658
cb_Quit_stub(Fl_Widget *,void * v)1659 static void cb_Quit_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->hide(); }
hide(void)1660 void mainWindow_c::hide(void) {
1661 if ((!changed) || fl_choice("Puzzle changed do you want to quit and loose the changes?", "Cancel", "Quit", 0))
1662 Fl_Double_Window::hide();
1663 }
1664
cb_Config_stub(Fl_Widget *,void * v)1665 static void cb_Config_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_Config(); }
cb_Config(void)1666 void mainWindow_c::cb_Config(void) {
1667 config.dialog();
1668 activateConfigOptions();
1669 }
1670
cb_Comment_stub(Fl_Widget *,void * v)1671 static void cb_Comment_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_Coment(); }
cb_Coment(void)1672 void mainWindow_c::cb_Coment(void) {
1673
1674 multiLineWindow_c win("Edit Comment", "Change the comment for the current puzzle", puzzle->getComment().c_str());
1675
1676 win.show();
1677
1678 while (win.visible())
1679 Fl::wait();
1680
1681 if (win.saveChanges()) {
1682 puzzle->setComment(win.getText());
1683 changed = true;
1684 }
1685 }
1686
cb_ImageExportVector_stub(Fl_Widget *,void * v)1687 static void cb_ImageExportVector_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_ImageExportVector(); }
cb_ImageExportVector(void)1688 void mainWindow_c::cb_ImageExportVector(void) {
1689
1690 vectorExportWindow_c w;
1691
1692 w.show();
1693 while (w.visible())
1694 Fl::wait();
1695
1696 if (!w.cancelled)
1697 View3D->getView()->exportToVector(w.getFileName(), w.getVectorType());
1698 }
1699
cb_ImageExport_stub(Fl_Widget *,void * v)1700 static void cb_ImageExport_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_ImageExport(); }
cb_ImageExport(void)1701 void mainWindow_c::cb_ImageExport(void) {
1702 imageExport_c w(puzzle);
1703 w.show();
1704
1705 while (w.visible()) {
1706 w.update();
1707 if (w.isWorking())
1708 Fl::wait(0);
1709 else
1710 Fl::wait(1);
1711 }
1712 }
1713
cb_STLExport_stub(Fl_Widget *,void * v)1714 static void cb_STLExport_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_STLExport(); }
cb_STLExport(void)1715 void mainWindow_c::cb_STLExport(void) {
1716 stlExport_c w(puzzle);
1717 w.show();
1718
1719 while (w.visible()) {
1720 Fl::wait();
1721 }
1722 }
1723
cb_StatusWindow_stub(Fl_Widget *,void * v)1724 static void cb_StatusWindow_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_StatusWindow(); }
cb_StatusWindow(void)1725 void mainWindow_c::cb_StatusWindow(void) {
1726
1727 bool again;
1728
1729 do {
1730
1731 statusWindow_c w(puzzle);
1732 w.show();
1733
1734 while (w.visible()) {
1735 Fl::wait();
1736 }
1737
1738 again = w.getAgain();
1739
1740 if (again)
1741 changed = true;
1742
1743 } while (again);
1744
1745 unsigned int current = PcSel->getSelection();
1746
1747 if (puzzle->shapeNumber() == 0)
1748 current = (unsigned int)-1;
1749 else
1750 while (current >= puzzle->shapeNumber())
1751 current--;
1752
1753 activateShape(current);
1754
1755 PcSel->setSelection(current);
1756
1757 updateInterface();
1758 }
1759
cb_Toggle3D_stub(Fl_Widget *,void * v)1760 static void cb_Toggle3D_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_Toggle3D(); }
cb_Toggle3D(void)1761 void mainWindow_c::cb_Toggle3D(void) {
1762
1763 if (TaskSelectionTab->value() == TabPieces) {
1764 shapeEditorWithBig3DView = !shapeEditorWithBig3DView;
1765 if (!shapeEditorWithBig3DView)
1766 Small3DView();
1767 else
1768 Big3DView();
1769 }
1770 }
1771
cb_Help_stub(Fl_Widget *,void * v)1772 static void cb_Help_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_Help(); }
cb_Help(void)1773 void mainWindow_c::cb_Help(void) {
1774
1775 Fl_Help_Dialog * help = new Fl_Help_Dialog;
1776
1777 help->load("Prologue.html");
1778
1779 help->show();
1780 }
1781
cb_About_stub(Fl_Widget *,void * v)1782 static void cb_About_stub(Fl_Widget* /*o*/, void* v) { ((mainWindow_c*)v)->cb_About(); }
cb_About(void)1783 void mainWindow_c::cb_About(void) {
1784
1785 fl_message("This is the GUI for BurrTools version " VERSION "\n"
1786 "BurrTools (c) 2003-2011 by Andreas Röver\n"
1787 "The latest version is available at burrtools.sourceforge.net\n"
1788 "\n"
1789 "This software is distributed under the GPL\n"
1790 "You should have received a copy of the GNU General Public License\n"
1791 "along with this program (COPYING); if not, write to the Free Software\n"
1792 "Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA\n"
1793 "or see www.fsf.org\n"
1794 "\n"
1795 "The program uses\n"
1796 "- Fltk, FLU, libZ, libpng, gzstream, gl2ps\n"
1797 "- Fl_Table (http://3dsite.com/people/erco/Fl_Table/)\n"
1798 "- tr by Brian Paul (http://www.mesa3d.org/brianp/TR.html)\n"
1799 );
1800 }
1801
StatPieceInfo(unsigned int pc)1802 void mainWindow_c::StatPieceInfo(unsigned int pc) {
1803
1804 if (pc < puzzle->shapeNumber()) {
1805 char txt[100];
1806
1807 unsigned int fx = puzzle->getShape(pc)->countState(voxel_c::VX_FILLED);
1808 unsigned int vr = puzzle->getShape(pc)->countState(voxel_c::VX_VARIABLE);
1809
1810 snprintf(txt, 100, "Shape S%i has %i voxels (%i fixed, %i variable)", pc+1, fx+vr, fx, vr);
1811 StatusLine->setText(txt);
1812 }
1813 }
1814
StatProblemInfo(unsigned int prob)1815 void mainWindow_c::StatProblemInfo(unsigned int prob) {
1816
1817 if ((prob < puzzle->problemNumber()) && (puzzle->getProblem(prob)->resultValid())) {
1818
1819 problem_c * pr = puzzle->getProblem(prob);
1820
1821 char txt[100];
1822
1823 unsigned int cnt = 0;
1824 unsigned int cntMin = 0;
1825
1826 for (unsigned int i = 0; i < pr->partNumber(); i++) {
1827 cnt += pr->getShapeShape(i)->countState(voxel_c::VX_FILLED) * pr->getShapeMax(i);
1828 cntMin += pr->getShapeShape(i)->countState(voxel_c::VX_FILLED) * pr->getShapeMin(i);
1829 }
1830
1831 if (cnt == cntMin) {
1832
1833 snprintf(txt, 100, "Problem P%i result can contain %i - %i voxels, pieces (n = %i) contain %i voxels", prob+1,
1834 pr->getResultShape()->countState(voxel_c::VX_FILLED),
1835 pr->getResultShape()->countState(voxel_c::VX_FILLED) +
1836 pr->getResultShape()->countState(voxel_c::VX_VARIABLE),
1837 pr->pieceNumber(), cnt);
1838
1839 } else {
1840
1841 snprintf(txt, 100, "Problem P%i result can contain %i - %i voxels, pieces (n = %i) contain %i-%i voxels", prob+1,
1842 pr->getResultShape()->countState(voxel_c::VX_FILLED),
1843 pr->getResultShape()->countState(voxel_c::VX_FILLED) +
1844 pr->getResultShape()->countState(voxel_c::VX_VARIABLE),
1845 pr->pieceNumber(), cntMin, cnt);
1846 }
1847
1848 StatusLine->setText(txt);
1849
1850 } else
1851
1852 StatusLine->setText("");
1853 }
1854
changeColor(unsigned int nr)1855 void mainWindow_c::changeColor(unsigned int nr) {
1856
1857 for (unsigned int i = 0; i < puzzle->shapeNumber(); i++)
1858 for (unsigned int j = 0; j < puzzle->getShape(i)->getXYZ(); j++)
1859 if (puzzle->getShape(i)->getColor(j) == nr) {
1860 changeShape(i);
1861 break;
1862 }
1863 }
1864
changeShape(unsigned int nr)1865 void mainWindow_c::changeShape(unsigned int nr) {
1866 for (unsigned int i = 0; i < puzzle->problemNumber(); i++)
1867 if (puzzle->getProblem(i)->usesShape(nr))
1868 puzzle->getProblem(i)->removeAllSolutions();
1869 }
1870
changeProblem(unsigned int nr)1871 void mainWindow_c::changeProblem(unsigned int nr) {
1872 puzzle->getProblem(nr)->removeAllSolutions();
1873 }
1874
threadStopped(void)1875 bool mainWindow_c::threadStopped(void) {
1876
1877 if (assmThread) {
1878
1879 fl_message("Stop solving process first!");
1880 return false;
1881 }
1882
1883 return true;
1884 }
1885
tryToLoad(const char * f)1886 bool mainWindow_c::tryToLoad(const char * f) {
1887
1888 // it may well be that the file doesn't exist, if it came from the command line
1889 if (!f) return false;
1890 if (!fileExists(f)) return false;
1891
1892 std::istream * str = openGzFile(f);
1893 xmlParser_c pars(*str);
1894
1895 puzzle_c * newPuzzle;
1896
1897 try {
1898 newPuzzle = new puzzle_c(pars);
1899 }
1900
1901 catch (xmlParserException_c e)
1902 {
1903 fl_message((std::string("load error: ") + e.what()).c_str());
1904 delete str;
1905 return false;
1906 }
1907
1908 delete str;
1909
1910 if (fname) delete [] fname;
1911 fname = new char[strlen(f)+1];
1912 strcpy(fname, f);
1913
1914 char nm[300];
1915 snprintf(nm, 299, "BurrTools - %s", fname);
1916 label(nm);
1917
1918 ReplacePuzzle(newPuzzle);
1919 updateInterface();
1920
1921 TaskSelectionTab->value(TabPieces);
1922 activateShape(PcSel->getSelection());
1923 StatPieceInfo(PcSel->getSelection());
1924 View3D->getView()->showColors(puzzle, StatusLine->getColorMode());
1925
1926 changed = false;
1927
1928 // check for a started assemblies, and warn user about it
1929 bool containsStarted = false;
1930
1931 for (unsigned int p = 0; p < puzzle->problemNumber(); p++) {
1932 if (puzzle->getProblem(p)->getSolveState() == SS_SOLVING) {
1933 containsStarted = true;
1934 break;
1935 }
1936 }
1937
1938 if (containsStarted)
1939 fl_message("This puzzle file contains started but not finished search for solutions.");
1940
1941 if (puzzle->getCommentPopup())
1942 fl_message(puzzle->getComment().c_str());
1943
1944 return true;
1945 }
1946
ReplacePuzzle(puzzle_c * NewPuzzle)1947 void mainWindow_c::ReplacePuzzle(puzzle_c * NewPuzzle) {
1948
1949 // inform everybody
1950 colorSelector->setPuzzle(NewPuzzle);
1951 PcSel->setPuzzle(NewPuzzle);
1952 pieceEdit->setPuzzle(NewPuzzle, 0);
1953 problemSelector->setPuzzle(NewPuzzle);
1954 colorAssignmentSelector->setPuzzle(NewPuzzle);
1955 colconstrList->setPuzzle(NewPuzzle, 0);
1956 if (NewPuzzle->problemNumber() > 0) {
1957 problemResult->setPuzzle(NewPuzzle->getProblem(0));
1958 PiecesCountList->setPuzzle(NewPuzzle->getProblem(0));
1959 PcVis->setPuzzle(NewPuzzle->getProblem(0));
1960 } else {
1961 problemResult->setPuzzle(0);
1962 PiecesCountList->setPuzzle(0);
1963 PcVis->setPuzzle(0);
1964 }
1965 shapeAssignmentSelector->setPuzzle(NewPuzzle);
1966 solutionProblem->setPuzzle(NewPuzzle);
1967
1968 SolutionSel->value(1);
1969 SolutionAnim->value(0);
1970
1971 if (NewPuzzle != puzzle) {
1972 delete puzzle;
1973 puzzle = NewPuzzle;
1974 }
1975
1976 guiGridType_c * nggt = new guiGridType_c(puzzle->getGridType());
1977
1978 // now replace all gridtype dependent gui elements with
1979 // instances from the guigridtype
1980 pieceEdit->newGridType(nggt, puzzle);
1981 pieceTools->newGridType(nggt);
1982
1983 // for the pieceEditor we need to reset all the edit mode fields
1984 pieceEdit->editSymmetries(editSymmetries);
1985 switch(editChoice->getSelected()) {
1986 case 0: pieceEdit->editChoice(gridEditor_c::TSK_SET); break;
1987 case 1: pieceEdit->editChoice(gridEditor_c::TSK_VAR); break;
1988 case 2: pieceEdit->editChoice(gridEditor_c::TSK_RESET); break;
1989 case 3: pieceEdit->editChoice(gridEditor_c::TSK_COLOR); break;
1990 }
1991 switch(editMode->getSelected()) {
1992 case 0: pieceEdit->editType(gridEditor_c::EDT_RUBBER); break;
1993 case 1: pieceEdit->editType(gridEditor_c::EDT_SINGLE); break;
1994 }
1995
1996 delete ggt;
1997 ggt = nggt;
1998 }
1999
2000 Fl_Menu_Item mainWindow_c::menu_MainMenu[] = {
2001 { "&File", 0, 0, 0, FL_SUBMENU },
2002 {"New", 0, cb_New_stub, 0, 0, 0, 0, 14, 56},
2003 {"Load", FL_F + 3, cb_Load_stub, 0, 0, 0, 0, 14, 56},
2004 {"Import", 0, cb_Load_Ps3d_stub, 0, 0, 0, 0, 14, 56},
2005 {"Save", FL_F + 2, cb_Save_stub, 0, 0, 0, 0, 14, 56},
2006 {"Save As", 0, cb_SaveAs_stub, 0, FL_MENU_DIVIDER, 0, 0, 14, 56},
2007 {"Convert", 0, cb_Convert_stub, 0, 0, 0, 0, 14, 56},
2008 {"Import Assms", 0, cb_AssembliesToShapes_stub, 0, 0, 0, 0, 14, 56},
2009 {"Quit", 0, cb_Quit_stub, 0, 0, 3, 0, 14, 56},
2010 { 0 },
2011 {"Toggle 3D", FL_F + 4, cb_Toggle3D_stub, 0, 0, 0, 0, 14, 56},
2012 { "&Export", 0, 0, 0, FL_SUBMENU },
2013 {"Images", 0, cb_ImageExport_stub, 0, 0, 0, 0, 14, 56},
2014 {"Vector Image", 0, cb_ImageExportVector_stub, 0, 0, 0, 0, 14, 56},
2015 {"STL", 0, cb_STLExport_stub, 0, 0, 0, 0, 14, 56},
2016 { 0 },
2017 {"Status", 0, cb_StatusWindow_stub, 0, 0, 0, 0, 14, 56},
2018 {"Edit Comment", 0, cb_Comment_stub, 0, 0, 0, 0, 14, 56},
2019 {"Config", 0, cb_Config_stub, 0, 0, 0, 0, 14, 56},
2020 {"Help", FL_F + 1, cb_Help_stub, 0, 0, 0, 0, 14, 56},
2021 {"About", 0, cb_About_stub, 0, 0, 3, 0, 14, 56},
2022 {0}
2023 };
2024
show(int argn,char ** argv)2025 void mainWindow_c::show(int argn, char ** argv) {
2026 LFl_Double_Window::show();
2027
2028 int arg = 1;
2029
2030 // try all command line switches, until either they are
2031 // all tried or one got loaded successfully
2032 while (arg < argn)
2033 if (tryToLoad(argv[arg]))
2034 break;
2035 else
2036 arg++;
2037 }
2038
activateClear(void)2039 void mainWindow_c::activateClear(void) {
2040 View3D->getView()->showNothing();
2041 pieceEdit->clearPuzzle();
2042 pieceTools->setVoxelSpace(0, 0);
2043
2044 SolutionEmpty = true;
2045 }
2046
activateShape(unsigned int number)2047 void mainWindow_c::activateShape(unsigned int number) {
2048
2049 if ((number < puzzle->shapeNumber())) {
2050
2051 View3D->getView()->showSingleShape(puzzle, number);
2052 pieceEdit->setPuzzle(puzzle, number);
2053 pieceTools->setVoxelSpace(puzzle, number);
2054
2055 PcSel->setSelection(number);
2056
2057 } else {
2058
2059 View3D->getView()->showNothing();
2060 pieceEdit->clearPuzzle();
2061 pieceTools->setVoxelSpace(0, 0);
2062 }
2063
2064 SolutionEmpty = true;
2065 }
2066
activateProblem(unsigned int prob)2067 void mainWindow_c::activateProblem(unsigned int prob) {
2068
2069 if (prob < puzzle->problemNumber())
2070 View3D->getView()->showProblem(puzzle, prob, shapeAssignmentSelector->getSelection());
2071 else
2072 View3D->getView()->showNothing();
2073
2074 SolutionEmpty = true;
2075 }
2076
activateSolution(unsigned int prob,unsigned int num)2077 void mainWindow_c::activateSolution(unsigned int prob, unsigned int num) {
2078
2079 if (disassemble) {
2080 delete disassemble;
2081 disassemble = 0;
2082 }
2083
2084 if ((prob < puzzle->problemNumber()) && (num < puzzle->getProblem(prob)->solutionNumber())) {
2085
2086 problem_c * pr = puzzle->getProblem(prob);
2087
2088 PcVis->setPuzzle(puzzle->getProblem(prob));
2089 PcVis->setAssembly(pr->getSolution(num)->getAssembly());
2090 AssemblyNumber->show();
2091 AssemblyNumber->value(pr->getSolution(num)->getAssemblyNumber()+1);
2092
2093 if (pr->getSolution(num)->getDisassembly()) {
2094 SolutionAnim->show();
2095 SolutionAnim->range(0, pr->getSolution(num)->getDisassembly()->sumMoves());
2096
2097 SolutionsInfo->show();
2098
2099 MovesInfo->show();
2100
2101 char levelText[50];
2102 int len = snprintf(levelText, 50, "%i (", pr->getSolution(num)->getDisassembly()->sumMoves());
2103 pr->getSolution(num)->getDisassembly()->movesText(levelText + len, 50-len);
2104 levelText[strlen(levelText)+1] = 0;
2105 levelText[strlen(levelText)] = ')';
2106
2107 MovesInfo->value(levelText);
2108
2109 disassemble = new disasmToMoves_c(pr->getSolution(num)->getDisassembly(),
2110 2*pr->getResultShape()->getBiggestDimension(),
2111 pr->pieceNumber());
2112 disassemble->setStep(SolutionAnim->value(), config.useBlendedRemoving(), true);
2113
2114 if (prob < puzzle->problemNumber()) View3D->getView()->showAssembly(puzzle->getProblem(prob), num);
2115 View3D->getView()->updatePositions(disassemble);
2116 View3D->getView()->updateVisibility(PcVis);
2117
2118 SolutionNumber->show();
2119 SolutionNumber->value(pr->getSolution(num)->getSolutionNumber()+1);
2120
2121 } else if (pr->getSolution(num)->getDisassemblyInfo()) {
2122
2123 SolutionAnim->range(0, 0);
2124 SolutionAnim->hide();
2125
2126 SolutionsInfo->show();
2127
2128 MovesInfo->show();
2129
2130 char levelText[50];
2131 int len = snprintf(levelText, 50, "%i (", pr->getSolution(num)->getDisassemblyInfo()->sumMoves());
2132 pr->getSolution(num)->getDisassemblyInfo()->movesText(levelText + len, 50-len);
2133 levelText[strlen(levelText)+1] = 0;
2134 levelText[strlen(levelText)] = ')';
2135
2136 MovesInfo->value(levelText);
2137
2138 if (prob < puzzle->problemNumber()) View3D->getView()->showAssembly(puzzle->getProblem(prob), num);
2139 View3D->getView()->updateVisibility(PcVis);
2140
2141 SolutionNumber->show();
2142 SolutionNumber->value(pr->getSolution(num)->getSolutionNumber()+1);
2143
2144 } else {
2145
2146 SolutionAnim->range(0, 0);
2147 SolutionAnim->hide();
2148 MovesInfo->value(0);
2149 MovesInfo->hide();
2150
2151 if (prob < puzzle->problemNumber()) View3D->getView()->showAssembly(puzzle->getProblem(prob), num);
2152 View3D->getView()->updateVisibility(PcVis);
2153
2154 SolutionNumber->hide();
2155 }
2156
2157 SolutionEmpty = false;
2158
2159 } else {
2160
2161 View3D->getView()->showNothing();
2162 SolutionEmpty = true;
2163
2164 SolutionAnim->hide();
2165 MovesInfo->hide();
2166
2167 PcVis->setPuzzle(0);
2168
2169 AssemblyNumber->hide();
2170 SolutionNumber->hide();
2171 }
2172 }
2173
timeToString(float time)2174 const char * timeToString(float time) {
2175
2176 static char tmp[50];
2177
2178 if (time < 60) snprintf(tmp, 50, "%i seconds", int(time/(1 )));
2179 else if (time < 60*60) snprintf(tmp, 50, "%.1f minutes", time/(60 ));
2180 else if (time < 60*60*24) snprintf(tmp, 50, "%.1f hours", time/(60*60 ));
2181 else if (time < 60*60*24*30) snprintf(tmp, 50, "%.1f days", time/(60*60*24 ));
2182 else if (time < 60*60*24*365.2422) snprintf(tmp, 50, "%.1f months", time/(60*60*24*30 ));
2183 else if (time < 60*60*24*365.2422*1000) snprintf(tmp, 50, "%.1f years", time/(60*60*24*365.2422 ));
2184 else if (time < 60*60*24*365.2422*1000*1000) snprintf(tmp, 50, "%.1f millennia", time/(60*60*24*365.2422*1000));
2185 else snprintf(tmp, 50, "ages");
2186
2187 return tmp;
2188 }
2189
findMenuEntry(const char * txt)2190 int mainWindow_c::findMenuEntry(const char * txt) {
2191
2192 int found = -1;
2193
2194 for (unsigned int i = 0; i < (sizeof(menu_MainMenu) / sizeof(menu_MainMenu[0])); i++)
2195 if (menu_MainMenu[i].text && (strcmp(menu_MainMenu[i].label(), txt) == 0)) {
2196 bt_assert(found == -1);
2197 found = i;
2198 }
2199
2200 bt_assert(found >= 0);
2201 return found;
2202 }
2203
updateInterface(void)2204 void mainWindow_c::updateInterface(void) {
2205
2206 // update the menu items activate state
2207
2208 // there must be at least one shape before there is something to export...
2209 if (puzzle->shapeNumber() > 0)
2210 menu_MainMenu[findMenuEntry("Images")].activate();
2211 else
2212 menu_MainMenu[findMenuEntry("Images")].deactivate();
2213
2214 if (ggt->getGridType()->getCapabilities() & gridType_c::CAP_STLEXPORT &&
2215 puzzle->shapeNumber() > 0)
2216 menu_MainMenu[findMenuEntry("STL")].activate();
2217 else
2218 menu_MainMenu[findMenuEntry("STL")].deactivate();
2219
2220 MainMenu->copy(menu_MainMenu, this);
2221
2222 unsigned int prob = solutionProblem->getSelection();
2223
2224 if (TaskSelectionTab->value() == TabPieces) {
2225 // shapes tab
2226
2227 // we can only delete colours, when something valid is selected
2228 // and no assembler is running
2229 if ((colorSelector->getSelection() > 0) && !assmThread)
2230 BtnDelColor->activate();
2231 else
2232 BtnDelColor->deactivate();
2233
2234 // colours can be changed for all colours except the neutral colour
2235 if (colorSelector->getSelection() > 0)
2236 BtnChnColor->activate();
2237 else
2238 BtnChnColor->deactivate();
2239
2240 // we can only edit and copy shapes, when something valid is selected
2241 if (PcSel->getSelection() < puzzle->shapeNumber()) {
2242 BtnCpyShape->activate();
2243 BtnRenShape->activate();
2244 pieceEdit->activate();
2245 } else {
2246 BtnCpyShape->deactivate();
2247 BtnRenShape->deactivate();
2248 pieceEdit->deactivate();
2249 }
2250
2251 // shapes can only be moved, when the neighbour shape is there
2252 if ((PcSel->getSelection() > 0) && (PcSel->getSelection() < puzzle->shapeNumber()) && !assmThread)
2253 BtnShapeLeft->activate();
2254 else
2255 BtnShapeLeft->deactivate();
2256 if ((PcSel->getSelection()+1 < puzzle->shapeNumber()) && !assmThread)
2257 BtnShapeRight->activate();
2258 else
2259 BtnShapeRight->deactivate();
2260
2261 // we can only delete shapes, when something valid is selected
2262 // and no assembler is running
2263 if ((PcSel->getSelection() < puzzle->shapeNumber()) && !assmThread) {
2264 BtnDelShape->activate();
2265 } else {
2266 BtnDelShape->deactivate();
2267 }
2268
2269 const problem_c * pr = (assmThread) ? assmThread->getProblem() : 0;
2270
2271 // we can only edit shapes, when something valid is selected and
2272 // either no assembler is running or the shape is not in the problem that the assembler works on
2273 if ((PcSel->getSelection() < puzzle->shapeNumber()) &&
2274 (!assmThread || !pr->usesShape(PcSel->getSelection()))) {
2275 pieceTools->activate();
2276 } else {
2277 pieceTools->deactivate();
2278 }
2279
2280 // when the current shape is in the assembler we lock the editor, only viewing is possible
2281 if (assmThread && (pr->usesShape(PcSel->getSelection())))
2282 pieceEdit->deactivate();
2283 else
2284 pieceEdit->activate();
2285
2286 if (puzzle->colorNumber() < 63)
2287 BtnNewColor->activate();
2288 else
2289 BtnNewColor->deactivate();
2290
2291 } else if (TaskSelectionTab->value() == TabProblems) {
2292
2293 problem_c * pr = (problemSelector->getSelection() < puzzle->problemNumber())
2294 ? puzzle->getProblem(problemSelector->getSelection()) : 0;
2295
2296 // problem tab
2297 PiecesCountList->setPuzzle(pr);
2298 colconstrList->setPuzzle(puzzle, problemSelector->getSelection());
2299 problemResult->setPuzzle(pr);
2300
2301 // problems can only be renames and copied, when something valid is selected
2302 if (problemSelector->getSelection() < puzzle->problemNumber()) {
2303 BtnCpyProb->activate();
2304 BtnRenProb->activate();
2305 } else {
2306 BtnCpyProb->deactivate();
2307 BtnRenProb->deactivate();
2308 }
2309
2310 // problems can only be shifted around when the corresponding neighbour is
2311 // available
2312 if ((problemSelector->getSelection() > 0) && (problemSelector->getSelection() < puzzle->problemNumber()) && !assmThread)
2313 BtnProbLeft->activate();
2314 else
2315 BtnProbLeft->deactivate();
2316 if ((problemSelector->getSelection()+1 < puzzle->problemNumber()) && !assmThread)
2317 BtnProbRight->activate();
2318 else
2319 BtnProbRight->deactivate();
2320
2321 if (problemSelector->getSelection() < puzzle->problemNumber() && !assmThread)
2322 {
2323 unsigned int current;
2324 unsigned int p = problemSelector->getSelection();
2325 unsigned int s = shapeAssignmentSelector->getSelection();
2326
2327 problem_c * pr = puzzle->getProblem(p);
2328
2329 for (current = 0; current < pr->partNumber(); current++)
2330 if (pr->getShape(current) == s)
2331 break;
2332
2333 if (current && (current < pr->partNumber()))
2334 BtnProbShapeLeft->activate();
2335 else
2336 BtnProbShapeLeft->deactivate();
2337 if (current+1 < pr->partNumber())
2338 BtnProbShapeRight->activate();
2339 else
2340 BtnProbShapeRight->deactivate();
2341
2342 } else {
2343 BtnProbShapeRight->deactivate();
2344 BtnProbShapeLeft->deactivate();
2345 }
2346
2347 // problems can only be deleted, something valid is selected and the
2348 // assembler is not running
2349 if ((problemSelector->getSelection() < puzzle->problemNumber()) && !assmThread)
2350 BtnDelProb->activate();
2351 else
2352 BtnDelProb->deactivate();
2353
2354 // we can only edit colour constraints when a valid problem is selected
2355 // the selected colour is valid
2356 // the assembler is not running or not busy with the selected problem
2357 if ((problemSelector->getSelection() < puzzle->problemNumber()) &&
2358 (colorAssignmentSelector->getSelection() < puzzle->colorNumber()) &&
2359 (!assmThread || (assmThread->getProblem() != puzzle->getProblem(problemSelector->getSelection())))) {
2360
2361 problem_c * pr = puzzle->getProblem(problemSelector->getSelection());
2362
2363 // check, if the given colour is already added
2364 if (colconstrList->GetSortByResult()) {
2365 if (pr->placementAllowed(colorAssignmentSelector->getSelection()+1,
2366 colconstrList->getSelection()+1)) {
2367 BtnColAdd->deactivate();
2368 BtnColRem->activate();
2369 } else {
2370 BtnColAdd->activate();
2371 BtnColRem->deactivate();
2372 }
2373 } else {
2374 if (pr->placementAllowed(colconstrList->getSelection()+1,
2375 colorAssignmentSelector->getSelection()+1)) {
2376 BtnColAdd->deactivate();
2377 BtnColRem->activate();
2378 } else {
2379 BtnColAdd->activate();
2380 BtnColRem->deactivate();
2381 }
2382 }
2383 } else {
2384 BtnColAdd->deactivate();
2385 BtnColRem->deactivate();
2386 }
2387
2388 // we can only change shapes, when a valid problem is selected
2389 // a valid shape is selected
2390 // the assembler is not running or not busy with out problem
2391 if ((problemSelector->getSelection() < puzzle->problemNumber()) &&
2392 (shapeAssignmentSelector->getSelection() < puzzle->shapeNumber()) &&
2393 (!assmThread || (assmThread->getProblem() != puzzle->getProblem(problemSelector->getSelection())))) {
2394 BtnSetResult->activate();
2395
2396 problem_c * pr = puzzle->getProblem(problemSelector->getSelection());
2397
2398 // we can only add a shape, when it's not the result of the current problem
2399 if (!pr->resultValid() || pr->getResultId() != shapeAssignmentSelector->getSelection())
2400 BtnAddShape->activate();
2401 else
2402 BtnAddShape->deactivate();
2403
2404 bool found = false;
2405
2406 for (unsigned int p = 0; p < pr->partNumber(); p++)
2407 if (pr->getShape(p) == shapeAssignmentSelector->getSelection()) {
2408 found = true;
2409 break;
2410 }
2411
2412 if (found) {
2413 BtnRemShape->activate();
2414 BtnMinZero->activate();
2415 } else {
2416 BtnRemShape->deactivate();
2417 BtnMinZero->deactivate();
2418 }
2419
2420 } else {
2421 BtnSetResult->deactivate();
2422 BtnAddShape->deactivate();
2423 BtnRemShape->deactivate();
2424 BtnMinZero->deactivate();
2425 }
2426
2427 // we can edit the groups, when we have a problem with at least one shape and
2428 // the assembler is not working on the current problem
2429 if ((problemSelector->getSelection() < puzzle->problemNumber()) &&
2430 (!assmThread || (assmThread->getProblem() != puzzle->getProblem(problemSelector->getSelection())))) {
2431 BtnGroup->activate();
2432 } else {
2433 BtnGroup->deactivate();
2434 }
2435
2436 if ((problemSelector->getSelection() < puzzle->problemNumber()) &&
2437 (!assmThread || (assmThread->getProblem() != puzzle->getProblem(problemSelector->getSelection())))) {
2438 BtnAddAll->activate();
2439 BtnRemAll->activate();
2440 } else {
2441 BtnAddAll->deactivate();
2442 BtnRemAll->deactivate();
2443 }
2444
2445 } else {
2446
2447 float finished = ((prob < puzzle->problemNumber()) &&
2448 puzzle->getProblem(prob)->getAssembler())
2449 ? puzzle->getProblem(prob)->getAssembler()->getFinished()
2450 : 0;
2451
2452 if (prob < puzzle->problemNumber()) {
2453
2454 problem_c * pr = puzzle->getProblem(prob);
2455
2456 // solution tab
2457 PcVis->setPuzzle(pr);
2458
2459 // we have a valid problem selected, so update the information visible
2460
2461 SolvingProgress->value(100*finished);
2462 SolvingProgress->show();
2463
2464 {
2465 static char tmp[100];
2466 snprintf(tmp, 100, "%.4f%%", 100*finished);
2467 SolvingProgress->label(tmp);
2468 }
2469
2470 unsigned long numSol = pr->solutionNumber();
2471
2472 if (numSol > 0) {
2473
2474 SolutionSel->show();
2475 SolutionsInfo->show();
2476
2477 SolutionSel->range(1, numSol);
2478 if (SolutionSel->value() > numSol)
2479 SolutionSel->value(numSol);
2480 SolutionsInfo->value(numSol);
2481
2482 // if we are in the solve tab and have a valid solution
2483 // we can activate that
2484 if (SolutionEmpty && (numSol > 0)) {
2485 activateSolution(prob, 0);
2486 SolutionSel->value(1);
2487 }
2488
2489 } else {
2490
2491 SolutionSel->range(1, 1);
2492 SolutionSel->hide();
2493 SolutionsInfo->hide();
2494 SolutionAnim->hide();
2495 MovesInfo->hide();
2496
2497 AssemblyNumber->hide();
2498 SolutionNumber->hide();
2499 }
2500
2501 if (pr->numAssembliesKnown()) {
2502 OutputAssemblies->value(pr->getNumAssemblies());
2503 OutputAssemblies->show();
2504 } else {
2505 OutputAssemblies->hide();
2506 }
2507
2508 if (pr->numSolutionsKnown()) {
2509 OutputSolutions->value(pr->getNumSolutions());
2510 OutputSolutions->show();
2511 } else {
2512 OutputSolutions->hide();
2513 }
2514
2515 // the placement browser can only be activated when an assembler is available and not assembling is active
2516 if (pr->getAssembler() && !assmThread) {
2517 BtnPlacement->activate();
2518 } else {
2519 BtnPlacement->deactivate();
2520 }
2521
2522 // the step button is only active when the placements browser can be active AND when the puzzle is not
2523 // yet completely solved
2524 if (pr->getAssembler() && !assmThread && (pr->getSolveState() != SS_SOLVED)) {
2525 if (BtnStep) BtnStep->activate();
2526 } else {
2527 if (BtnStep) BtnStep->deactivate();
2528 }
2529
2530 if (pr->solutionNumber() >= 2) {
2531 BtnSrtFind->activate();
2532 BtnSrtLevel->activate();
2533 BtnSrtMoves->activate();
2534 BtnSrtPieces->activate();
2535 } else {
2536 BtnSrtFind->deactivate();
2537 BtnSrtLevel->deactivate();
2538 BtnSrtMoves->deactivate();
2539 BtnSrtPieces->deactivate();
2540 }
2541
2542 if (pr->solutionNumber() > 0) {
2543 BtnDelAll->activate();
2544 if (SolutionSel->value() > 1)
2545 BtnDelBefore->activate();
2546 else
2547 BtnDelBefore->deactivate();
2548
2549 BtnDelAt->activate();
2550
2551 if ((SolutionSel->value()-1) < (pr->solutionNumber()-1))
2552 BtnDelAfter->activate();
2553 else
2554 BtnDelAfter->deactivate();
2555
2556 BtnDelDisasm->activate();
2557 } else {
2558 BtnDelAll->deactivate();
2559 BtnDelBefore->deactivate();
2560 BtnDelAt->deactivate();
2561 BtnDelAfter->deactivate();
2562 BtnDelDisasm->deactivate();
2563 }
2564
2565 if ((SolutionSel->value() >= 1) &&
2566 ((int)SolutionSel->value()-1) < (int)pr->solutionNumber() &&
2567 pr->getSolution((int)SolutionSel->value()-1)->getDisassembly()) {
2568 BtnDisasmDel->activate();
2569 } else {
2570 BtnDisasmDel->deactivate();
2571 }
2572
2573 if (pr->solutionNumber() > 0) {
2574 BtnDisasmDelAll->activate();
2575 } else {
2576 BtnDisasmDelAll->deactivate();
2577 }
2578
2579 if (ggt->getGridType()->getCapabilities() & gridType_c::CAP_DISASSEMBLE) {
2580
2581 if (pr->solutionNumber() > 0) {
2582 BtnDisasmAdd->activate();
2583 BtnDisasmAddAll->activate();
2584 BtnDisasmAddMissing->activate();
2585 } else {
2586 BtnDisasmAdd->deactivate();
2587 BtnDisasmAddAll->deactivate();
2588 BtnDisasmAddMissing->deactivate();
2589 }
2590 SolveDisasm->activate();
2591 } else {
2592 BtnDisasmAdd->deactivate();
2593 BtnDisasmAddAll->deactivate();
2594 BtnDisasmAddMissing->deactivate();
2595 SolveDisasm->deactivate();
2596 SolveDisasm->value(0);
2597 }
2598
2599 if (ggt->getGridType()->getCapabilities() & gridType_c::CAP_DISASSEMBLE &&
2600 !assmThread &&
2601 solutionProblem->getSelection() < puzzle->problemNumber() &&
2602 (int)SolutionSel->value()-1 < puzzle->getProblem(solutionProblem->getSelection())->solutionNumber()
2603 )
2604 {
2605 BtnMovement->activate();
2606 }
2607 else
2608 {
2609 BtnMovement->deactivate();
2610 }
2611 } else {
2612
2613 // no valid problem available, hide all information
2614
2615 SolutionSel->hide();
2616 SolutionsInfo->hide();
2617 OutputSolutions->hide();
2618 SolutionAnim->hide();
2619 MovesInfo->hide();
2620
2621 AssemblyNumber->hide();
2622 SolutionNumber->hide();
2623
2624 SolvingProgress->hide();
2625 OutputAssemblies->hide();
2626
2627 BtnPlacement->deactivate();
2628 BtnMovement->deactivate();
2629 if (BtnStep) BtnStep->deactivate();
2630 if (BtnPrepare) BtnPrepare->deactivate();
2631
2632 BtnSrtFind->deactivate();
2633 BtnSrtLevel->deactivate();
2634 BtnSrtMoves->deactivate();
2635 BtnSrtPieces->deactivate();
2636 BtnDelAll->deactivate();
2637 BtnDelBefore->deactivate();
2638 BtnDelAt->deactivate();
2639 BtnDelAfter->deactivate();
2640 BtnDelDisasm->deactivate();
2641 BtnDisasmDel->deactivate();
2642 BtnDisasmDelAll->deactivate();
2643 BtnDisasmAdd->deactivate();
2644 BtnDisasmAddAll->deactivate();
2645 BtnDisasmAddMissing->deactivate();
2646
2647 PcVis->setPuzzle(0);
2648 }
2649
2650
2651 if (assmThread && (assmThread->getProblem() == puzzle->getProblem(prob))) {
2652
2653 problem_c * pr = puzzle->getProblem(prob);
2654
2655 // a thread is currently running
2656
2657 unsigned int ut;
2658 if (pr->usedTimeKnown())
2659 ut = pr->getUsedTime() + assmThread->getTime();
2660 else
2661 ut = assmThread->getTime();
2662
2663 TimeUsed->value(timeToString(ut));
2664 if (finished != 0)
2665 TimeEst->value(timeToString(ut/finished-ut));
2666 else
2667 TimeEst->value("unknown");
2668
2669 TimeUsed->show();
2670 TimeEst->show();
2671
2672 } else {
2673
2674 if ((prob < puzzle->problemNumber()) && puzzle->getProblem(prob)->usedTimeKnown()) {
2675 problem_c * pr = puzzle->getProblem(prob);
2676 TimeUsed->value(timeToString(pr->getUsedTime()));
2677 TimeUsed->show();
2678 } else {
2679 TimeUsed->hide();
2680 }
2681
2682 TimeEst->hide();
2683 }
2684
2685 if (assmThread) {
2686
2687 problem_c * pr = puzzle->getProblem(prob);
2688
2689 switch(assmThread->currentAction()) {
2690 case solveThread_c::ACT_PREPARATION:
2691 {
2692 char tmp[20];
2693 snprintf(tmp, 20, "prepare piece %i", assmThread->currentActionParameter()+1);
2694 OutputActivity->value(tmp);
2695 }
2696 break;
2697 case solveThread_c::ACT_REDUCE:
2698 if (pr->getAssembler()) {
2699 char tmp[20];
2700 snprintf(tmp, 20, "optimize piece %i", pr->getAssembler()->getReducePiece()+1);
2701 OutputActivity->value(tmp);
2702 } else {
2703 char tmp[20];
2704 snprintf(tmp, 20, "optimize piece %i", assmThread->currentActionParameter()+1);
2705 OutputActivity->value(tmp);
2706 }
2707 break;
2708 case solveThread_c::ACT_ASSEMBLING:
2709 OutputActivity->value("assemble");
2710 break;
2711 case solveThread_c::ACT_DISASSEMBLING:
2712 OutputActivity->value("disassemble");
2713 break;
2714 case solveThread_c::ACT_PAUSING:
2715 OutputActivity->value("pause");
2716 break;
2717 case solveThread_c::ACT_FINISHED:
2718 OutputActivity->value("finished");
2719 break;
2720 case solveThread_c::ACT_WAIT_TO_STOP:
2721 OutputActivity->value("please wait");
2722 break;
2723 case solveThread_c::ACT_ERROR:
2724 OutputActivity->value("error");
2725 break;
2726 }
2727
2728 if (assmThread->getProblem() == puzzle->getProblem(prob)) {
2729
2730 // for the actually solved problem we enable the stop button
2731 BtnStart->deactivate();
2732 if (BtnPrepare) BtnPrepare->deactivate();
2733 BtnCont->deactivate();
2734 BtnStop->activate();
2735
2736 // we can not edit solutions for a currently solved problem
2737 BtnSrtFind->deactivate();
2738 BtnSrtLevel->deactivate();
2739 BtnSrtMoves->deactivate();
2740 BtnSrtPieces->deactivate();
2741 BtnDelAll->deactivate();
2742 BtnDelBefore->deactivate();
2743 BtnDelAt->deactivate();
2744 BtnDelAfter->deactivate();
2745 BtnDelDisasm->deactivate();
2746 BtnDisasmDel->deactivate();
2747 BtnDisasmDelAll->deactivate();
2748 BtnDisasmAdd->deactivate();
2749 BtnDisasmAddAll->deactivate();
2750 BtnDisasmAddMissing->deactivate();
2751
2752 } else {
2753
2754 // all other problems can do nothing
2755 BtnStart->deactivate();
2756 if (BtnPrepare) BtnPrepare->deactivate();
2757 BtnCont->deactivate();
2758 BtnStop->deactivate();
2759 if (BtnPrepare) BtnPrepare->deactivate();
2760
2761 }
2762
2763 } else {
2764
2765 pieceEdit->activate();
2766
2767 // no thread currently calculating
2768
2769 // so we can not stop the thread
2770 BtnStop->deactivate();
2771
2772 // the stop button might be pressed when the thread finished, this might happen
2773 // relatively often, so we clear the state of that button
2774 BtnStop->clear();
2775
2776 if (prob < puzzle->problemNumber()) {
2777
2778 problem_c * pr = puzzle->getProblem(prob);
2779 // a valid problem is selected
2780
2781 switch(pr->getSolveState()) {
2782 case SS_UNSOLVED:
2783 OutputActivity->value("nothing");
2784 BtnCont->deactivate();
2785 break;
2786 case SS_SOLVED:
2787 OutputActivity->value("finished");
2788 BtnCont->deactivate();
2789 break;
2790 case SS_SOLVING:
2791 OutputActivity->value("pause");
2792 BtnCont->activate();
2793 break;
2794 case SS_UNKNOWN:
2795 OutputActivity->value("partial");
2796 BtnCont->deactivate();
2797 break;
2798
2799 }
2800
2801 // if we have a result and at least one piece, we can give it a try
2802 if ((pr->pieceNumber() > 0) && (pr->resultValid())) {
2803 BtnStart->activate();
2804 if (BtnPrepare) BtnPrepare->activate();
2805 } else {
2806 BtnStart->deactivate();
2807 if (BtnPrepare) BtnPrepare->deactivate();
2808 }
2809
2810 } else {
2811
2812 // no start possible, when no valid problem selected
2813 BtnStart->deactivate();
2814 if (BtnPrepare) BtnPrepare->deactivate();
2815 BtnCont->deactivate();
2816 if (BtnPrepare) BtnPrepare->deactivate();
2817 }
2818 }
2819 }
2820
2821 TaskSelectionTab->redraw();
2822 }
2823
update(void)2824 void mainWindow_c::update(void) {
2825
2826 if (assmThread) {
2827
2828 // check, if the thread has thrown an exception, if so re-throw it
2829 if (assmThread->currentAction() == solveThread_c::ACT_ASSERT) {
2830
2831 assertWindow_c * aw = new assertWindow_c("Because of an internal error the current puzzle\n"
2832 "can not be solved\n",
2833 &(assmThread->getAssertException()));
2834
2835 aw->show();
2836
2837 while (aw->visible())
2838 Fl::wait();
2839
2840 delete aw;
2841 delete assmThread;
2842 assmThread = 0;
2843 updateInterface();
2844 return;
2845 }
2846
2847 // check, if the thread has stopped, if so then delete the object
2848 if ((assmThread->currentAction() == solveThread_c::ACT_PAUSING) ||
2849 (assmThread->currentAction() == solveThread_c::ACT_FINISHED)) {
2850
2851 delete assmThread;
2852 assmThread = 0;
2853
2854 } else if (assmThread->currentAction() == solveThread_c::ACT_ERROR) {
2855
2856 unsigned int selectShape = 0xFFFFFFFF;
2857
2858 switch(assmThread->getErrorState()) {
2859 case assembler_c::ERR_TOO_MANY_UNITS:
2860 fl_message("Pieces contain %i units too many", assmThread->getErrorParam());
2861 break;
2862 case assembler_c::ERR_TOO_FEW_UNITS:
2863 fl_message("Pieces contain %i units less than required\n"
2864 "See user guide sections\n"
2865 "1.3.2.1 'Voxel States'\n"
2866 "3.4.2 'Basic Drawing Tools' and\n"
2867 "3.8 'Miscellaneous Editing Tools'", assmThread->getErrorParam());
2868 break;
2869 case assembler_c::ERR_CAN_NOT_PLACE:
2870 fl_message("Piece %i can be placed nowhere within the result", assmThread->getErrorParam()+1);
2871 selectShape = assmThread->getErrorParam();
2872 break;
2873 case assembler_c::ERR_CAN_NOT_RESTORE_VERSION:
2874 fl_message("Impossible to restore the saved state because the internal format changed.\n"
2875 "You either have to start from the beginning or finish with the old version of BurrTools, sorry");
2876 break;
2877 case assembler_c::ERR_CAN_NOT_RESTORE_SYNTAX:
2878 fl_message("Impossible to restore the saved state because something with the data is wrong.\n"
2879 "You have to start from the beginning, sorry");
2880 break;
2881 case assembler_c::ERR_PUZZLE_UNHANDABLE:
2882 fl_message("Something went wrong the program can not solve your puzzle definitions.\n"
2883 "You should send the puzzle file to the programmer!");
2884 break;
2885 default:
2886 break;
2887 }
2888
2889 if (selectShape < puzzle->shapeNumber()) {
2890 TaskSelectionTab->value(TabPieces);
2891 PcSel->setSelection(selectShape);
2892 activateShape(PcSel->getSelection());
2893 updateInterface();
2894 StatPieceInfo(PcSel->getSelection());
2895 }
2896
2897 delete assmThread;
2898 assmThread = 0;
2899 }
2900
2901 // update the window, either when the thread stopped and so the buttons need to
2902 // be updated, or then the thread works for the currently selected problem
2903 if (!assmThread || assmThread->getProblem() == puzzle->getProblem(solutionProblem->getSelection()))
2904 updateInterface();
2905 }
2906 }
2907
Toggle3DView(void)2908 void mainWindow_c::Toggle3DView(void)
2909 {
2910 // select the pieces tab, as exchanging widgets while they are invisible
2911 // didn't work. Save the current tab before that
2912 // this is required when changing the tab and we need to get the 3D view back
2913 // in the large window
2914 TaskSelectionTab->when(0);
2915 Fl_Widget *v = TaskSelectionTab->value();
2916 if (v != TabPieces) TaskSelectionTab->value(TabPieces);
2917
2918 // exchange widget positions
2919 Fl_Group * tmp = pieceEdit->parent();
2920 View3D->parent()->add(pieceEdit);
2921 tmp->add(View3D);
2922
2923 // exchange sizes
2924 {
2925 int x = pieceEdit->x();
2926 int y = pieceEdit->y();
2927 int w = pieceEdit->w();
2928 int h = pieceEdit->h();
2929 pieceEdit->resize(View3D->x(), View3D->y(), View3D->w(), View3D->h());
2930 View3D->resize(x, y, w, h);
2931 }
2932
2933 // exchange grid positions
2934 {
2935 unsigned int x1, y1, w1, h1, x2, y2, w2, h2;
2936 pieceEdit->getGridValues(&x1, &y1, &w1, &h1);
2937 View3D->getGridValues (&x2, &y2, &w2, &h2);
2938
2939 pieceEdit->setGridValues( x2, y2, w2, h2);
2940 View3D->setGridValues ( x1, y1, w1, h1);
2941 }
2942
2943 is3DViewBig = !is3DViewBig;
2944
2945 if (is3DViewBig)
2946 pieceEdit->parent()->resizable(pieceEdit);
2947 else
2948 View3D->parent()->resizable(View3D);
2949
2950 // restore the old selected tab
2951 if (v != TabPieces) TaskSelectionTab->value(v);
2952 TaskSelectionTab->when(FL_WHEN_CHANGED);
2953 }
2954
Big3DView(void)2955 void mainWindow_c::Big3DView(void) {
2956 if (!is3DViewBig) Toggle3DView();
2957 View3D->show();
2958 redraw();
2959 }
2960
Small3DView(void)2961 void mainWindow_c::Small3DView(void) {
2962 if (is3DViewBig) Toggle3DView();
2963 pieceEdit->show();
2964 redraw();
2965 }
2966
handle(int event)2967 int mainWindow_c::handle(int event) {
2968
2969 if (Fl_Double_Window::handle(event))
2970 return 1;
2971
2972 switch(event) {
2973 case FL_SHORTCUT:
2974 if (Fl::event_length()) {
2975 switch (Fl::event_text()[0]) {
2976 case '+':
2977 if (TaskSelectionTab->value() == TabPieces) {
2978 pieceEdit->setZ(pieceEdit->getZ()+1);
2979 return 1;
2980 }
2981 break;
2982 case '-':
2983 if (TaskSelectionTab->value() == TabPieces) {
2984 if (pieceEdit->getZ() > 0)
2985 pieceEdit->setZ(pieceEdit->getZ()-1);
2986 return 1;
2987 }
2988 break;
2989 }
2990 }
2991 switch(Fl::event_key()) {
2992 case FL_F + 5:
2993 if (TaskSelectionTab->value() == TabPieces) {
2994 editChoice->select(0);
2995 return 1;
2996 }
2997 break;
2998 case FL_F + 6:
2999 if (TaskSelectionTab->value() == TabPieces) {
3000 editChoice->select(1);
3001 return 1;
3002 }
3003 break;
3004 case FL_F + 7:
3005 if (TaskSelectionTab->value() == TabPieces) {
3006 editChoice->select(2);
3007 return 1;
3008 }
3009 break;
3010 case FL_F + 8:
3011 if (TaskSelectionTab->value() == TabPieces) {
3012 editChoice->select(3);
3013 return 1;
3014 }
3015 break;
3016 }
3017 }
3018
3019 return 0;
3020 }
3021
3022 #define SZ_GAP 5 // gap between elements
3023
CreateShapeTab(void)3024 void mainWindow_c::CreateShapeTab(void) {
3025
3026 TabPieces = new layouter_c();
3027 TabPieces->label("Entities");
3028 TabPieces->tooltip("Edit shapes");
3029 TabPieces->clear_visible_focus();
3030
3031 LFl_Tile * tile = new LFl_Tile(0, 0, 1, 1);
3032 tile->pitch(SZ_GAP);
3033
3034 {
3035 layouter_c * group = new layouter_c(0, 0);
3036 group->box(FL_FLAT_BOX);
3037
3038 new LSeparator_c(0, 0, 1, 1, "Shapes", false);
3039
3040 layouter_c * o = new layouter_c(0, 1);
3041
3042 BtnNewShape = new LFlatButton_c(0, 0, 1, 1, "New", " Add another piece ", cb_NewShape_stub, this);
3043 ((LFlatButton_c*)BtnNewShape)->weight(1, 0);
3044 (new LFl_Box(1, 0))->setMinimumSize(SZ_GAP, 0);
3045 BtnDelShape = new LFlatButton_c(2, 0, 1, 1, "Delete", " Delete selected piece ", cb_DeleteShape_stub, this);
3046 ((LFlatButton_c*)BtnDelShape)->weight(1, 0);
3047 (new LFl_Box(3, 0))->setMinimumSize(SZ_GAP, 0);
3048 BtnCpyShape = new LFlatButton_c(4, 0, 1, 1, "Copy", " Copy selected piece ", cb_CopyShape_stub, this);
3049 ((LFlatButton_c*)BtnCpyShape)->weight(1, 0);
3050 (new LFl_Box(5, 0))->setMinimumSize(SZ_GAP, 0);
3051 BtnRenShape = new LFlatButton_c(6, 0, 1, 1, "Label", " Give the selected shape a name ", cb_NameShape_stub, this);
3052 ((LFlatButton_c*)BtnRenShape)->weight(1, 0);
3053 (new LFl_Box(7, 0))->setMinimumSize(SZ_GAP, 0);
3054 BtnWeightInc = new LFlatButton_c(8, 0, 1, 1, "W+", " Increase Weight of the selected shape ",cb_WeightInc_stub, this);
3055 (new LFl_Box(9, 0))->setMinimumSize(SZ_GAP, 0);
3056 BtnWeightDec = new LFlatButton_c(10, 0, 1, 1, "W-", " Decrease Weight of the selected shape ",cb_WeightDec_stub, this);
3057 (new LFl_Box(11, 0))->setMinimumSize(SZ_GAP, 0);
3058 BtnShapeLeft = new LFlatButton_c(12, 0, 1, 1, "@-14->", " Exchange current shape with previous shape ", cb_ShapeLeft_stub, this);
3059 (new LFl_Box(13, 0))->setMinimumSize(SZ_GAP, 0);
3060 BtnShapeRight = new LFlatButton_c(14, 0, 1, 1, "@-16->", " Exchange current shape with next shape ", cb_ShapeRight_stub, this);
3061
3062 o->end();
3063
3064 (new LFl_Box(0, 2))->setMinimumSize(0, SZ_GAP);
3065
3066 PcSel = new PieceSelector(0, 0, 200, 200, puzzle);
3067 LBlockListGroup_c * selGroup = new LBlockListGroup_c(0, 3, 1, 1, PcSel);
3068 selGroup->callback(cb_PcSel_stub, this);
3069 selGroup->tooltip(" Select the shape that you want to edit ");
3070 selGroup->weight(1, 1);
3071
3072 group->end();
3073 }
3074
3075 {
3076 layouter_c * group = new layouter_c(0, 1);
3077 group->box(FL_FLAT_BOX);
3078
3079 new LSeparator_c(0, 0, 1, 1, "Edit", true);
3080
3081 pieceTools = new ToolTabContainer(0, 1, 1, 1, ggt);
3082 pieceTools->callback(cb_TransformPiece_stub, this);
3083
3084 (new LFl_Box(0, 2, 1, 1))->setMinimumSize(0, 5);
3085
3086 layouter_c * o2 = new layouter_c(0, 3, 1, 1);
3087
3088 editChoice = new ButtonGroup_c(0, 0, 1, 1);
3089
3090 Fl_Button * b;
3091 b = editChoice->addButton();
3092 b->image(pm.get(TB_Color_Pen_Fixed_xpm));
3093 b->tooltip(" Add normal voxels to the shape F5 ");
3094
3095 b = editChoice->addButton();
3096 b->image(pm.get(TB_Color_Pen_Variable_xpm));
3097 b->tooltip(" Add variable voxels to the shape F6 ");
3098
3099 b = editChoice->addButton();
3100 b->image(pm.get(TB_Color_Eraser_xpm));
3101 b->tooltip(" Remove voxels from the shape F7 ");
3102
3103 b = editChoice->addButton();
3104 b->image(pm.get(TB_Color_Brush_xpm));
3105 b->tooltip(" Change the constrain colour of voxels in the shape F8 ");
3106
3107 editChoice->callback(cb_EditChoice_stub, this);
3108
3109 (new LFl_Box(1, 0, 1, 1))->setMinimumSize(5, 0);
3110
3111 editMode = new ButtonGroup_c(2, 0, 1, 1);
3112
3113 b = editMode->addButton();
3114 b->image(pm.get(TB_Color_Mouse_Rubber_Band_xpm));
3115 b->tooltip(" Make changes by dragging rectangular areas in the grid editor ");
3116
3117 b = editMode->addButton();
3118 b->image(pm.get(TB_Color_Mouse_Drag_xpm));
3119 b->tooltip(" Make changes by painting in the grid editor ");
3120
3121 editMode->callback(cb_EditMode_stub, this);
3122
3123 (new LFl_Box(3, 0, 1, 1))->setMinimumSize(5, 0);
3124
3125 LToggleButton_c * btn;
3126
3127 btn = new LToggleButton_c(4, 0, 1, 1, cb_EditSym_stub, this, gridEditor_c::TOOL_MIRROR_X);
3128 btn->image(pm.get(TB_Color_Symmetrical_X_xpm));
3129 btn->tooltip(" Toggle mirroring along the y-z-plane ");
3130
3131 btn = new LToggleButton_c(5, 0, 1, 1, cb_EditSym_stub, this, gridEditor_c::TOOL_MIRROR_Y);
3132 btn->image(pm.get(TB_Color_Symmetrical_Y_xpm));
3133 btn->tooltip(" Toggle mirroring along the x-z-plane ");
3134
3135 btn = new LToggleButton_c(6, 0, 1, 1, cb_EditSym_stub, this, gridEditor_c::TOOL_MIRROR_Z);
3136 btn->image(pm.get(TB_Color_Symmetrical_Z_xpm));
3137 btn->tooltip(" Toggle mirroring along the x-y-plane ");
3138
3139 (new LFl_Box(7, 0, 1, 1))->setMinimumSize(5, 0);
3140
3141 btn = new LToggleButton_c(8, 0, 1, 1, cb_EditSym_stub, this, gridEditor_c::TOOL_STACK_X);
3142 btn->image(pm.get(TB_Color_Columns_X_xpm));
3143 btn->tooltip(" Toggle drawing in all x layers ");
3144
3145 btn = new LToggleButton_c(9, 0, 1, 1, cb_EditSym_stub, this, gridEditor_c::TOOL_STACK_Y);
3146 btn->image(pm.get(TB_Color_Columns_Y_xpm));
3147 btn->tooltip(" Toggle drawing in all y layers ");
3148
3149 btn = new LToggleButton_c(10, 0, 1, 1, cb_EditSym_stub, this, gridEditor_c::TOOL_STACK_Z);
3150 btn->image(pm.get(TB_Color_Columns_Z_xpm));
3151 btn->tooltip(" Toggle drawing in all z layers ");
3152
3153 (new LFl_Box(11, 0, 1, 1))->weight(1, 0);
3154
3155 o2->end();
3156
3157 (new LFl_Box(0, 4, 1, 1))->setMinimumSize(0, 5);
3158
3159 pieceEdit = new VoxelEditGroup_c(0, 5, 1, 1, puzzle, ggt);
3160 pieceEdit->callback(cb_pieceEdit_stub, this);
3161 pieceEdit->end();
3162 pieceEdit->editType(gridEditor_c::EDT_RUBBER);
3163 pieceEdit->weight(0, 1);
3164
3165 group->end();
3166 }
3167
3168 {
3169 layouter_c * group = new layouter_c(0, 2);
3170 group->box(FL_FLAT_BOX);
3171
3172 new LSeparator_c(0, 0, 1, 1, "Colours", true);
3173
3174 layouter_c * o = new layouter_c(0, 1);
3175
3176 BtnNewColor = new LFlatButton_c(0, 0, 1, 1, "Add", " Add another colour ", cb_AddColor_stub, this);
3177 ((LFlatButton_c*)BtnNewColor)->weight(1, 0);
3178 (new LFl_Box(1, 0))->setMinimumSize(SZ_GAP, 0);
3179 BtnDelColor = new LFlatButton_c(2, 0, 1, 1, "Remove", " Remove selected colour ", cb_RemoveColor_stub, this);
3180 ((LFlatButton_c*)BtnDelColor)->weight(1, 0);
3181 (new LFl_Box(3, 0))->setMinimumSize(SZ_GAP, 0);
3182 BtnChnColor = new LFlatButton_c(4, 0, 1, 1, "Edit", " Change selected colour ", cb_ChangeColor_stub, this);
3183 ((LFlatButton_c*)BtnChnColor)->weight(1, 0);
3184
3185 o->end();
3186
3187 (new LFl_Box(0, 2))->setMinimumSize(0, SZ_GAP);
3188
3189 colorSelector = new ColorSelector(0, 0, 200, 200, puzzle, true);
3190 LBlockListGroup_c * colGroup = new LBlockListGroup_c(0, 3, 1, 1, colorSelector);
3191 colGroup->callback(cb_ColSel_stub, this);
3192 colGroup->tooltip(" Select colour to use for all editing operations ");
3193 colGroup->weight(1, 1);
3194
3195 group->end();
3196 }
3197
3198 tile->end();
3199
3200 TabPieces->resizable(tile);
3201 TabPieces->end();
3202
3203 Fl_Group::current()->resizable(TabPieces);
3204 }
3205
CreateProblemTab(void)3206 void mainWindow_c::CreateProblemTab(void) {
3207
3208 TabProblems = new layouter_c();
3209 TabProblems->label("Puzzle");
3210 TabProblems->tooltip("Edit problems");
3211 TabProblems->hide();
3212 TabProblems->clear_visible_focus();
3213
3214 LFl_Tile * tile = new LFl_Tile(0, 0, 1, 1);
3215 tile->pitch(SZ_GAP);
3216
3217 {
3218 layouter_c * group = new layouter_c(0, 0);
3219 group->box(FL_FLAT_BOX);
3220
3221 new LSeparator_c(0, 0, 1, 1, "Problems", false);
3222
3223 layouter_c * o = new layouter_c(0, 1);
3224
3225 BtnNewProb = new LFlatButton_c(0, 0, 1, 1, "New", " Add another problem ", cb_NewProblem_stub, this);
3226 ((LFlatButton_c*)BtnNewProb)->weight(1, 0);
3227 (new LFl_Box(1, 0))->setMinimumSize(SZ_GAP, 0);
3228 BtnDelProb = new LFlatButton_c(2, 0, 1, 1, "Delete", " Delete selected problem ", cb_DeleteProblem_stub, this);
3229 ((LFlatButton_c*)BtnDelProb)->weight(1, 0);
3230 (new LFl_Box(3, 0))->setMinimumSize(SZ_GAP, 0);
3231 BtnCpyProb = new LFlatButton_c(4, 0, 1, 1, "Copy", " Copy selected problem ", cb_CopyProblem_stub, this);
3232 ((LFlatButton_c*)BtnCpyProb)->weight(1, 0);
3233 (new LFl_Box(5, 0))->setMinimumSize(SZ_GAP, 0);
3234 BtnRenProb = new LFlatButton_c(6, 0, 1, 1, "Label", " Rename selected problem ", cb_RenameProblem_stub, this);
3235 ((LFlatButton_c*)BtnRenProb)->weight(1, 0);
3236 (new LFl_Box(7, 0))->setMinimumSize(SZ_GAP, 0);
3237
3238 BtnProbLeft = new LFlatButton_c(8, 0, 1, 1, "@-14->", " Exchange current problem with previous problem ", cb_ProblemLeft_stub, this);
3239 (new LFl_Box(9, 0))->setMinimumSize(SZ_GAP, 0);
3240 BtnProbRight = new LFlatButton_c(10, 0, 1, 1, "@-16->", " Exchange current problem with next problem ", cb_ProblemRight_stub, this);
3241
3242 o->end();
3243
3244 (new LFl_Box(0, 2))->setMinimumSize(0, SZ_GAP);
3245
3246 problemSelector = new ProblemSelector(0, 0, 100, 100, puzzle);
3247 LBlockListGroup_c * probGroup = new LBlockListGroup_c(0, 3, 1, 1, problemSelector);
3248 probGroup->callback(cb_ProbSel_stub, this);
3249 probGroup->tooltip(" Select problem to edit ");
3250 probGroup->weight(1, 1);
3251
3252 group->end();
3253 }
3254
3255 {
3256 layouter_c * group = new layouter_c(0, 1);
3257 group->box(FL_FLAT_BOX);
3258
3259 new LSeparator_c(0, 0, 1, 1, "Piece Assignment", true);
3260
3261 layouter_c * o = new layouter_c(0, 1);
3262
3263 problemResult = new ResultViewer_c(0, 0, 1, 1);
3264 problemResult->tooltip(" The result shape for the current problem ");
3265 problemResult->weight(1, 0);
3266
3267 (new LFl_Box(1, 0))->setMinimumSize(SZ_GAP, 0);
3268
3269 BtnSetResult = new LFlatButton_c(2, 0, 1, 1, "Set Result", " Set selected shape as result ", cb_ShapeToResult_stub, this);
3270
3271 o->end();
3272
3273 (new LFl_Box(0, 2))->setMinimumSize(0, SZ_GAP);
3274
3275 shapeAssignmentSelector = new PieceSelector(0, 0, 100, 100, puzzle);
3276 LBlockListGroup_c * shapeGroup = new LBlockListGroup_c(0, 3, 1, 1, shapeAssignmentSelector);
3277 shapeGroup->callback(cb_ShapeSel_stub, this);
3278 shapeGroup->tooltip(" Select a shape to set as result or to add or remove from problem ");
3279 shapeGroup->weight(1, 1);
3280
3281 group->end();
3282 }
3283
3284 {
3285 layouter_c * group = new layouter_c(0, 2);
3286 group->box(FL_FLAT_BOX);
3287
3288 new LSeparator_c(0, 0, 1, 1, 0, true);
3289
3290 layouter_c * o = new layouter_c(0, 1);
3291
3292 int xp = 0;
3293
3294 BtnAddShape = new LFlatButton_c(xp++, 0, 1, 1, "+1", " Add another one of the selected shape ", cb_AddShapeToProblem_stub, this);
3295 ((LFlatButton_c*)BtnAddShape)->weight(1, 0);
3296 (new LFl_Box(xp++, 0))->setMinimumSize(SZ_GAP, 0);
3297 BtnRemShape = new LFlatButton_c(xp++, 0, 1, 1, "-1", " Remove one of the selected shapes ", cb_RemoveShapeFromProblem_stub, this);
3298 ((LFlatButton_c*)BtnRemShape)->weight(1, 0);
3299 (new LFl_Box(xp++, 0))->setMinimumSize(SZ_GAP, 0);
3300 BtnMinZero = new LFlatButton_c(xp++, 0, 1, 1, "min=0", " Set minimum number of pieces to 0 ", cb_SetShapeMinimumToZero_stub, this);
3301 ((LFlatButton_c*)BtnMinZero)->weight(1, 0);
3302 (new LFl_Box(xp++, 0))->setMinimumSize(SZ_GAP, 0);
3303 BtnAddAll = new LFlatButton_c(xp++, 0, 1, 1, "all+1", " Add one of all shapes except result ", cb_AddAllShapesToProblem_stub, this);
3304 ((LFlatButton_c*)BtnAddAll)->weight(1, 0);
3305 (new LFl_Box(xp++, 0))->setMinimumSize(SZ_GAP, 0);
3306 BtnRemAll = new LFlatButton_c(xp++, 0, 1, 1, "Clr", " Remove all pieces ", cb_RemoveAllShapesFromProblem_stub, this);
3307 ((LFlatButton_c*)BtnRemAll)->weight(1, 0);
3308 (new LFl_Box(xp++, 0))->setMinimumSize(SZ_GAP, 0);
3309 BtnGroup = new LFlatButton_c(xp++, 0, 1, 1, "Detail", " Edit details of the problem ", cb_ShapeGroup_stub, this);
3310 ((LFlatButton_c*)BtnGroup)->weight(1, 0);
3311 (new LFl_Box(xp++, 0))->setMinimumSize(SZ_GAP, 0);
3312 BtnProbShapeLeft = new LFlatButton_c(xp++, 0, 1, 1, "@-14->", " Exchange current shape with previous shape ", cb_ProbShapeLeft_stub, this);
3313 (new LFl_Box(xp++, 0))->setMinimumSize(SZ_GAP, 0);
3314 BtnProbShapeRight = new LFlatButton_c(xp++, 0, 1, 1, "@-16->", " Exchange current shape with next shape ", cb_ProbShapeRight_stub, this);
3315
3316 o->end();
3317
3318 (new LFl_Box(0, 2))->setMinimumSize(0, SZ_GAP);
3319
3320 PiecesCountList = new PiecesList(0, 0, 100, 100);
3321 LBlockListGroup_c * shapeGroup = new LBlockListGroup_c(0, 3, 1, 1, PiecesCountList);
3322 shapeGroup->callback(cb_PiecesClicked_stub, this);
3323 shapeGroup->tooltip(" Show which shapes are used in the current problem and how often they are used, can be used to select shapes ");
3324 shapeGroup->weight(1, 1);
3325
3326 group->end();
3327 }
3328
3329 {
3330 layouter_c * group = new layouter_c(0, 3);
3331 group->box(FL_FLAT_BOX);
3332
3333 new LSeparator_c(0, 0, 1, 1, "Colour Assignment", true);
3334
3335 colorAssignmentSelector = new ColorSelector(0, 0, 100, 100, puzzle, false);
3336 LBlockListGroup_c * colGroup = new LBlockListGroup_c(0, 1, 1, 1, colorAssignmentSelector);
3337 colGroup->callback(cb_ColorAssSel_stub, this);
3338 colGroup->tooltip(" Select colour to add or remove from constraints ");
3339 colGroup->weight(1, 1);
3340
3341 group->end();
3342 }
3343
3344 {
3345 layouter_c * group = new layouter_c(0, 4);
3346 group->box(FL_FLAT_BOX);
3347
3348 new LSeparator_c(0, 0, 1, 1, 0, true);
3349
3350 layouter_c * o = new layouter_c(0, 1);
3351
3352 BtnColSrtPc = new LFlatButton_c(0, 0, 1, 1, "Sort by Piece", " Sort colour constraints by piece ", cb_CCSortByPiece_stub, this);
3353 ((LFlatButton_c*)BtnColSrtPc)->weight(1, 0);
3354 (new LFl_Box(1, 0))->setMinimumSize(SZ_GAP, 0);
3355 BtnColAdd = new LFlatButton_c(2, 0, 1, 1, "@-12->", " Add colour to constraint ", cb_AllowColor_stub, this);
3356 BtnColRem = new LFlatButton_c(3, 0, 1, 1, "@-18->", " Add colour to constraint ", cb_DisallowColor_stub, this);
3357 (new LFl_Box(4, 0))->setMinimumSize(SZ_GAP, 0);
3358 BtnColSrtRes = new LFlatButton_c(5, 0, 1, 1, "Sort by Result", " Sort Colour Constraints by Result ", cb_CCSortByResult_stub, this);
3359 ((LFlatButton_c*)BtnColSrtRes)->weight(1, 0);
3360
3361 o->end();
3362
3363 (new LFl_Box(0, 2))->setMinimumSize(0, SZ_GAP);
3364
3365 colconstrList = new ColorConstraintsEdit(0, 0, 100, 100, puzzle);
3366 LConstraintsGroup_c * colGroup = new LConstraintsGroup_c(0, 3, 1, 1, colconstrList);
3367 colGroup->callback(cb_ColorConstrSel_stub, this);
3368 colGroup->tooltip(" Colour constraints for the current problem ");
3369 colGroup->weight(1, 1);
3370
3371 group->end();
3372 }
3373
3374 tile->end();
3375
3376 TabProblems->resizable(tile);
3377 TabProblems->end();
3378 }
3379
CreateSolveTab(void)3380 void mainWindow_c::CreateSolveTab(void) {
3381
3382 TabSolve = new layouter_c();
3383 TabSolve->label("Solver");
3384 TabSolve->tooltip("Solve problems");
3385 TabSolve->hide();
3386 TabSolve->clear_visible_focus();
3387
3388 LFl_Tile * tile = new LFl_Tile(0, 0, 1, 1);
3389 tile->pitch(SZ_GAP);
3390
3391 {
3392 layouter_c * group = new layouter_c(0, 0);
3393 group->box(FL_FLAT_BOX);
3394
3395 new LSeparator_c(0, 0, 1, 1, "Parameters", false);
3396
3397 solutionProblem = new ProblemSelector(0, 0, 100, 100, puzzle);
3398 LBlockListGroup_c * shapeGroup = new LBlockListGroup_c(0, 1, 1, 1, solutionProblem);
3399 shapeGroup->callback(cb_SolProbSel_stub, this);
3400 shapeGroup->tooltip(" Select problem to solve ");
3401 shapeGroup->weight(1, 1);
3402
3403 layouter_c * o = new layouter_c(0, 2);
3404
3405 SolveDisasm = new LFl_Check_Button("Disassemble", 0, 0, 1, 1);
3406 SolveDisasm->tooltip(" Do also try to disassemble the assembled puzzles. Only puzzles that can be disassembled will be added to solutions ");
3407 SolveDisasm->clear_visible_focus();
3408
3409 JustCount = new LFl_Check_Button("Just Count", 0, 1, 1, 1);
3410 JustCount->tooltip(" Don\'t save the solutions, just count the number of them ");
3411 JustCount->clear_visible_focus();
3412
3413 CompleteRotations = new LFl_Check_Button("Expnsv Rot Check", 0, 2, 1, 1);
3414 CompleteRotations->tooltip(" Do expensive and thorough rotation check, eliminating translations and rotations not in symmetry of the result shape ");
3415 CompleteRotations->clear_visible_focus();
3416
3417 DropDisassemblies = new LFl_Check_Button("Drop Disassemblies", 1, 0, 1, 1);
3418 DropDisassemblies->tooltip(" Don\'t save the Disassemblies, just the information about them ");
3419 DropDisassemblies->clear_visible_focus();
3420
3421 KeepMirrors = new LFl_Check_Button("Keep Mirror Solutions", 1, 1, 1, 1);
3422 KeepMirrors->tooltip(" Don't remove solutions that are mirrors of another solution ");
3423 KeepMirrors->clear_visible_focus();
3424
3425 KeepRotations = new LFl_Check_Button("Keep Rotated Solutions", 1, 2, 1, 1);
3426 KeepRotations->tooltip(" Don't remove solutions that are rotations of other solutions ");
3427 KeepRotations->clear_visible_focus();
3428
3429 o->end();
3430
3431 o = new layouter_c(0, 3);
3432
3433 new LFl_Box("Sort by: ", 0, 0, 1, 1);
3434
3435 sortMethod = new LFl_Choice(1, 0, 1, 1);
3436 ((LFl_Choice*)sortMethod)->weight(1, 0);
3437
3438 // be careful the order in here must correspond with the enumeration in assembler thread
3439 sortMethod->add("Unsorted");
3440 sortMethod->add("Moves for Complete Disassembly");
3441 sortMethod->add("Level");
3442
3443 sortMethod->value(1);
3444
3445 o->end();
3446
3447 (new LFl_Box(0, 4))->setMinimumSize(0, SZ_GAP);
3448
3449 o = new layouter_c(0, 5);
3450
3451 new LFl_Box("Drop ", 0, 0, 1, 1);
3452 new LFl_Box("Limit ", 3, 0, 1, 1);
3453 (new LFl_Box(2, 0))->setMinimumSize(SZ_GAP, 0);
3454
3455 solDrop = new LFl_Value_Input(1, 0, 1, 1);
3456 solLimit = new LFl_Value_Input(4, 0, 1, 1);
3457 solDrop->bounds(1, 100000000);
3458 solLimit->bounds(1, 100000000);
3459 solLimit->step(1, 1);
3460 solDrop->step(1, 1);
3461
3462 solDrop->value(1);
3463 solLimit->value(100);
3464
3465 ((LFl_Value_Input*)solDrop)->weight(1, 0);
3466 ((LFl_Value_Input*)solLimit)->weight(1, 0);
3467
3468 o->end();
3469
3470 (new LFl_Box(0, 6))->setMinimumSize(0, SZ_GAP);
3471
3472 o = new layouter_c(0, 7);
3473
3474 if (expertMode) {
3475 BtnPrepare = new LFlatButton_c(0, 0, 1, 1, "Prepare", " Do the preparation phase and then stop, this removes old results ", cb_BtnPrepare_stub, this);
3476 ((LFlatButton_c*)BtnPrepare)->weight(1, 0);
3477 (new LFl_Box(1, 0))->setMinimumSize(SZ_GAP, 0);
3478 } else
3479 BtnPrepare = 0;
3480 BtnStart = new LFlatButton_c(2, 0, 1, 1, "Start", " Start new solving process, removing old result ", cb_BtnStart_stub, this);
3481 ((LFlatButton_c*)BtnStart)->weight(1, 0);
3482 (new LFl_Box(3, 0))->setMinimumSize(SZ_GAP, 0);
3483 BtnCont = new LFlatButton_c(4, 0, 1, 1, "Continue", " Continue started process ", cb_BtnCont_stub, this);
3484 ((LFlatButton_c*)BtnCont)->weight(1, 0);
3485 (new LFl_Box(5, 0))->setMinimumSize(SZ_GAP, 0);
3486 BtnStop = new LFlatButton_c(6, 0, 1, 1, "Stop", " Stop a currently running solution process ", cb_BtnStop_stub, this);
3487 ((LFlatButton_c*)BtnStop)->weight(1, 0);
3488
3489 o->end();
3490
3491 (new LFl_Box(0, 8))->setMinimumSize(0, SZ_GAP);
3492
3493 o = new layouter_c(0, 9);
3494
3495 BtnPlacement = new LFlatButton_c(0, 0, 1, 1, "Placements", " Browse the calculated placement of pieces ", cb_BtnPlacementBrowser_stub, this);
3496 ((LFlatButton_c*)BtnPlacement)->weight(1, 0);
3497
3498 (new LFl_Box(1, 0))->setMinimumSize(SZ_GAP, 0);
3499
3500 BtnMovement = new LFlatButton_c(2, 0, 1, 1, "Movements", " Browse the possible movements for an assembly ", cb_BtnMovementBrowser_stub, this);
3501 ((LFlatButton_c*)BtnMovement)->weight(1, 0);
3502
3503 if (expertMode)
3504 {
3505 (new LFl_Box(3, 0))->setMinimumSize(SZ_GAP, 0);
3506
3507 BtnStep = new LFlatButton_c(4, 0, 1, 1, "Step", " Make one step in the assembler ", cb_BtnAssemblerStep_stub, this);
3508 ((LFlatButton_c*)BtnStep)->weight(1, 0);
3509 } else
3510 BtnStep = 0;
3511
3512 o->end();
3513
3514 (new LFl_Box(0, 10))->setMinimumSize(0, SZ_GAP);
3515
3516 SolvingProgress = new LFl_Progress(0, 11, 1, 1);
3517 SolvingProgress->tooltip(" Percentage of solution space searched ");
3518 SolvingProgress->box(FL_ENGRAVED_BOX);
3519 SolvingProgress->selection_color((Fl_Color)4);
3520 SolvingProgress->align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE);
3521
3522 o = new layouter_c(0, 12);
3523
3524 (new LFl_Box("Activity: ", 0, 0, 1, 1))->stretchRight();
3525 OutputActivity = new LFl_Output(1, 0, 3, 1);
3526 OutputActivity->box(FL_FLAT_BOX);
3527 OutputActivity->color(FL_BACKGROUND_COLOR);
3528 OutputActivity->tooltip(" What is currently done ");
3529 OutputActivity->clear_visible_focus();
3530
3531 (new LFl_Box("Assemblies: ", 0, 1, 1, 1))->stretchRight();
3532 OutputAssemblies = new LFl_Value_Output(1, 1, 1, 1);
3533 OutputAssemblies->box(FL_FLAT_BOX);
3534 OutputAssemblies->step(1); // make output NOT use scientific presentation for big numbers
3535 OutputAssemblies->tooltip(" Number of assemblies found so far ");
3536 ((LFl_Value_Output*)OutputAssemblies)->weight(2, 0);
3537
3538 (new LFl_Box("Solutions: ", 0, 2, 1, 1))->stretchRight();
3539 OutputSolutions = new LFl_Value_Output(1, 2, 1, 1);
3540 OutputSolutions->box(FL_FLAT_BOX);
3541 OutputSolutions->step(1); // make output NOT use scientific presentation for big numbers
3542 OutputSolutions->tooltip(" Number of solutions (assemblies that can be disassembled) found so far ");
3543
3544 (new LFl_Box("Time used: ", 2, 1, 1, 1))->stretchRight();
3545 TimeUsed = new LFl_Output(3, 1, 1, 1);
3546 TimeUsed->box(FL_NO_BOX);
3547 ((LFl_Output*)TimeUsed)->weight(4, 0);
3548
3549 (new LFl_Box("Time left: ", 2, 2, 1, 1))->stretchRight();
3550 TimeEst = new LFl_Output(3, 2, 1, 1);
3551 TimeEst->box(FL_NO_BOX);
3552 TimeEst->tooltip(" This is a very approximate estimate and can be totally wrong, to take with a grain of salt ");
3553
3554 o->end();
3555
3556 group->end();
3557 }
3558
3559 {
3560 layouter_c * group = new layouter_c(0, 1);
3561 group->box(FL_FLAT_BOX);
3562
3563 new LSeparator_c(0, 0, 1, 1, "Solutions", true);
3564
3565 layouter_c * o = new layouter_c(0, 1);
3566
3567 new LFl_Box("Solution", 0, 0, 1, 1);
3568
3569 // Gap between Solution and value
3570 (new LFl_Box(1, 0))->setMinimumSize(SZ_GAP, 0);
3571
3572 SolutionsInfo = new LFl_Value_Output(2, 0, 1, 1);
3573 SolutionsInfo->tooltip(" Number of solutions ");
3574 SolutionsInfo->box(FL_FLAT_BOX);
3575 ((LFl_Value_Output*)SolutionsInfo)->weight(1, 0);
3576
3577 SolutionSel = new LFl_Value_Slider(0, 1, 3, 1);
3578 SolutionSel->tooltip(" Select one Solution ");
3579 SolutionSel->value(1);
3580 SolutionSel->type(1);
3581 SolutionSel->step(1);
3582 SolutionSel->callback(cb_SolutionSel_stub, this);
3583 SolutionSel->align(FL_ALIGN_TOP_LEFT);
3584
3585 (new LFl_Box(0, 3))->setMinimumSize(0, SZ_GAP);
3586
3587 new LFl_Box("Move", 0, 4, 1, 1);
3588
3589 MovesInfo = new LFl_Output(2, 4, 1, 1);
3590 MovesInfo->tooltip(" Steps for complete disassembly ");
3591 MovesInfo->box(FL_FLAT_BOX);
3592 MovesInfo->color(FL_BACKGROUND_COLOR);
3593 ((LFl_Output*)MovesInfo)->weight(1, 0);
3594
3595 SolutionAnim = new LFl_Value_Slider(0, 5, 3, 1);
3596 SolutionAnim->tooltip(" Animate the disassembly ");
3597 SolutionAnim->type(1);
3598 SolutionAnim->step(0.02);
3599 SolutionAnim->callback(cb_SolutionAnim_stub, this);
3600 SolutionAnim->align(FL_ALIGN_TOP_LEFT);
3601
3602 o->end();
3603
3604 (new LFl_Box(0, 2))->setMinimumSize(0, SZ_GAP);
3605
3606 o = new layouter_c(0, 3);
3607
3608 new LFl_Box("Assembly:", 0, 0, 1, 1);
3609 new LFl_Box("Solution:", 2, 0, 1, 1);
3610
3611 AssemblyNumber = new LFl_Value_Output(1, 0, 1, 1);
3612 SolutionNumber = new LFl_Value_Output(3, 0, 1, 1);
3613 AssemblyNumber->box(FL_FLAT_BOX);
3614 SolutionNumber->box(FL_FLAT_BOX);
3615 AssemblyNumber->step(1); // make output NOT use scientific presentation for big numbers
3616 SolutionNumber->step(1); // make output NOT use scientific presentation for big numbers
3617 ((LFl_Value_Output*)AssemblyNumber)->weight(1, 0);
3618 ((LFl_Value_Output*)SolutionNumber)->weight(1, 0);
3619
3620 o->end();
3621
3622 (new LFl_Box(0, 4))->setMinimumSize(0, SZ_GAP);
3623
3624 o = new layouter_c(0, 5);
3625
3626 new LFl_Box("Sort by: ", 0, 0);
3627
3628 BtnSrtFind = new LFlatButton_c(1, 0, 1, 1, "Number", " Sort in the order the solutions were found ", cb_SrtFind_stub, this);
3629 ((LFlatButton_c*)BtnSrtFind)->weight(1, 0);
3630 (new LFl_Box(2, 0))->setMinimumSize(SZ_GAP, 0);
3631 BtnSrtLevel = new LFlatButton_c(3, 0, 1, 1, "Level", " Sort in the order of increasing level ", cb_SrtLevel_stub, this);
3632 ((LFlatButton_c*)BtnSrtLevel)->weight(1, 0);
3633 (new LFl_Box(4, 0))->setMinimumSize(SZ_GAP, 0);
3634 BtnSrtMoves = new LFlatButton_c(5, 0, 1, 1, "Disasm", " Sort in the order of increasing moves for complete disassembly ", cb_SrtMoves_stub, this);
3635 ((LFlatButton_c*)BtnSrtMoves)->weight(1, 0);
3636 (new LFl_Box(6, 0))->setMinimumSize(SZ_GAP, 0);
3637 BtnSrtPieces = new LFlatButton_c(7, 0, 1, 1, "Pieces", " Sort in the order of used pieces ", cb_SrtPieces_stub, this);
3638 ((LFlatButton_c*)BtnSrtPieces)->weight(1, 0);
3639
3640 o->end();
3641
3642 (new LFl_Box(0, 6))->setMinimumSize(0, SZ_GAP);
3643
3644 o = new layouter_c(0, 7);
3645
3646 new LFl_Box("Delete: ", 0, 0);
3647
3648 BtnDelAll = new LFlatButton_c(1, 0, 1, 1, "All", " Delete all solutions ", cb_DelAll_stub, this);
3649 ((LFlatButton_c*)BtnDelAll)->weight(1, 0);
3650 (new LFl_Box(2, 0))->setMinimumSize(SZ_GAP, 0);
3651 BtnDelBefore = new LFlatButton_c(3, 0, 1, 1, "Before", " Delete all before the currently selected one ", cb_DelBefore_stub, this);
3652 ((LFlatButton_c*)BtnDelBefore)->weight(1, 0);
3653 (new LFl_Box(4, 0))->setMinimumSize(SZ_GAP, 0);
3654 BtnDelAt = new LFlatButton_c(5, 0, 1, 1, "At", " Delete current solution ", cb_DelAt_stub, this);
3655 ((LFlatButton_c*)BtnDelAt)->weight(1, 0);
3656 (new LFl_Box(6, 0))->setMinimumSize(SZ_GAP, 0);
3657 BtnDelAfter = new LFlatButton_c(7, 0, 1, 1, "After", " Delete all solutions after the currently selected one ", cb_DelAfter_stub, this);
3658 ((LFlatButton_c*)BtnDelAfter)->weight(1, 0);
3659 (new LFl_Box(8, 0))->setMinimumSize(SZ_GAP, 0);
3660 BtnDelDisasm = new LFlatButton_c(9, 0, 1, 1, "w/o DA", " Delete all solutions without valid disassembly ", cb_DelDisasmless_stub, this);
3661 ((LFlatButton_c*)BtnDelDisasm)->weight(1, 0);
3662
3663 o->end();
3664
3665 (new LFl_Box(0, 8))->setMinimumSize(0, SZ_GAP);
3666
3667 o = new layouter_c(0, 9);
3668
3669 BtnDisasmDel = new LFlatButton_c(0, 0, 1, 1, "D DA", " Remove the disassembly for the current solution ", cb_DelDisasm_stub, this);
3670 ((LFlatButton_c*)BtnDisasmDel)->weight(1, 0);
3671 (new LFl_Box(1, 0))->setMinimumSize(SZ_GAP, 0);
3672 BtnDisasmDelAll = new LFlatButton_c(2, 0, 1, 1, "D A DA", " Remove the disassemblies for all solutions ", cb_DelAllDisasm_stub, this);
3673 ((LFlatButton_c*)BtnDisasmDelAll)->weight(1, 0);
3674 (new LFl_Box(3, 0))->setMinimumSize(SZ_GAP, 0);
3675 BtnDisasmAdd = new LFlatButton_c(4, 0, 1, 1, "A DA", " Recalculate the disassembly for the current solution ", cb_AddDisasm_stub, this);
3676 ((LFlatButton_c*)BtnDisasmAdd)->weight(1, 0);
3677 (new LFl_Box(5, 0))->setMinimumSize(SZ_GAP, 0);
3678 BtnDisasmAddAll = new LFlatButton_c(6, 0, 1, 1, "A A DA", " Recalculate the disassemblies for all solutions ", cb_AddAllDisasm_stub, this);
3679 ((LFlatButton_c*)BtnDisasmAddAll)->weight(1, 0);
3680 (new LFl_Box(7, 0))->setMinimumSize(SZ_GAP, 0);
3681 BtnDisasmAddMissing=new LFlatButton_c(8, 0, 1, 1, "A M DA", " Recalculate the missing disassemblies for all solutions without valid disassembly ", cb_AddMissingDisasm_stub, this);
3682 ((LFlatButton_c*)BtnDisasmAddMissing)->weight(1, 0);
3683
3684 o->end();
3685
3686 (new LFl_Box(0, 10))->setMinimumSize(0, SZ_GAP);
3687
3688 PcVis = new PieceVisibility(0, 0, 100, 100);
3689 LBlockListGroup_c * shapeGroup = new LBlockListGroup_c(0, 11, 1, 1, PcVis);
3690 shapeGroup->callback(cb_PcVis_stub, this);
3691 shapeGroup->tooltip(" Change appearance of the pieces between normal, grid and invisible ");
3692 shapeGroup->weight(1, 1);
3693
3694 group->end();
3695 }
3696 tile->end();
3697
3698 TabSolve->resizable(tile);
3699 TabSolve->end();
3700 }
3701
activateConfigOptions(void)3702 void mainWindow_c::activateConfigOptions(void) {
3703
3704 if (config.useTooltips())
3705 Fl_Tooltip::enable();
3706 else
3707 Fl_Tooltip::disable();
3708
3709 View3D->getView()->useLightning(config.useLightning());
3710 View3D->getView()->setRotaterMethod(config.rotationMethod());
3711 }
3712
mainWindow_c(gridType_c * gt)3713 mainWindow_c::mainWindow_c(gridType_c * gt) : LFl_Double_Window(true) {
3714
3715 assmThread = 0;
3716 fname = 0;
3717 disassemble = 0;
3718 editSymmetries = 0;
3719 expertMode = true;
3720
3721 puzzle = new puzzle_c(gt);
3722 ggt = new guiGridType_c(puzzle->getGridType());
3723 changed = false;
3724
3725 label("BurrTools - unknown");
3726 user_data((void*)(this));
3727
3728 MainMenu = new LFl_Menu_Bar(0, 0, 1, 1);
3729 MainMenu->copy(menu_MainMenu, this);
3730
3731 StatusLine = new LStatusLine(0, 2, 1, 1);
3732 StatusLine->callback(cb_Status_stub, this);
3733
3734 LFl_Tile * mainTile = new LFl_Tile(0, 1, 1, 1);
3735 mainTile->weight(0, 1);
3736
3737 layouter_c * lay = new layouter_c(1, 0, 1, 1);
3738 View3D = new LView3dGroup(0, 0, 1, 1);
3739 lay->weight(1, 0);
3740 lay->end();
3741 lay->setMinimumSize(400, 400);
3742 View3D->weight(0, 1);
3743 View3D->callback(cb_3dClick_stub, this);
3744
3745 // this box paints the background behind the tab, because the tabs are partly transparent
3746 (new LFl_Box(0, 0, 1, 1))->color(FL_BACKGROUND_COLOR);
3747
3748 // the tab for the tool bar
3749 TaskSelectionTab = new LFl_Tabs(0, 0, 1, 1);
3750 TaskSelectionTab->callback(cb_TaskSelectionTab_stub, this);
3751 TaskSelectionTab->clear_visible_focus();
3752
3753 // the three tabs
3754 CreateShapeTab();
3755 CreateProblemTab();
3756 CreateSolveTab();
3757
3758 currentTab = 0;
3759 ViewSizes[0] = -1;
3760 ViewSizes[1] = -1;
3761 ViewSizes[2] = -1;
3762
3763 resize(config.windowPosX(), config.windowPosY(), config.windowPosW(), config.windowPosH());
3764
3765 if (!config.useRubberband())
3766 editMode->select(1);
3767 else
3768 editMode->select(0);
3769
3770 is3DViewBig = true;
3771 shapeEditorWithBig3DView = true;
3772
3773 updateInterface();
3774 activateClear();
3775
3776 // set the edit mode from the selected mode
3777 cb_EditChoice();
3778
3779 activateConfigOptions();
3780 }
3781
~mainWindow_c()3782 mainWindow_c::~mainWindow_c() {
3783
3784 config.windowPos(x(), y(), w(), h());
3785
3786 if (assmThread) {
3787 delete assmThread;
3788 assmThread = 0;
3789 }
3790
3791 delete puzzle;
3792
3793 if (fname) {
3794 delete [] fname;
3795 fname = 0;
3796 }
3797
3798 if (disassemble) {
3799 delete disassemble;
3800 disassemble = 0;
3801 }
3802
3803 if (ggt)
3804 delete ggt;
3805 }
3806