1 // Gmsh - Copyright (C) 1997-2012 C. Geuzaine, J.-F. Remacle
2 //
3 // See the LICENSE.txt file for license information. Please report all
4 // bugs and problems to <gmsh@geuz.org>.
5 
6 #include "GmshConfig.h"
7 #if !defined(HAVE_NO_STDINT_H)
8 #include <stdint.h>
9 #elif defined(HAVE_NO_INTPTR_T)
10 typedef unsigned long intptr_t;
11 #endif
12 #include <sstream>
13 #include <string.h>
14 #include <FL/Fl.H>
15 #include <FL/Fl_Tooltip.H>
16 #include <FL/Fl_Shared_Image.H>
17 #include <FL/Fl_File_Icon.H>
18 #include <FL/x.H>
19 #include <FL/gl.h>
20 #include "FlGui.h"
21 #include "graphicWindow.h"
22 #include "menuWindow.h"
23 #include "optionWindow.h"
24 #include "fieldWindow.h"
25 #include "pluginWindow.h"
26 #include "statisticsWindow.h"
27 #include "visibilityWindow.h"
28 #include "clippingWindow.h"
29 #include "manipWindow.h"
30 #include "contextWindow.h"
31 #include "onelabWindow.h"
32 #include "aboutWindow.h"
33 #include "colorbarWindow.h"
34 #include "fileDialogs.h"
35 #include "GmshDefines.h"
36 #include "GmshMessage.h"
37 #include "GModel.h"
38 #include "MElement.h"
39 #include "PView.h"
40 #include "Field.h"
41 #include "Plugin.h"
42 #include "PluginManager.h"
43 #include "OpenFile.h"
44 #include "Win32Icon.h"
45 #include "Options.h"
46 #include "CommandLine.h"
47 #include "Context.h"
48 #include "StringUtils.h"
49 #include "Generator.h"
50 #include "gl2ps.h"
51 
52 // check (now!) if there are any pending events, and process them
check()53 void FlGui::check(){ Fl::check(); }
54 
55 // wait (possibly indefinitely) for any events, then process them
wait()56 void FlGui::wait(){ Fl::wait(); }
57 
58 // wait (at most time seconds) for any events, then process them
wait(double time)59 void FlGui::wait(double time){ Fl::wait(time); }
60 
61 class drawContextFltk : public drawContextGlobal{
62  public:
draw()63   void draw()
64   {
65     if(!FlGui::available()) return;
66     for(unsigned int i = 0; i < FlGui::instance()->graph.size(); i++){
67       for(unsigned int j = 0; j < FlGui::instance()->graph[i]->gl.size(); j++){
68         FlGui::instance()->graph[i]->gl[j]->make_current();
69         FlGui::instance()->graph[i]->gl[j]->redraw();
70 	// to initialize the camera distance from model
71 	drawContext * ctx = FlGui::instance()->graph[i]->gl[j]->getDrawContext();
72 	ctx->camera.update();
73       }
74     }
75     FlGui::instance()->check();
76   }
drawCurrentOpenglWindow(bool make_current)77   void drawCurrentOpenglWindow(bool make_current)
78   {
79     if(!FlGui::available()) return;
80     openglWindow *gl = FlGui::instance()->getCurrentOpenglWindow();
81     if(make_current) gl->make_current();
82     gl->redraw();
83     glFlush();
84     FlGui::instance()->check();
85   }
getFontIndex(const char * fontname)86   int getFontIndex(const char *fontname)
87   {
88     if(fontname){
89       for(int i = 0; i < NUM_FONTS; i++)
90         if(!strcmp(menu_font_names[i].label(), fontname))
91           return i;
92     }
93     Msg::Error("Unknown font \"%s\" (using \"Helvetica\" instead)", fontname);
94     Msg::Info("Available fonts:");
95     for(int i = 0; i < NUM_FONTS; i++)
96       Msg::Info("  \"%s\"", menu_font_names[i].label());
97     return 4;
98   }
getFontEnum(int index)99   int getFontEnum(int index)
100   {
101     if(index >= 0 && index < NUM_FONTS)
102       return (intptr_t)menu_font_names[index].user_data();
103     return FL_HELVETICA;
104   }
getFontName(int index)105   const char *getFontName(int index)
106   {
107     if(index >= 0 && index < NUM_FONTS)
108       return menu_font_names[index].label();
109     return "Helvetica";
110   }
getFontAlign(const char * alignstr)111   int getFontAlign(const char *alignstr)
112   {
113     if(alignstr){
114       if(!strcmp(alignstr, "BottomLeft") || !strcmp(alignstr, "Left") ||
115          !strcmp(alignstr, "left"))
116         return 0;
117       else if(!strcmp(alignstr, "BottomCenter") || !strcmp(alignstr, "Center") ||
118               !strcmp(alignstr, "center"))
119         return 1;
120       else if(!strcmp(alignstr, "BottomRight") || !strcmp(alignstr, "Right") ||
121               !strcmp(alignstr, "right"))
122         return 2;
123       else if(!strcmp(alignstr, "TopLeft"))
124         return 3;
125       else if(!strcmp(alignstr, "TopCenter"))
126         return 4;
127       else if(!strcmp(alignstr, "TopRight"))
128         return 5;
129       else if(!strcmp(alignstr, "CenterLeft"))
130         return 6;
131       else if(!strcmp(alignstr, "CenterCenter"))
132         return 7;
133       else if(!strcmp(alignstr, "CenterRight"))
134         return 8;
135     }
136     Msg::Error("Unknown font alignment \"%s\" (using \"Left\" instead)", alignstr);
137     Msg::Info("Available font alignments:");
138     Msg::Info("  \"Left\" (or \"BottomLeft\")");
139     Msg::Info("  \"Center\" (or \"BottomCenter\")");
140     Msg::Info("  \"Right\" (or \"BottomRight\")");
141     Msg::Info("  \"TopLeft\"");
142     Msg::Info("  \"TopCenter\"");
143     Msg::Info("  \"TopRight\"");
144     Msg::Info("  \"CenterLeft\"");
145     Msg::Info("  \"CenterCenter\"");
146     Msg::Info("  \"CenterRight\"");
147     return 0;
148   }
getFontSize()149   int getFontSize()
150   {
151     if(CTX::instance()->fontSize > 0){
152       return CTX::instance()->fontSize;
153     }
154     else{
155       int w = Fl::w();
156       if(w <= 1024)      return 11;
157       else if(w <= 1280) return 12;
158       else if(w <= 1680) return 13;
159       else if(w <= 1920) return 14;
160       else               return 15;
161     }
162   }
setFont(int fontid,int fontsize)163   void setFont(int fontid, int fontsize)
164   {
165     gl_font(fontid, fontsize);
166   }
getStringWidth(const char * str)167   double getStringWidth(const char *str)
168   {
169     return gl_width(str);
170   }
getStringHeight()171   int getStringHeight()
172   {
173     return gl_height();
174   }
getStringDescent()175   int getStringDescent()
176   {
177     return gl_descent();
178   }
drawString(const char * str)179   void drawString(const char *str)
180   {
181     gl_draw(str);
182   }
resetFontTextures()183   void resetFontTextures()
184   {
185 #if defined(__APPLE__) && (FL_MAJOR_VERSION == 1) && (FL_MINOR_VERSION == 3)
186     gl_texture_pile_height(1); // force font texture recomputation
187 #endif
188   }
189 };
190 
globalShortcut(int event)191 static int globalShortcut(int event)
192 {
193   if(!FlGui::available()) return 0;
194   return FlGui::instance()->testGlobalShortcuts(event);
195 }
196 
FlGui(int argc,char ** argv)197 FlGui::FlGui(int argc, char **argv) : _openedThroughMacFinder(false)
198 {
199   // set X display
200   if(CTX::instance()->display.size())
201     Fl::display(CTX::instance()->display.c_str());
202 
203 #if 0 // dark scheme... not bad, but needs work
204   Fl::background(60, 60, 60);
205   Fl::background2(120, 120, 120);
206   Fl::foreground(200, 200, 200);
207 #endif
208 
209   // add global shortcuts
210   Fl::add_handler(globalShortcut);
211 
212   // set global fltk-dependent drawing functions
213   drawContext::setGlobal(new drawContextFltk);
214 
215   // set default font size
216   FL_NORMAL_SIZE = drawContext::global()->getFontSize();
217 
218   // handle themes and tooltip font size
219   if(CTX::instance()->guiTheme.size())
220     Fl::scheme(CTX::instance()->guiTheme.c_str());
221   Fl_Tooltip::size(FL_NORMAL_SIZE);
222 
223   // register image formats not in core fltk library (jpeg/png)
224   fl_register_images();
225 
226   // load default system icons (for file browser)
227   Fl_File_Icon::load_system_icons();
228 
229   // add callback to respond to Mac Finder
230 #if defined(__APPLE__)
231   fl_open_callback(OpenProjectMacFinder);
232 #if (FL_MAJOR_VERSION == 1) && (FL_MINOR_VERSION == 3)
233   fl_mac_set_about(help_about_cb, 0);
234 #endif
235 #endif
236 
237   // all the windows are contructed (even if some are not displayed)
238   // since the shortcuts should be valid even for hidden windows, and
239   // we don't want to test for widget existence every time
240   menu = new menuWindow();
241   graph.push_back(new graphicWindow(true, CTX::instance()->numTiles));
242 
243 #if defined(WIN32)
244   graph[0]->win->icon
245     ((const char*)LoadImage(fl_display, MAKEINTRESOURCE(IDI_ICON),
246                             IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR));
247 #elif defined(__APPLE__)
248   // nothing to do here
249 #else
250   fl_open_display();
251   static char gmsh32x32[] = {
252     0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x40, 0x03, 0x00,
253     0x00, 0x40, 0x03, 0x00, 0x00, 0x20, 0x07, 0x00, 0x00, 0x20, 0x07, 0x00,
254     0x00, 0x10, 0x0f, 0x00, 0x00, 0x10, 0x0f, 0x00, 0x00, 0x08, 0x1f, 0x00,
255     0x00, 0x08, 0x1f, 0x00, 0x00, 0x04, 0x3f, 0x00, 0x00, 0x04, 0x3f, 0x00,
256     0x00, 0x02, 0x7f, 0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x01, 0xff, 0x00,
257     0x00, 0x01, 0xff, 0x00, 0x80, 0x00, 0xff, 0x01, 0x80, 0x00, 0xff, 0x01,
258     0x40, 0x00, 0xff, 0x03, 0x40, 0x00, 0xff, 0x03, 0x20, 0x00, 0xff, 0x07,
259     0x20, 0x00, 0xff, 0x07, 0x10, 0x00, 0xff, 0x0f, 0x10, 0x00, 0xff, 0x0f,
260     0x08, 0x00, 0xff, 0x1f, 0x08, 0x00, 0xff, 0x1f, 0x04, 0x40, 0xfd, 0x3f,
261     0x04, 0xa8, 0xea, 0x3f, 0x02, 0x55, 0x55, 0x7f, 0xa2, 0xaa, 0xaa, 0x7a,
262     0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00};
263   graph[0]->win->icon
264     ((const char*)XCreateBitmapFromData(fl_display, DefaultRootWindow(fl_display),
265                                         gmsh32x32, 32, 32));
266   menu->win->icon
267     ((const char*)XCreateBitmapFromData(fl_display, DefaultRootWindow(fl_display),
268                                         gmsh32x32, 32, 32));
269 #endif
270 
271   // open graphic window first for correct non-modal behaviour on
272   // Win32
273   graph[0]->win->show(1, argv);
274   menu->win->show();
275 
276   // graphic window should have the initial focus (so we can
277   // e.g. directly loop through time steps with the keyboard)
278   //graph[0]->gl[0]->take_focus();
279   Fl::focus(graph[0]->gl[0]);
280 
281   // create additional graphic windows
282   for(int i = 1; i < CTX::instance()->numWindows; i++){
283     graphicWindow *g = new graphicWindow(false, CTX::instance()->numTiles);
284     g->win->resize(graph.back()->win->x() + 10, graph.back()->win->y() + 10,
285                    graph.back()->win->w(), graph.back()->win->h());
286     g->win->show();
287     graph.push_back(g);
288   }
289 
290   options = new optionWindow(CTX::instance()->deltaFontSize);
291   fields = new fieldWindow(CTX::instance()->deltaFontSize);
292   plugins = new pluginWindow(CTX::instance()->deltaFontSize);
293   stats = new statisticsWindow(CTX::instance()->deltaFontSize);
294   visibility = new visibilityWindow(CTX::instance()->deltaFontSize);
295   clipping = new clippingWindow(CTX::instance()->deltaFontSize);
296   manip = new manipWindow(CTX::instance()->deltaFontSize);
297   geoContext = new geometryContextWindow(CTX::instance()->deltaFontSize);
298   meshContext = new meshContextWindow(CTX::instance()->deltaFontSize);
299   about = new aboutWindow();
300 #if defined(HAVE_ONELAB) && (FL_MAJOR_VERSION == 1) && (FL_MINOR_VERSION == 3)
301   onelab = new onelabWindow(CTX::instance()->deltaFontSize);
302 #endif
303 
304   // init solver plugin stuff
305   callForSolverPlugin(-1);
306 
307   // draw
308   for(unsigned int i = 0; i < graph.size(); i++)
309     for(unsigned int j = 0; j < graph[i]->gl.size(); j++)
310       graph[i]->gl[j]->redraw();
311 
312   menu->setContext(menu_geometry, 0);
313 }
314 
315 FlGui *FlGui::_instance = 0;
316 
instance(int argc,char ** argv)317 FlGui *FlGui::instance(int argc, char **argv)
318 {
319   if(!_instance){
320     _instance = new FlGui(argc, argv);
321     // set all options in the new GUI
322     InitOptionsGUI(0);
323     // say welcome!
324     Msg::StatusBar(1, false, "Geometry");
325     Msg::StatusBar(2, false, "Gmsh %s", GetGmshVersion());
326     // log the following for bug reports
327     Msg::Info("-------------------------------------------------------");
328     Msg::Info("Gmsh version   : %s", GetGmshVersion());
329     Msg::Info("Build OS       : %s", GetGmshBuildOS());
330     Msg::Info("Build options  :%s", GetGmshBuildOptions());
331     Msg::Info("Build date     : %s", GetGmshBuildDate());
332     Msg::Info("Build host     : %s", GetGmshBuildHost());
333     Msg::Info("Packager       : %s", GetGmshPackager());
334     Msg::Info("Home directory : %s", CTX::instance()->homeDir.c_str());
335     Msg::Info("Launch date    : %s", Msg::GetLaunchDate().c_str());
336     Msg::Info("Command line   : %s", Msg::GetCommandLineArgs().c_str());
337     Msg::Info("-------------------------------------------------------");
338   }
339   return _instance;
340 }
341 
run()342 int FlGui::run()
343 {
344   // bounding box computation necessary if we run the gui without
345   // merging any files (e.g. if we build the geometry with python and
346   // create the gui from the python script)
347   SetBoundingBox();
348 
349   // draw the scene
350   drawContext::global()->draw();
351 
352   return Fl::run();
353 }
354 
testGlobalShortcuts(int event)355 int FlGui::testGlobalShortcuts(int event)
356 {
357   // we only handle shortcuts here
358   if(event != FL_SHORTCUT) return 0;
359 
360   int status = 0;
361 
362   if(Fl::test_shortcut('0')) {
363     // FIXME: here we should also reset all onelab variables that depend on Gmsh
364     geometry_reload_cb(0, 0);
365     mod_geometry_cb(0, 0);
366     status = 1;
367   }
368   else if(Fl::test_shortcut('1') || Fl::test_shortcut(FL_F + 1)) {
369     mesh_1d_cb(0, 0);
370     mod_mesh_cb(0, 0);
371     status = 1;
372   }
373   else if(Fl::test_shortcut('2') || Fl::test_shortcut(FL_F + 2)) {
374     mesh_2d_cb(0, 0);
375     mod_mesh_cb(0, 0);
376     status = 1;
377   }
378   else if(Fl::test_shortcut('3') || Fl::test_shortcut(FL_F + 3)) {
379     mesh_3d_cb(0, 0);
380     mod_mesh_cb(0, 0);
381     status = 1;
382   }
383   // FIXME TEST
384   else if(Fl::test_shortcut('4') || Fl::test_shortcut(FL_F + 4)) {
385     RecombineMesh(GModel::current());
386     status = 2;
387   }
388   else if(Fl::test_shortcut(FL_CTRL + 'q') || Fl::test_shortcut(FL_META + 'q')){
389     // only necessary when using the system menu bar, but hey, it
390     // cannot hurt...
391     file_quit_cb(0, 0);
392     status = 1;
393   }
394   else if(Fl::test_shortcut('g')) {
395     mod_geometry_cb(0, 0);
396     Fl::focus(menu->scroll);
397     status = 1;
398   }
399   else if(Fl::test_shortcut('m')) {
400     mod_mesh_cb(0, 0);
401     Fl::focus(menu->scroll);
402     status = 1;
403   }
404   else if(Fl::test_shortcut('s')) {
405     mod_solver_cb(0, 0);
406     Fl::focus(menu->scroll);
407     status = 1;
408   }
409   else if(Fl::test_shortcut('p')) {
410     mod_post_cb(0, 0);
411     Fl::focus(menu->scroll);
412     status = 1;
413   }
414   else if(Fl::test_shortcut('<')) {
415     mod_back_cb(0, 0);
416     status = 1;
417   }
418   else if(Fl::test_shortcut('>')) {
419     mod_forward_cb(0, 0);
420     status = 1;
421   }
422   else if(Fl::test_shortcut('w')) {
423     file_watch_cb(0, 0);
424     status = 1;
425   }
426   else if(Fl::test_shortcut('e')) {
427     for(unsigned int i = 0; i < graph.size(); i++)
428       for(unsigned int j = 0; j < graph[i]->gl.size(); j++)
429         graph[i]->gl[j]->endSelection = 1;
430     status = 0; // trick: do as if we didn't use it
431   }
432   else if(Fl::test_shortcut('u')) {
433     for(unsigned int i = 0; i < graph.size(); i++)
434       for(unsigned int j = 0; j < graph[i]->gl.size(); j++)
435         graph[i]->gl[j]->undoSelection = 1;
436     status = 0; // trick: do as if we didn't use it
437   }
438   else if(Fl::test_shortcut('i')) {
439     for(unsigned int i = 0; i < graph.size(); i++)
440       for(unsigned int j = 0; j < graph[i]->gl.size(); j++)
441         graph[i]->gl[j]->invertSelection = 1;
442     status = 0; // trick: do as if we didn't use it
443   }
444   else if(Fl::test_shortcut('q')) {
445     for(unsigned int i = 0; i < graph.size(); i++)
446       for(unsigned int j = 0; j < graph[i]->gl.size(); j++)
447         graph[i]->gl[j]->quitSelection = 1;
448     status = 0; // trick: do as if we didn't use it
449   }
450   else if(Fl::test_shortcut('-')) {
451     for(unsigned int i = 0; i < graph.size(); i++)
452       for(unsigned int j = 0; j < graph[i]->gl.size(); j++)
453         graph[i]->gl[j]->invertSelection = 1;
454     status = 0; // trick: do as if we didn't use it
455   }
456   else if(Fl::test_shortcut(FL_Escape) ||
457           Fl::test_shortcut(FL_META + FL_Escape) ||
458           Fl::test_shortcut(FL_SHIFT + FL_Escape) ||
459           Fl::test_shortcut(FL_CTRL + FL_Escape) ||
460           Fl::test_shortcut(FL_ALT + FL_Escape)) {
461     bool lasso = false;
462     for(unsigned int i = 0; i < graph.size(); i++)
463       for(unsigned int j = 0; j < graph[i]->gl.size(); j++)
464         if(graph[i]->gl[j]->lassoMode) lasso = true;
465     if(lasso){
466       for(unsigned int i = 0; i < graph.size(); i++)
467         for(unsigned int j = 0; j < graph[i]->gl.size(); j++)
468           graph[i]->gl[j]->lassoMode = false;
469       status = 2;
470     }
471     else{
472       status_options_cb(0, (void *)"S");
473       status = 1;
474     }
475   }
476   else if(Fl::test_shortcut(FL_SHIFT + 'a')) {
477     window_cb(0, (void*)"front");
478     status = 1;
479   }
480   else if(Fl::test_shortcut(FL_SHIFT + 'o')) {
481     general_options_cb(0, 0);
482     status = 1;
483   }
484   else if(Fl::test_shortcut(FL_SHIFT + 'g')) {
485     geometry_options_cb(0, 0);
486     status = 1;
487   }
488   else if(Fl::test_shortcut(FL_SHIFT + 'm')) {
489     mesh_options_cb(0, 0);
490     status = 1;
491   }
492   else if(Fl::test_shortcut(FL_SHIFT + 's')) {
493     solver_options_cb(0, 0);
494     status = 1;
495   }
496   else if(Fl::test_shortcut(FL_SHIFT + 'p')) {
497     post_options_cb(0, 0);
498     status = 1;
499   }
500   else if(Fl::test_shortcut(FL_SHIFT + 'w')) {
501     if(PView::list.size()){
502       if(options->view.index >= 0 && options->view.index < (int)PView::list.size())
503         options->showGroup(options->view.index + 6);
504       else
505         options->showGroup(6);
506     }
507     status = 1;
508   }
509   else if(Fl::test_shortcut(FL_SHIFT + 'u')) {
510     if(PView::list.size()){
511       if(options->view.index >= 0 && options->view.index < (int)PView::list.size())
512         plugins->show(options->view.index);
513       else
514         plugins->show(0);
515     }
516     status = 1;
517   }
518   else if(Fl::test_shortcut(FL_ALT + 'f')) {
519     opt_general_fast_redraw
520       (0, GMSH_SET | GMSH_GUI, !opt_general_fast_redraw(0, GMSH_GET, 0));
521     status = 2;
522   }
523   else if(Fl::test_shortcut(FL_ALT + 'b')) {
524     opt_general_draw_bounding_box
525       (0, GMSH_SET | GMSH_GUI, !opt_general_draw_bounding_box(0, GMSH_GET, 0));
526     status = 2;
527   }
528   else if(Fl::test_shortcut(FL_ALT + 'i')) {
529     for(unsigned int i = 0; i < PView::list.size(); i++)
530       if(opt_view_visible(i, GMSH_GET, 0))
531         opt_view_show_scale
532           (i, GMSH_SET | GMSH_GUI, !opt_view_show_scale(i, GMSH_GET, 0));
533     status = 2;
534   }
535   else if(Fl::test_shortcut(FL_ALT + 'c')) {
536     opt_general_color_scheme
537       (0, GMSH_SET | GMSH_GUI, opt_general_color_scheme(0, GMSH_GET, 0) + 1);
538     status = 2;
539   }
540   else if(Fl::test_shortcut(FL_ALT + 'w')) {
541     opt_geometry_light
542       (0, GMSH_SET | GMSH_GUI, !opt_geometry_light(0, GMSH_GET, 0));
543     opt_mesh_light
544       (0, GMSH_SET | GMSH_GUI, !opt_mesh_light(0, GMSH_GET, 0));
545     for(unsigned int i = 0; i < PView::list.size(); i++)
546       if(opt_view_visible(i, GMSH_GET, 0))
547         opt_view_light
548           (i, GMSH_SET | GMSH_GUI, !opt_view_light(i, GMSH_GET, 0));
549     status = 2;
550   }
551   else if(Fl::test_shortcut(FL_ALT + FL_SHIFT + 'w')) {
552     opt_mesh_reverse_all_normals
553       (0, GMSH_SET | GMSH_GUI, !opt_mesh_reverse_all_normals(0, GMSH_GET, 0));
554     status = 2;
555   }
556   else if(Fl::test_shortcut(FL_ALT + 'x') ||
557           Fl::test_shortcut(FL_ALT + FL_SHIFT + 'x')) {
558     status_xyz1p_cb(0, (void *)"x");
559     status = 1;
560   }
561   else if(Fl::test_shortcut(FL_ALT + 'y') ||
562           Fl::test_shortcut(FL_ALT + FL_SHIFT + 'y')) {
563     status_xyz1p_cb(0, (void *)"y");
564     status = 1;
565   }
566   else if(Fl::test_shortcut(FL_ALT + 'z') ||
567           Fl::test_shortcut(FL_ALT + FL_SHIFT + 'z')) {
568     status_xyz1p_cb(0, (void *)"z");
569     status = 1;
570   }
571   else if(Fl::test_shortcut(FL_ALT + 'o') ||
572           Fl::test_shortcut(FL_ALT + FL_SHIFT + 'o')) {
573     status_options_cb(0, (void *)"p");
574     status = 1;
575   }
576   else if(Fl::test_shortcut(FL_ALT + 'a')) {
577     opt_general_axes
578       (0, GMSH_SET | GMSH_GUI, opt_general_axes(0, GMSH_GET, 0) + 1);
579     for(unsigned int i = 0; i < PView::list.size(); i++)
580       if(opt_view_visible(i, GMSH_GET, 0))
581         opt_view_axes(i, GMSH_SET | GMSH_GUI, opt_view_axes(i, GMSH_GET, 0) + 1);
582     status = 2;
583   }
584   else if(Fl::test_shortcut(FL_ALT + FL_SHIFT + 'a')) {
585     opt_general_small_axes
586       (0, GMSH_SET | GMSH_GUI, !opt_general_small_axes(0, GMSH_GET, 0));
587     status = 2;
588   }
589   else if(Fl::test_shortcut(FL_ALT + 'p')) {
590     opt_geometry_points
591       (0, GMSH_SET | GMSH_GUI, !opt_geometry_points(0, GMSH_GET, 0));
592     status = 2;
593   }
594   else if(Fl::test_shortcut(FL_ALT + 'l')) {
595     opt_geometry_lines
596       (0, GMSH_SET | GMSH_GUI, !opt_geometry_lines(0, GMSH_GET, 0));
597     status = 2;
598   }
599   else if(Fl::test_shortcut(FL_ALT + 's')) {
600     opt_geometry_surfaces
601       (0, GMSH_SET | GMSH_GUI, !opt_geometry_surfaces(0, GMSH_GET, 0));
602     status = 2;
603   }
604   else if(Fl::test_shortcut(FL_ALT + 'v')) {
605     opt_geometry_volumes
606       (0, GMSH_SET | GMSH_GUI, !opt_geometry_volumes(0, GMSH_GET, 0));
607     status = 2;
608   }
609   else if(Fl::test_shortcut(FL_ALT + FL_SHIFT + 'p')) {
610     opt_mesh_points(0, GMSH_SET | GMSH_GUI, !opt_mesh_points(0, GMSH_GET, 0));
611     status = 2;
612   }
613   else if(Fl::test_shortcut(FL_ALT + FL_SHIFT + 'l')) {
614     opt_mesh_lines
615       (0, GMSH_SET | GMSH_GUI, !opt_mesh_lines(0, GMSH_GET, 0));
616     status = 2;
617   }
618   else if(Fl::test_shortcut(FL_ALT + FL_SHIFT + 's')) {
619     opt_mesh_surfaces_edges
620       (0, GMSH_SET | GMSH_GUI, !opt_mesh_surfaces_edges(0, GMSH_GET, 0));
621     status = 2;
622   }
623   else if(Fl::test_shortcut(FL_ALT + FL_SHIFT + 'v')) {
624     opt_mesh_volumes_edges
625       (0, GMSH_SET | GMSH_GUI, !opt_mesh_volumes_edges(0, GMSH_GET, 0));
626     status = 2;
627   }
628   else if(Fl::test_shortcut(FL_ALT + 'd')){
629     opt_geometry_surface_type
630       (0, GMSH_SET | GMSH_GUI, opt_geometry_surface_type(0, GMSH_GET, 0) + 1);
631     status = 2;
632   }
633   else if(Fl::test_shortcut(FL_ALT + FL_SHIFT + 'd')) {
634     opt_mesh_surfaces_faces
635       (0, GMSH_SET | GMSH_GUI, !opt_mesh_surfaces_faces(0, GMSH_GET, 0));
636     status = 2;
637   }
638   else if(Fl::test_shortcut(FL_ALT + FL_SHIFT + 'b')) {
639     opt_mesh_volumes_faces
640       (0, GMSH_SET | GMSH_GUI, !opt_mesh_volumes_faces(0, GMSH_GET, 0));
641     status = 2;
642   }
643   else if(Fl::test_shortcut(FL_ALT + 'm')) {
644     status_options_cb(0, (void *)"M");
645     status = 2;
646   }
647   else if(Fl::test_shortcut(FL_ALT + 't')) {
648     for(unsigned int i = 0; i < PView::list.size(); i++)
649       if(opt_view_visible(i, GMSH_GET, 0))
650         opt_view_intervals_type
651           (i, GMSH_SET | GMSH_GUI, opt_view_intervals_type(i, GMSH_GET, 0) + 1);
652     status = 2;
653   }
654   else if(Fl::test_shortcut(FL_ALT + 'r')) {
655     for(unsigned int i = 0; i < PView::list.size(); i++)
656       if(opt_view_visible(i, GMSH_GET, 0))
657         opt_view_range_type
658           (i, GMSH_SET | GMSH_GUI, opt_view_range_type(i, GMSH_GET, 0) + 1);
659     status = 2;
660   }
661   else if(Fl::test_shortcut(FL_ALT + 'n')) {
662     for(unsigned int i = 0; i < PView::list.size(); i++)
663       if(opt_view_visible(i, GMSH_GET, 0))
664         opt_view_draw_strings
665           (i, GMSH_SET | GMSH_GUI, !opt_view_draw_strings(i, GMSH_GET, 0));
666     status = 2;
667   }
668   else if(Fl::test_shortcut(FL_ALT + 'e') ||
669           Fl::test_shortcut(FL_ALT + FL_SHIFT + 'e')) {
670     for(unsigned int i = 0; i < PView::list.size(); i++)
671       if(opt_view_visible(i, GMSH_GET, 0))
672         opt_view_show_element
673           (i, GMSH_SET | GMSH_GUI, !opt_view_show_element(i, GMSH_GET, 0));
674     status = 2;
675   }
676   else if(Fl::test_shortcut(FL_ALT + 'h')) {
677     static int show = 0;
678     for(unsigned int i = 0; i < PView::list.size(); i++)
679       opt_view_visible(i, GMSH_SET | GMSH_GUI, show);
680     show = !show;
681     status = 2;
682   }
683   else if(testArrowShortcuts()) {
684     status = 1;
685   }
686 
687   if(status == 2){
688     drawContext::global()->draw();
689     return 1;
690   }
691   else if(status == 1)
692     return 1;
693   else
694     return 0;
695 }
696 
testArrowShortcuts()697 int FlGui::testArrowShortcuts()
698 {
699   if(Fl::test_shortcut(FL_Left)) {
700     status_play_manual(1, -CTX::instance()->post.animStep);
701     return 1;
702   }
703   else if(Fl::test_shortcut(FL_Right)) {
704     status_play_manual(1, CTX::instance()->post.animStep);
705     return 1;
706   }
707   else if(Fl::test_shortcut(FL_Up)) {
708     status_play_manual(0, -CTX::instance()->post.animStep);
709     return 1;
710   }
711   else if(Fl::test_shortcut(FL_Down)) {
712     status_play_manual(0, CTX::instance()->post.animStep);
713     return 1;
714   }
715   return 0;
716 }
717 
setGraphicTitle(std::string title)718 void FlGui::setGraphicTitle(std::string title)
719 {
720   for(unsigned int i = 0; i < graph.size(); i++){
721     if(!i){
722       graph[i]->setTitle(title);
723     }
724     else{
725       std::ostringstream sstream;
726       sstream << title << " [" << i << "]";
727       graph[i]->setTitle(sstream.str());
728     }
729   }
730 }
731 
updateViews(bool numberOfViewsHasChanged)732 void FlGui::updateViews(bool numberOfViewsHasChanged)
733 {
734   for(unsigned int i = 0; i < graph.size(); i++)
735     graph[i]->checkAnimButtons();
736   if(numberOfViewsHasChanged){
737     if(menu->module->value() == 3)
738       menu->setContext(menu_post, 0);
739     options->resetBrowser();
740     options->resetExternalViewList();
741     fields->loadFieldViewList();
742     plugins->resetViewBrowser();
743     clipping->resetBrowser();
744   }
745 }
746 
updateFields()747 void FlGui::updateFields()
748 {
749   fields->editField(GModel::current()->getFields()->get(fields->selected_id));
750 }
751 
resetVisibility()752 void FlGui::resetVisibility()
753 {
754   if(visibility->win->shown())
755     visibility_cb(NULL, NULL);
756 }
757 
getCurrentOpenglWindow()758 openglWindow *FlGui::getCurrentOpenglWindow()
759 {
760   if(openglWindow::getLastHandled())
761     return openglWindow::getLastHandled();
762   else
763     return graph[0]->gl[0];
764 }
765 
splitCurrentOpenglWindow(char how)766 void FlGui::splitCurrentOpenglWindow(char how)
767 {
768   openglWindow *g = getCurrentOpenglWindow();
769   for(unsigned int i = 0; i < graph.size(); i++){
770     if(graph[i]->tile->find(g) != graph[i]->tile->children()){
771       graph[i]->split(g, how);
772       break;
773     }
774   }
775 }
776 
selectEntity(int type)777 char FlGui::selectEntity(int type)
778 {
779   return getCurrentOpenglWindow()->selectEntity
780     (type, selectedVertices, selectedEdges, selectedFaces, selectedRegions,
781      selectedElements);
782 }
783 
setStatus(const char * msg,int num)784 void FlGui::setStatus(const char *msg, int num)
785 {
786   if(num == 0 || num == 1){
787     static char buff[2][1024];
788     strncpy(buff[num], msg, sizeof(buff[num]) - 1);
789     buff[num][sizeof(buff[num]) - 1] = '\0';
790     for(unsigned int i = 0; i < graph.size(); i++){
791       graph[i]->label[num]->label(buff[num]);
792       graph[i]->label[num]->redraw();
793     }
794   }
795   else if(num == 2){
796     openglWindow *gl = getCurrentOpenglWindow();
797     int n = strlen(msg);
798     int i = 0;
799     while(i < n) if(msg[i++] == '\n') break;
800     gl->screenMessage[0] = std::string(msg);
801     if(i)
802       gl->screenMessage[0].resize(i - 1);
803     if(i < n)
804       gl->screenMessage[1] = std::string(&msg[i]);
805     else
806       gl->screenMessage[1].clear();
807     drawContext::global()->draw();
808   }
809 }
810 
storeCurrentWindowsInfo()811 void FlGui::storeCurrentWindowsInfo()
812 {
813   CTX::instance()->menuPosition[0] = menu->win->x();
814   CTX::instance()->menuPosition[1] = menu->win->y();
815   CTX::instance()->glPosition[0] = graph[0]->win->x();
816   CTX::instance()->glPosition[1] = graph[0]->win->y();
817   CTX::instance()->glSize[0] = graph[0]->win->w();
818   CTX::instance()->glSize[1] = (graph[0]->win->h() - graph[0]->bottom->h());
819   CTX::instance()->msgSize = graph[0]->getMessageHeight();
820   CTX::instance()->optPosition[0] = options->win->x();
821   CTX::instance()->optPosition[1] = options->win->y();
822   CTX::instance()->pluginPosition[0] = plugins->win->x();
823   CTX::instance()->pluginPosition[1] = plugins->win->y();
824   CTX::instance()->pluginSize[0] = plugins->win->w();
825   CTX::instance()->pluginSize[1] = plugins->win->h();
826   CTX::instance()->fieldPosition[0] = fields->win->x();
827   CTX::instance()->fieldPosition[1] = fields->win->y();
828   CTX::instance()->fieldSize[0] = fields->win->w();
829   CTX::instance()->fieldSize[1] = fields->win->h();
830   CTX::instance()->statPosition[0] = stats->win->x();
831   CTX::instance()->statPosition[1] = stats->win->y();
832   CTX::instance()->visPosition[0] = visibility->win->x();
833   CTX::instance()->visPosition[1] = visibility->win->y();
834   CTX::instance()->clipPosition[0] = clipping->win->x();
835   CTX::instance()->clipPosition[1] = clipping->win->y();
836   CTX::instance()->manipPosition[0] = manip->win->x();
837   CTX::instance()->manipPosition[1] = manip->win->y();
838   CTX::instance()->ctxPosition[0] = geoContext->win->x();
839   CTX::instance()->ctxPosition[1] = meshContext->win->y();
840 #if defined(HAVE_ONELAB) && (FL_MAJOR_VERSION == 1) && (FL_MINOR_VERSION == 3)
841   CTX::instance()->solverPosition[0] = onelab->x();
842   CTX::instance()->solverPosition[1] = onelab->y();
843   CTX::instance()->solverSize[0] = onelab->w();
844   CTX::instance()->solverSize[1] = onelab->h();
845 #endif
846   fileChooserGetPosition(&CTX::instance()->fileChooserPosition[0],
847                          &CTX::instance()->fileChooserPosition[1]);
848 }
849 
callForSolverPlugin(int dim)850 void FlGui::callForSolverPlugin(int dim)
851 {
852   GMSH_SolverPlugin *sp = PluginManager::instance()->findSolverPlugin();
853   if(sp) sp->popupPropertiesForPhysicalEntity(dim);
854 }
855 
856 // Callbacks
857 
redraw_cb(Fl_Widget * w,void * data)858 void redraw_cb(Fl_Widget *w, void *data)
859 {
860   drawContext::global()->draw();
861 }
862 
window_cb(Fl_Widget * w,void * data)863 void window_cb(Fl_Widget *w, void *data)
864 {
865   static int oldx = 0, oldy = 0, oldw = 0, oldh = 0, zoom = 1;
866   std::string str((const char*)data);
867 
868   if(str == "minimize"){
869     for(unsigned int i = 0; i < FlGui::instance()->graph.size(); i++)
870       if(FlGui::instance()->graph[i]->win->shown())
871         FlGui::instance()->graph[i]->win->iconize();
872     if(FlGui::instance()->options->win->shown())
873       FlGui::instance()->options->win->iconize();
874     if(FlGui::instance()->plugins->win->shown())
875       FlGui::instance()->plugins->win->iconize();
876     if(FlGui::instance()->fields->win->shown())
877       FlGui::instance()->fields->win->iconize();
878     if(FlGui::instance()->visibility->win->shown())
879       FlGui::instance()->visibility->win->iconize();
880     if(FlGui::instance()->clipping->win->shown())
881       FlGui::instance()->clipping->win->iconize();
882     if(FlGui::instance()->manip->win->shown())
883       FlGui::instance()->manip->win->iconize();
884     if(FlGui::instance()->stats->win->shown())
885       FlGui::instance()->stats->win->iconize();
886     if(FlGui::instance()->menu->win->shown())
887       FlGui::instance()->menu->win->iconize();
888   }
889   else if(str == "zoom"){
890     if(zoom){
891       oldx = FlGui::instance()->graph[0]->win->x();
892       oldy = FlGui::instance()->graph[0]->win->y();
893       oldw = FlGui::instance()->graph[0]->win->w();
894       oldh = FlGui::instance()->graph[0]->win->h();
895 //#define FS
896 #ifndef FS
897       FlGui::instance()->graph[0]->win->resize(Fl::x(), Fl::y(), Fl::w(), Fl::h());
898       FlGui::instance()->graph[0]->hideMessages();
899       FlGui::check();
900 #else
901       FlGui::instance()->graph[0]->win->fullscreen();
902 #endif
903       zoom = 0;
904     }
905     else{
906 #ifndef FS
907       FlGui::instance()->graph[0]->win->resize(oldx, oldy, oldw, oldh);
908 #else
909       FlGui::instance()->graph[0]->win->fullscreen_off();
910 #endif
911       zoom = 1;
912     }
913     FlGui::instance()->menu->win->show();
914   }
915   else if(str == "front"){
916     // the order is important!
917     for(unsigned int i = 0; i < FlGui::instance()->graph.size(); i++)
918       FlGui::instance()->graph[i]->win->show();
919     if(FlGui::instance()->options->win->shown())
920       FlGui::instance()->options->win->show();
921     if(FlGui::instance()->plugins->win->shown())
922       FlGui::instance()->plugins->win->show();
923     if(FlGui::instance()->fields->win->shown())
924       FlGui::instance()->fields->win->show();
925     if(FlGui::instance()->geoContext->win->shown())
926       FlGui::instance()->geoContext->win->show();
927     if(FlGui::instance()->meshContext->win->shown())
928       FlGui::instance()->meshContext->win->show();
929 #if defined(HAVE_ONELAB) && (FL_MAJOR_VERSION == 1) && (FL_MINOR_VERSION == 3)
930     if(FlGui::instance()->onelab->shown())
931       FlGui::instance()->onelab->show();
932 #endif
933     if(FlGui::instance()->visibility->win->shown())
934       FlGui::instance()->visibility->win->show();
935     if(FlGui::instance()->clipping->win->shown())
936       FlGui::instance()->clipping->win->show();
937     if(FlGui::instance()->manip->win->shown())
938       FlGui::instance()->manip->win->show();
939     if(FlGui::instance()->stats->win->shown())
940       FlGui::instance()->stats->win->show();
941     FlGui::instance()->menu->win->show();
942   }
943 }
944 
addMessage(const char * msg)945 void FlGui::addMessage(const char *msg)
946 {
947   for(unsigned int i = 0; i < FlGui::instance()->graph.size(); i++)
948     FlGui::instance()->graph[i]->addMessage(msg);
949 }
950 
showMessages()951 void FlGui::showMessages()
952 {
953   for(unsigned int i = 0; i < FlGui::instance()->graph.size(); i++)
954     FlGui::instance()->graph[i]->showMessages();
955 }
956 
saveMessages(const char * fileName)957 void FlGui::saveMessages(const char *fileName)
958 {
959   FlGui::instance()->graph[0]->saveMessages(fileName);
960 }
961