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