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