1 //
2 // gui_cb.cc
3 //
4
5 #include "wx/event.h"
6 #include "wx/menu.h"
7 #include "wx/msgdlg.h"
8 #include "wx/numdlg.h"
9 #include "wx/string.h"
10
11 #include <set>
12 #include <sstream>
13 #include <vector>
14 #include "aboutbox.h"
15 #include "canvas.h"
16 #include "config.h"
17 #include "edge.h"
18 #include "exporter.h"
19 #include "factory.h"
20 #include "fancyfileselection.h"
21 #include "graph.h"
22 #include "gui.h"
23 #include "lang.h"
24 #include "matrix.h"
25 #include "matrixdialog.h"
26 #include "paramdialog.h"
27 #include "polynomial.h"
28 #include "undo.h"
29 #include "vertex.h"
30
31
cb_File_Load(wxCommandEvent & event)32 void GTFrame::cb_File_Load (wxCommandEvent &event)
33 {
34 FancyFileSelection fs (this, _("Load File"), wxOPEN);
35 bool res;
36
37 if (fs.ShowModal () == wxID_CANCEL)
38 return;
39
40 Graph *g = graph->load (fs.GetFileName (), res);
41 if (!g) {
42 msg (_("Loading failed"), _("Loading failed"));
43 return;
44 }
45 if (!res)
46 msg (_("Warning"), _("WARNING:\n\n"
47 "The loading partially failed;\n"
48 "this graph may be incomplete."));
49
50 undoableAction (_("Load graph"));
51 delete graph;
52 graph = g;
53
54 canvas->redraw ();
55 }
56
cb_File_Save(wxCommandEvent & event)57 void GTFrame::cb_File_Save (wxCommandEvent &event)
58 {
59 FancyFileSelection fs (this, _("Save File"), wxSAVE, true);
60
61 if (fs.ShowModal () == wxID_CANCEL)
62 return;
63
64 // Put in creator tag if omitted
65 if (graph->get_tag ("creator").IsEmpty ())
66 graph->set_tag ("creator", wxT("GraphThing " GT_VERSION));
67
68 Exporter *exp = Exporter::make (fs.GetFileType (), fs.GetFileName ());
69 bool labels = view_Labels->IsChecked ();
70 bool weights = view_Weights->IsChecked ();
71 exp->output (graph, labels, weights);
72 delete exp;
73 }
74
cb_File_Exit(wxCommandEvent & event)75 void GTFrame::cb_File_Exit (wxCommandEvent &event)
76 {
77 Close ();
78 }
79
cb_Edit_Undo(wxCommandEvent & event)80 void GTFrame::cb_Edit_Undo (wxCommandEvent &event)
81 {
82 if (undoStack.empty ())
83 return;
84 delete graph;
85 graph = undoStack.pop ().getGraph ();
86 canvas->redraw ();
87 if (undoStack.empty ()) {
88 edit_Undo->Enable (false);
89 setUndoText (wxT(""));
90 } else
91 setUndoText (undoStack.top ().getMessage ());
92 }
93
cb_Edit_SelectAll(wxCommandEvent & event)94 void GTFrame::cb_Edit_SelectAll (wxCommandEvent &event)
95 {
96 Graph::e_const_iterator eit;
97 Graph::v_const_iterator vit;
98
99 for (eit = graph->e_begin (); eit != graph->e_end (); ++eit)
100 graph->select (*eit);
101 for (vit = graph->v_begin (); vit != graph->v_end (); ++vit)
102 graph->select (*vit);
103
104 canvas->redraw ();
105 }
106
cb_Edit_SelectNone(wxCommandEvent & event)107 void GTFrame::cb_Edit_SelectNone (wxCommandEvent &event)
108 {
109 graph->unselect_all ();
110 canvas->redraw ();
111 }
112
cb_Edit_InvertSelectionVertices(wxCommandEvent & event)113 void GTFrame::cb_Edit_InvertSelectionVertices (wxCommandEvent &event)
114 {
115 Graph::v_const_iterator vit;
116
117 for (vit = graph->v_begin (); vit != graph->v_end (); ++vit) {
118 if ((*vit)->selected)
119 graph->unselect (*vit);
120 else
121 graph->select (*vit);
122 }
123
124 canvas->redraw ();
125 }
126
cb_Edit_InvertSelectionEdges(wxCommandEvent & event)127 void GTFrame::cb_Edit_InvertSelectionEdges (wxCommandEvent &event)
128 {
129 Graph::e_const_iterator eit;
130
131 for (eit = graph->e_begin (); eit != graph->e_end (); ++eit) {
132 if ((*eit)->selected)
133 graph->unselect (*eit);
134 else
135 graph->select (*eit);
136 }
137
138 canvas->redraw ();
139 }
140
cb_Edit_InvertSelectionAll(wxCommandEvent & event)141 void GTFrame::cb_Edit_InvertSelectionAll (wxCommandEvent &event)
142 {
143 cb_Edit_InvertSelectionVertices (event);
144 cb_Edit_InvertSelectionEdges (event);
145 }
146
cb_View(wxCommandEvent & event)147 void GTFrame::cb_View (wxCommandEvent &event)
148 {
149 // Flows are only enabled when weights are
150 view_Flows->Enable (view_Weights->IsChecked ());
151
152 canvas->setParam (view_Labels->IsChecked (),
153 view_Weights->IsChecked (),
154 view_Flows->IsChecked ());
155 canvas->redraw ();
156 }
157
cb_Graph_Clear(wxCommandEvent & event)158 void GTFrame::cb_Graph_Clear (wxCommandEvent &event)
159 {
160 undoableAction (_("Clear graph"));
161 graph->clear ();
162 canvas->redraw ();
163 }
164
cb_Graph_Complement(wxCommandEvent & event)165 void GTFrame::cb_Graph_Complement (wxCommandEvent &event)
166 {
167 Graph *orig = graph;
168 Graph::e_const_iterator eit;
169 Graph::v_const_iterator vit, vit2;
170
171 undoableAction (_("Complement graph"));
172 graph = new Graph;
173 for (vit = orig->v_begin (); vit != orig->v_end (); ++vit)
174 graph->add (new Vertex (**vit));
175 // Method: create a new complete graph, then remove the edges that were
176 // in the original. TODO: speed this up!
177 for (vit = graph->v_begin (); vit != graph->v_end (); ++vit)
178 for (vit2 = vit + 1; vit2 != graph->v_end (); ++vit2)
179 graph->add (new Edge (*vit, *vit2));
180 for (eit = orig->e_begin (); eit != orig->e_end (); ++eit) {
181 Vertex *v1, *v2;
182 v1 = graph->find ((*eit)->v->label);
183 v2 = graph->find ((*eit)->w->label);
184 graph->remove (graph->find (v1, v2));
185 }
186
187 delete orig;
188 canvas->redraw ();
189 }
190
cb_Graph_LineGraph(wxCommandEvent & event)191 void GTFrame::cb_Graph_LineGraph (wxCommandEvent &event)
192 {
193 undoableAction (_("Line Graph"));
194 Graph *orig = graph;
195 graph = orig->line_graph ();
196 delete orig;
197 canvas->redraw ();
198 }
199
cb_Graph_Subgraph(wxCommandEvent & event)200 void GTFrame::cb_Graph_Subgraph (wxCommandEvent &event)
201 {
202 Graph *orig = graph;
203 Graph::v_const_iterator vit;
204
205 if (!graph->v_selected_head) {
206 msg (_("Subgraph"), _("At least one vertex must be selected "
207 "to induce a subgraph."));
208 return;
209 }
210
211 undoableAction (_("Induced subgraph"));
212
213 // Mark selection
214 for (vit = graph->v_begin (); vit != graph->v_end (); ++vit) {
215 Vertex *v = *vit;
216 v->mark = v->selected ? 1 : 0;
217 }
218
219 graph = orig->subgraph_marked ();
220 delete orig;
221 canvas->redraw ();
222 }
223
cb_Graph_Find_ShortestPath(wxCommandEvent & event)224 void GTFrame::cb_Graph_Find_ShortestPath (wxCommandEvent &event)
225 {
226 Vertex *v1, *v2, *walk;
227 Graph::e_const_iterator eit;
228 long tot;
229
230 v2 = graph->v_selected_head;
231 if (!v2 || !v2->next || v2->next->next) {
232 msg (_("Shortest Path"), _("Exactly two vertices must be "
233 "selected to find a shortest path."));
234 return;
235 }
236 v1 = v2->next;
237
238 pushStatus (_("Finding shortest path..."));
239
240 graph->mark_shortest_path (v1, v2);
241
242 // Select shortest path
243 tot = v2->mark;
244 graph->unselect_all ();
245 graph->select (v2);
246 walk = v2;
247 while (walk != v1) {
248 Edge *e = 0;
249 Vertex *alt = 0;
250
251 for (eit = walk->e_begin (); eit != walk->e_end (); ++eit) {
252 e = *eit;
253 if (e->selected)
254 continue;
255 alt = walk->opposite (e);
256 if (walk->mark == (alt->mark + e->weight))
257 break;
258 }
259 if (eit == walk->e_end ())
260 break; // Uh, oh!
261 graph->select (e);
262 graph->select (alt);
263 walk = alt;
264 }
265
266 if (tot < 0) {
267 // If there is no path at all,
268 // leave original vertices selected
269 graph->unselect_all ();
270 graph->select (v1);
271 graph->select (v2);
272 }
273
274 canvas->redraw ();
275
276 if (tot >= 0) {
277 wxString str = wxString::Format (_("Shortest path is %i."), tot);
278 msg (_("Shortest Path"), str);
279 } else
280 msg (_("Shortest Path"), _("No path found."));
281
282 popStatus ();
283 }
284
cb_Graph_Find_BFS(wxCommandEvent & event)285 void GTFrame::cb_Graph_Find_BFS (wxCommandEvent &event)
286 {
287 Vertex *v;
288
289 v = graph->v_selected_head;
290 if (!v || v->next) {
291 msg (_("Breadth-First Search"), _("Exactly one vertex "
292 "must be selected to perform a "
293 "Breadth-First Search."));
294 return;
295 }
296
297 pushStatus (_("Performing BFS..."));
298
299 wxString m (wxT("BFS:\n\n"));
300 graph->bfs (v, m);
301
302 msg (_("Breadth-First Search"), m);
303
304 popStatus ();
305 }
306
cb_Graph_Find_DFS(wxCommandEvent & event)307 void GTFrame::cb_Graph_Find_DFS (wxCommandEvent &event)
308 {
309 Vertex *v;
310
311 v = graph->v_selected_head;
312 if (!v || v->next) {
313 msg (_("Depth-First Search"), _("Exactly one vertex must "
314 "be selected to perform a Depth-First Search."));
315 return;
316 }
317
318 pushStatus (_("Performing DFS..."));
319
320 wxString m (wxT("DFS:\n\n"));
321 graph->dfs (v, m);
322
323 msg (_("Depth-First Search"), m);
324
325 popStatus ();
326 }
327
cb_Graph_Find_MST(wxCommandEvent & event)328 void GTFrame::cb_Graph_Find_MST (wxCommandEvent &event)
329 {
330 std::set<Edge *> spanning_tree;
331 std::set<Edge *>::const_iterator it;
332
333 pushStatus (_("Finding Minimum Spanning Tree..."));
334
335 graph->minimum_spanning_tree (spanning_tree);
336 graph->unselect_all ();
337 for (it = spanning_tree.begin (); it != spanning_tree.end (); ++it) {
338 graph->select (*it);
339 graph->select ((*it)->v);
340 graph->select ((*it)->w);
341 }
342 canvas->redraw ();
343
344 popStatus ();
345 }
346
cb_Graph_Find_MaxFlow(wxCommandEvent & event)347 void GTFrame::cb_Graph_Find_MaxFlow (wxCommandEvent &event)
348 {
349 Vertex *v1, *v2;
350
351 v2 = graph->v_selected_head;
352 if (!v2 || !v2->next || v2->next->next) {
353 msg (_("Maximum Flow"), _("Exactly two vertices must be "
354 "selected to find a maximum flow."));
355 return;
356 }
357 v1 = v2->next;
358
359 pushStatus (_("Finding Maximum Flow..."));
360
361 int flow = graph->ford_fulkerson (v1, v2);
362 #if 0
363 graph->unselect_all ();
364 for (it = spanning_tree.begin (); it != spanning_tree.end (); ++it) {
365 graph->select (*it);
366 graph->select ((*it)->v);
367 graph->select ((*it)->w);
368 }
369 #endif
370 wxString str = wxString::Format (_("Maximum flow is %i."), flow);
371 canvas->redraw ();
372
373 msg (_("Maximum Flow"), str);
374
375 popStatus ();
376 }
377
cb_Graph_Properties_Connectivity(wxCommandEvent & event)378 void GTFrame::cb_Graph_Properties_Connectivity (wxCommandEvent &event)
379 {
380 Graph::e_const_iterator eit;
381 Graph::v_const_iterator vit;
382 bool undir, conn, strong_conn = false;
383
384 pushStatus (_("Testing connectivity..."));
385
386 undir = graph->is_undirected ();
387
388 conn = graph->is_connected ();
389 if (conn && !undir)
390 strong_conn = graph->is_strongly_connected ();
391 if (conn) {
392 if (undir)
393 msg (_("Connectivity"), _("Graph is connected."));
394 else if (!strong_conn)
395 msg (_("Connectivity"), _("Graph is weakly connected."));
396 else
397 msg (_("Connectivity"), _("Graph is strongly connected."));
398 } else {
399 // Select marked vertices and edges
400 graph->unselect_all ();
401 for (eit = graph->e_begin (); eit != graph->e_end (); ++eit)
402 if ((*eit)->mark)
403 graph->select (*eit);
404 for (vit = graph->v_begin (); vit != graph->v_end (); ++vit)
405 if ((*vit)->mark)
406 graph->select (*vit);
407 canvas->redraw ();
408
409 msg (_("Connectivity"), _("Graph is not connected."));
410 }
411
412 popStatus ();
413 }
414
cb_Graph_Properties_Eulericity(wxCommandEvent & event)415 void GTFrame::cb_Graph_Properties_Eulericity (wxCommandEvent &event)
416 {
417 bool euler, semi;
418
419 pushStatus (_("Determining Eulericity..."));
420
421 wxString tour (wxT("\n("));
422 graph->eulericity (euler, semi, tour);
423 tour += wxT(")");
424
425 if (euler)
426 msg (_("Eulericity"), _("Graph is Eulerian.") + tour);
427 else if (semi)
428 msg (_("Eulericity"), _("Graph is Semi-Eulerian.") + tour);
429 else
430 msg (_("Eulericity"), _("Graph is neither Eulerian nor "
431 "Semi-Eulerian."));
432
433 popStatus ();
434 }
435
cb_Graph_Statistics_AdjacencyMatrix(wxCommandEvent & event)436 void GTFrame::cb_Graph_Statistics_AdjacencyMatrix (wxCommandEvent &event)
437 {
438 MatrixDialog md (this, _("Adjacency Matrix"),
439 graph->adjacency_matrix (), *graph);
440 md.ShowModal ();
441 }
442
cb_Graph_Statistics_DegreeSequence(wxCommandEvent & event)443 void GTFrame::cb_Graph_Statistics_DegreeSequence (wxCommandEvent &event)
444 {
445 std::vector<int> seq;
446 std::vector<int>::iterator it1, it2;
447 Graph::v_const_iterator vit;
448
449 if (graph->order () < 1) {
450 wxString str = _("Degree Sequence");
451 str += wxT(":\n\n");
452 str += _("(none)");
453 msg (_("Degree Sequence"), str);
454 return;
455 }
456
457 for (vit = graph->v_begin (); vit != graph->v_end (); ++vit)
458 seq.push_back ((*vit)->degree ());
459
460 // boring bubble sort
461 for (it1 = seq.begin (); (it1 + 1) != seq.end (); ++it1)
462 for (it2 = it1 + 1; it2 != seq.end (); ++it2) {
463 if (*it1 < *it2) {
464 int tmp = *it1;
465 *it1 = *it2;
466 *it2 = tmp;
467 }
468 }
469
470 wxString str = _("Degree Sequence");
471 str += wxT(":\n\n");
472
473 for (it1 = seq.begin (); it1 != seq.end (); ++it1) {
474 if (it1 == seq.begin ())
475 str += wxString::Format (wxT("%i"), *it1);
476 else
477 str += wxString::Format (wxT(", %i"), *it1);
478 }
479
480 msg (_("Degree Sequence"), str);
481 }
482
cb_Graph_Statistics_Diameter(wxCommandEvent & event)483 void GTFrame::cb_Graph_Statistics_Diameter (wxCommandEvent &event)
484 {
485 pushStatus (_("Determining diameter..."));
486
487 int diam = graph->diameter (true);
488 wxString str = wxString::Format (wxT("diam(G) = %i"), diam);
489 canvas->redraw ();
490
491 msg (_("Diameter"), str);
492
493 popStatus ();
494 }
495
cb_Graph_Statistics_Radius(wxCommandEvent & event)496 void GTFrame::cb_Graph_Statistics_Radius (wxCommandEvent &event)
497 {
498 pushStatus (_("Determining radius..."));
499
500 int rad = graph->radius (true);
501 wxString str = wxString::Format (wxT("rad(G) = %i"), rad);
502 canvas->redraw ();
503
504 msg (_("Radius"), str);
505
506 popStatus ();
507 }
508
cb_Graph_Statistics_ChromaticNumber(wxCommandEvent & event)509 void GTFrame::cb_Graph_Statistics_ChromaticNumber (wxCommandEvent &event)
510 {
511 pushStatus (_("Computing chromatic number..."));
512
513 int chi = graph->chromatic_number ();
514
515 graph->unselect_all ();
516 while (chi >= 2) { // WARNING: Abuse of loop construct!
517 if (!graph->try_colouring (chi))
518 break;
519 Graph::v_iterator vit;
520 for (vit = graph->v_begin (); vit != graph->v_end (); ++vit) {
521 graph->select (*vit);
522 (*vit)->selection_colour = (*vit)->mark;
523 }
524 break;
525 }
526 // TODO: mention something if we failed to colour properly!
527
528 canvas->redraw ();
529 wxString str = wxString::Format(wxT("chi(G) = %i"), chi);
530 msg (_("Chromatic Number"), str);
531
532 setProgress (-1);
533 popStatus ();
534 }
535
cb_Graph_Statistics_ChromaticIndex(wxCommandEvent & event)536 void GTFrame::cb_Graph_Statistics_ChromaticIndex (wxCommandEvent &event)
537 {
538 pushStatus (_("Computing chromatic index..."));
539
540 Graph *lg = graph->line_graph ();
541 int chi = lg->chromatic_number ();
542
543 graph->unselect_all ();
544 while (chi >= 2) { // WARNING: Abuse of loop construct!
545 if (!lg->try_colouring (chi))
546 break;
547 Graph::e_iterator eit;
548 for (eit = graph->e_begin (); eit != graph->e_end (); ++eit) {
549 Vertex *v = (Vertex *) (*eit)->mark;
550 graph->select (*eit);
551 (*eit)->selection_colour = v->mark;
552 }
553 break;
554 }
555 // TODO: mention something if we failed to colour properly!
556 delete lg;
557
558 canvas->redraw ();
559 wxString str = wxString::Format (wxT("chi'(G) = %i"), chi);
560 msg (_("Chromatic Index"), str);
561
562 setProgress (-1);
563 popStatus ();
564 }
565
cb_Graph_Statistics_ChromaticPolynomial(wxCommandEvent & event)566 void GTFrame::cb_Graph_Statistics_ChromaticPolynomial (wxCommandEvent &event)
567 {
568 wxString m = _("Chromatic Polynomial");
569
570 pushStatus (_("Computing chromatic polynomial..."));
571
572 Polynomial p = graph->chromatic_polynomial ();
573
574 m << wxT(":\n\n") << p.str ();
575 msg (_("Chromatic Polynomial"), m);
576
577 setProgress (-1);
578 popStatus ();
579 }
580
cb_Prefab_Complete(wxCommandEvent & event)581 void GTFrame::cb_Prefab_Complete (wxCommandEvent &event)
582 {
583 pushStatus (_("Prefab..."));
584 int param = wxGetNumberFromUser (wxT(""), _("Complete:"),
585 _("Prefab Parameter"), 5, 1, 20, this);
586 if (param < 0) {
587 popStatus ();
588 return;
589 }
590
591 undoableAction (_("Make prefab"));
592 delete graph;
593 graph = Factory::K (param);
594 canvas->redraw ();
595 popStatus ();
596 }
597
cb_Prefab_CompleteBipartite(wxCommandEvent & event)598 void GTFrame::cb_Prefab_CompleteBipartite (wxCommandEvent &event)
599 {
600 pushStatus (_("Prefab..."));
601 ParamDialogIntInt dlg (this, _("Prefab Parameter"),
602 _("Complete Bipartite:"), 3, 1, 20, 3, 1, 20);
603 if (dlg.ShowModal () == wxID_CANCEL) {
604 popStatus ();
605 return;
606 }
607
608 undoableAction (_("Make prefab"));
609 delete graph;
610 graph = Factory::K (dlg.GetValue1 (), dlg.GetValue2 ());
611 canvas->redraw ();
612 popStatus ();
613 }
614
cb_Prefab_Cycle(wxCommandEvent & event)615 void GTFrame::cb_Prefab_Cycle (wxCommandEvent &event)
616 {
617 pushStatus (_("Prefab..."));
618 int param = wxGetNumberFromUser (wxT(""), _("Cycle:"),
619 _("Prefab Parameter"), 5, 1, 20, this);
620 if (param < 0) {
621 popStatus ();
622 return;
623 }
624
625 undoableAction (_("Make prefab"));
626 delete graph;
627 graph = Factory::C (param);
628 canvas->redraw ();
629 popStatus ();
630 }
631
cb_Prefab_Gear(wxCommandEvent & event)632 void GTFrame::cb_Prefab_Gear (wxCommandEvent &event)
633 {
634 pushStatus (_("Prefab..."));
635 int param = wxGetNumberFromUser (wxT(""), _("Gear:"),
636 _("Prefab Parameter"), 5, 3, 20, this);
637 if (param < 0) {
638 popStatus ();
639 return;
640 }
641
642 undoableAction (_("Make prefab"));
643 delete graph;
644 graph = Factory::G (param);
645 canvas->redraw ();
646 popStatus ();
647 }
648
cb_Prefab_Hanoi(wxCommandEvent & event)649 void GTFrame::cb_Prefab_Hanoi (wxCommandEvent &event)
650 {
651 pushStatus (_("Prefab..."));
652 int param = wxGetNumberFromUser (wxT(""), _("Hanoi:"),
653 _("Prefab Parameter"), 3, 1, 20, this);
654 if (param < 0) {
655 popStatus ();
656 return;
657 }
658
659 undoableAction (_("Make prefab"));
660 delete graph;
661 graph = Factory::H (param);
662 canvas->redraw ();
663 popStatus ();
664 }
665
cb_Prefab_Ladder(wxCommandEvent & event)666 void GTFrame::cb_Prefab_Ladder (wxCommandEvent &event)
667 {
668 pushStatus (_("Prefab..."));
669 int param = wxGetNumberFromUser (wxT(""), _("Ladder:"),
670 _("Prefab Parameter"), 4, 1, 20, this);
671 if (param < 0) {
672 popStatus ();
673 return;
674 }
675
676 undoableAction (_("Make prefab"));
677 delete graph;
678 graph = Factory::L (param);
679 canvas->redraw ();
680 popStatus ();
681 }
682
cb_Prefab_Lattice(wxCommandEvent & event)683 void GTFrame::cb_Prefab_Lattice (wxCommandEvent &event)
684 {
685 pushStatus (_("Prefab..."));
686 ParamDialogIntInt dlg (this, _("Prefab Parameter"),
687 _("Lattice:"), 4, 1, 20, 4, 1, 20);
688 if (dlg.ShowModal () == wxID_CANCEL) {
689 popStatus ();
690 return;
691 }
692
693 undoableAction (_("Make prefab"));
694 delete graph;
695 graph = Factory::Lattice (dlg.GetValue1 (), dlg.GetValue2 ());
696 canvas->redraw ();
697 popStatus ();
698 }
699
cb_Prefab_Null(wxCommandEvent & event)700 void GTFrame::cb_Prefab_Null (wxCommandEvent &event)
701 {
702 pushStatus (_("Prefab..."));
703 int param = wxGetNumberFromUser (wxT(""), _("Null:"),
704 _("Prefab Parameter"), 3, 1, 20, this);
705 if (param < 0) {
706 popStatus ();
707 return;
708 }
709
710 undoableAction (_("Make prefab"));
711 delete graph;
712 graph = Factory::N (param);
713 canvas->redraw ();
714 popStatus ();
715 }
716
cb_Prefab_Star(wxCommandEvent & event)717 void GTFrame::cb_Prefab_Star (wxCommandEvent &event)
718 {
719 pushStatus (_("Prefab..."));
720 int param = wxGetNumberFromUser (wxT(""), _("Star:"),
721 _("Prefab Parameter"), 5, 1, 20, this);
722 if (param < 0) {
723 popStatus ();
724 return;
725 }
726
727 undoableAction (_("Make prefab"));
728 delete graph;
729 graph = Factory::S (param);
730 canvas->redraw ();
731 popStatus ();
732 }
733
cb_Prefab_Wheel(wxCommandEvent & event)734 void GTFrame::cb_Prefab_Wheel (wxCommandEvent &event)
735 {
736 pushStatus (_("Prefab..."));
737 int param = wxGetNumberFromUser (wxT(""), _("Wheel:"),
738 _("Prefab Parameter"), 5, 1, 20, this);
739 if (param < 0) {
740 popStatus ();
741 return;
742 }
743
744 undoableAction (_("Make prefab"));
745 delete graph;
746 graph = Factory::W (param);
747 canvas->redraw ();
748 popStatus ();
749 }
750
cb_Prefab_Petersen(wxCommandEvent & event)751 void GTFrame::cb_Prefab_Petersen (wxCommandEvent &event)
752 {
753 undoableAction (_("Make prefab"));
754 delete graph;
755 graph = Factory::Petersen ();
756 canvas->redraw ();
757 }
758
cb_Prefab_Platonic_Tetrahedral(wxCommandEvent & event)759 void GTFrame::cb_Prefab_Platonic_Tetrahedral (wxCommandEvent &event)
760 {
761 undoableAction (_("Make prefab"));
762 delete graph;
763 graph = Factory::Tetrahedral ();
764 canvas->redraw ();
765 }
766
cb_Prefab_Platonic_Cubical(wxCommandEvent & event)767 void GTFrame::cb_Prefab_Platonic_Cubical (wxCommandEvent &event)
768 {
769 undoableAction (_("Make prefab"));
770 delete graph;
771 graph = Factory::Cubical ();
772 canvas->redraw ();
773 }
774
cb_Prefab_Platonic_Octahedral(wxCommandEvent & event)775 void GTFrame::cb_Prefab_Platonic_Octahedral (wxCommandEvent &event)
776 {
777 undoableAction (_("Make prefab"));
778 delete graph;
779 graph = Factory::Octahedral ();
780 canvas->redraw ();
781 }
782
cb_Prefab_Platonic_Dodecahedral(wxCommandEvent & event)783 void GTFrame::cb_Prefab_Platonic_Dodecahedral (wxCommandEvent &event)
784 {
785 undoableAction (_("Make prefab"));
786 delete graph;
787 graph = Factory::Dodecahedral ();
788 canvas->redraw ();
789 }
790
cb_Prefab_Platonic_Icosahedral(wxCommandEvent & event)791 void GTFrame::cb_Prefab_Platonic_Icosahedral (wxCommandEvent &event)
792 {
793 undoableAction (_("Make prefab"));
794 delete graph;
795 graph = Factory::Icosahedral ();
796 canvas->redraw ();
797 }
798
cb_Help_About(wxCommandEvent & event)799 void GTFrame::cb_Help_About (wxCommandEvent &event)
800 {
801 pushStatus (_("About GraphThing"));
802 AboutBox dlg (this);
803 dlg.CentreOnParent ();
804 dlg.ShowModal ();
805
806 popStatus ();
807 }
808
cb_Change_Mode(wxCommandEvent & event)809 void GTFrame::cb_Change_Mode (wxCommandEvent &event)
810 {
811 popStatus ();
812
813 in_vertex_mode = (event.GetId() == ID_TOOL_VERTEXMODE);
814 canvas->setVertexMode (in_vertex_mode);
815
816 if (in_vertex_mode)
817 pushStatus (_("Ready (Vertex Mode)."));
818 else
819 pushStatus (_("Ready (Edge Mode)."));
820
821
822 // TODO: depress the correct buttons (mainly for keyboard mode switches)
823 //Gtk::Toolbar_Helpers::ToolList &tl = toolbar->tools ();
824 //Gtk::Toolbar_Helpers::Tool *tool = tl[1];
825 //Gtk::Widget *widget = tool->get_widget (),
826 // *content = tool->get_content ();
827 //std::cerr << Gtk::RadioButton::isA (widget) << "\n";
828 //std::cerr << Gtk::Pixmap::isA (content) << "\n";
829 }
830