1 // Gmsh - Copyright (C) 1997-2021 C. Geuzaine, J.-F. Remacle
2 //
3 // See the LICENSE.txt file in the Gmsh root directory for license information.
4 // Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5
6 #include "GmshConfig.h"
7 #include <sstream>
8 #include <string.h>
9 #include <FL/Fl.H>
10 #include <FL/Fl_Tooltip.H>
11 #include <FL/Fl_Shared_Image.H>
12 #include <FL/Fl_File_Icon.H>
13 #include <FL/fl_draw.H>
14 #include <FL/fl_ask.H>
15 #include "FlGui.h"
16 #include "drawContextFltk.h"
17 #include "drawContextFltkCairo.h"
18 #include "graphicWindow.h"
19 #include "optionWindow.h"
20 #include "fieldWindow.h"
21 #include "pluginWindow.h"
22 #include "statisticsWindow.h"
23 #include "visibilityWindow.h"
24 #include "highOrderToolsWindow.h"
25 #include "clippingWindow.h"
26 #include "manipWindow.h"
27 #include "contextWindow.h"
28 #include "onelabContextWindow.h"
29 #include "onelabGroup.h"
30 #include "helpWindow.h"
31 #include "colorbarWindow.h"
32 #include "fileDialogs.h"
33 #include "GmshDefines.h"
34 #include "GmshMessage.h"
35 #include "GModel.h"
36 #include "OS.h"
37 #include "MElement.h"
38 #include "PView.h"
39 #include "Field.h"
40 #include "Plugin.h"
41 #include "PluginManager.h"
42 #include "OpenFile.h"
43 #include "XpmIcon.h"
44 #include "Options.h"
45 #include "CommandLine.h"
46 #include "Context.h"
47 #include "StringUtils.h"
48 #include "gl2ps.h"
49 #include "gmshPopplerWrapper.h"
50 #include "PixelBuffer.h"
51 #if defined(HAVE_TOUCHBAR)
52 #include "touchBar.h"
53 #endif
54 #if defined(HAVE_3M)
55 #include "3M.h"
56 #endif
57
58 FlGui *FlGui::_instance = nullptr;
59 std::string FlGui::_openedThroughMacFinder = "";
60 bool FlGui::_finishedProcessingCommandLine = false;
61 std::atomic<int> FlGui::_locked(0);
62
63 // check (now!) if there are any pending events, and process them
check(bool rateLimited)64 void FlGui::check(bool rateLimited)
65 {
66 if(Msg::GetThreadNum() > 0 || _locked > 0) return;
67
68 static double lastRefresh = 0.;
69 double start = TimeOfDay();
70 if(rateLimited && CTX::instance()->guiRefreshRate > 0) {
71 if(start - lastRefresh > 1. / CTX::instance()->guiRefreshRate) {
72 lastRefresh = start;
73 Fl::check();
74 }
75 }
76 else {
77 lastRefresh = start;
78 Fl::check();
79 }
80 }
81
82 // wait (possibly indefinitely) for any events, then process them
wait(bool force)83 void FlGui::wait(bool force)
84 {
85 if((Msg::GetThreadNum() > 0 || _locked > 0) && !force) return;
86 Fl::wait();
87 }
88
89 // wait (at most time seconds) for any events, then process them
wait(double time,bool force)90 void FlGui::wait(double time, bool force)
91 {
92 if((Msg::GetThreadNum() > 0 || _locked > 0) && !force) return;
93 Fl::wait(time);
94 }
95
lock()96 void FlGui::lock()
97 {
98 _locked++;
99 Fl::lock();
100 }
101
unlock()102 void FlGui::unlock()
103 {
104 _locked--;
105 Fl::unlock();
106 }
107
locked()108 int FlGui::locked() { return _locked; }
109
awake_cb(void * data)110 static void awake_cb(void *data)
111 {
112 if(data) FlGui::instance()->updateViews(true, false);
113 }
114
awake(const std::string & action)115 void FlGui::awake(const std::string &action)
116 {
117 if(action.empty())
118 Fl::awake(awake_cb, nullptr);
119 else
120 Fl::awake(awake_cb, (void *)"update");
121 }
122
setOpenedThroughMacFinder(const std::string & name)123 void FlGui::setOpenedThroughMacFinder(const std::string &name)
124 {
125 _openedThroughMacFinder = name;
126 }
127
getOpenedThroughMacFinder()128 std::string FlGui::getOpenedThroughMacFinder()
129 {
130 return _openedThroughMacFinder;
131 }
132
setFinishedProcessingCommandLine()133 void FlGui::setFinishedProcessingCommandLine()
134 {
135 _finishedProcessingCommandLine = true;
136 }
137
getFinishedProcessingCommandLine()138 bool FlGui::getFinishedProcessingCommandLine()
139 {
140 return _finishedProcessingCommandLine;
141 }
142
globalShortcut(int event)143 static int globalShortcut(int event)
144 {
145 if(!FlGui::available()) return 0;
146 return FlGui::instance()->testGlobalShortcuts(event);
147 }
148
simple_right_box_draw(int x,int y,int w,int h,Fl_Color c)149 static void simple_right_box_draw(int x, int y, int w, int h, Fl_Color c)
150 {
151 fl_color(c);
152 fl_rectf(x, y, w, h);
153 fl_color(FL_DARK2);
154 fl_line(x + w - 1, y, x + w - 1, y + h);
155 }
156
simple_top_box_draw(int x,int y,int w,int h,Fl_Color c)157 static void simple_top_box_draw(int x, int y, int w, int h, Fl_Color c)
158 {
159 fl_color(c);
160 fl_rectf(x, y, w, h);
161 fl_color(FL_DARK2);
162 fl_line(x, y, x + w, y);
163 }
164
165 // Icons for the satus bar
166 #define vv(x, y) fl_vertex(x, y)
167 #define bl fl_begin_loop()
168 #define el fl_end_loop()
169
gmsh_play(Fl_Color c)170 static void gmsh_play(Fl_Color c)
171 {
172 fl_color(c);
173 bl;
174 vv(-0.3, 0.8);
175 vv(0.5, 0.0);
176 vv(-0.3, -0.8);
177 el;
178 }
179
gmsh_pause(Fl_Color c)180 static void gmsh_pause(Fl_Color c)
181 {
182 fl_color(c);
183 bl;
184 vv(-0.8, -0.8);
185 vv(-0.3, -0.8);
186 vv(-0.3, 0.8);
187 vv(-0.8, 0.8);
188 el;
189 bl;
190 vv(0.0, -0.8);
191 vv(0.5, -0.8);
192 vv(0.5, 0.8);
193 vv(0.0, 0.8);
194 el;
195 }
196
gmsh_rewind(Fl_Color c)197 static void gmsh_rewind(Fl_Color c)
198 {
199 fl_color(c);
200 bl;
201 vv(-0.8, -0.8);
202 vv(-0.3, -0.8);
203 vv(-0.3, 0.8);
204 vv(-0.8, 0.8);
205 el;
206 bl;
207 vv(-0.3, 0.0);
208 vv(0.5, -0.8);
209 vv(0.5, 0.8);
210 el;
211 }
212
gmsh_forward(Fl_Color c)213 static void gmsh_forward(Fl_Color c)
214 {
215 fl_color(c);
216 bl;
217 vv(0.0, 0.8);
218 vv(0.8, 0.0);
219 vv(0.0, -0.8);
220 el;
221 bl;
222 vv(-0.8, 0.8);
223 vv(-0.3, 0.8);
224 vv(-0.3, -0.8);
225 vv(-0.8, -0.8);
226 el;
227 }
228
gmsh_back(Fl_Color c)229 static void gmsh_back(Fl_Color c)
230 {
231 fl_rotate(180);
232 gmsh_forward(c);
233 }
234
gmsh_rotate(Fl_Color c)235 static void gmsh_rotate(Fl_Color c)
236 {
237 fl_color(c);
238 fl_begin_line();
239 fl_arc(0.0, -0.1, 0.7, 0.0, 270.0);
240 fl_end_line();
241 fl_begin_polygon();
242 vv(0.5, 0.6);
243 vv(-0.1, 0.9);
244 vv(-0.1, 0.3);
245 fl_end_polygon();
246 }
247
gmsh_models(Fl_Color c)248 static void gmsh_models(Fl_Color c)
249 {
250 fl_color(c);
251 bl;
252 vv(-0.8, -0.7);
253 vv(0.8, -0.7);
254 el;
255 bl;
256 vv(-0.8, -0.2);
257 vv(0.8, -0.2);
258 el;
259 bl;
260 vv(-0.8, 0.3);
261 vv(0.8, 0.3);
262 el;
263 bl;
264 vv(-0.8, 0.8);
265 vv(0.8, 0.8);
266 el;
267 }
268
gmsh_gear(Fl_Color c)269 static void gmsh_gear(Fl_Color c)
270 {
271 fl_color(c);
272 double w = 0.12;
273 double h1 = 0.5;
274 #if defined(WIN32)
275 double h2 = 1.0;
276 #else
277 double h2 = 1.05;
278 #endif
279 fl_line_style(FL_SOLID, 3);
280 fl_begin_line();
281 fl_circle(0, 0, 0.5);
282 fl_end_line();
283 fl_line_style(FL_SOLID);
284 for(int i = 0; i < 8; i++) {
285 fl_rotate(45);
286 fl_begin_polygon();
287 fl_vertex(h1, -w);
288 fl_vertex(h2, -w);
289 fl_vertex(h2, w);
290 fl_vertex(h1, w);
291 fl_end_polygon();
292 }
293 }
294
gmsh_graph(Fl_Color c)295 static void gmsh_graph(Fl_Color c)
296 {
297 fl_color(c);
298 fl_begin_line();
299 vv(-0.8, -0.8);
300 vv(-0.8, 0.8);
301 vv(0.8, 0.8);
302 fl_end_line();
303 fl_begin_line();
304 vv(-0.8, 0.3);
305 vv(-0.2, -0.2);
306 vv(0.3, 0.1);
307 vv(0.8, -0.4);
308 fl_end_line();
309 }
310
gmsh_search(Fl_Color col)311 static void gmsh_search(Fl_Color col)
312 {
313 double e = 0.5;
314 fl_color(col);
315 fl_begin_polygon();
316 vv(.6 - e, .33);
317 vv(1.2 - e, .93);
318 vv(.93 - e, 1.2);
319 vv(.33 - e, .6);
320 fl_end_polygon();
321 fl_line_style(FL_SOLID, 2);
322 fl_begin_loop();
323 fl_circle(0 - e, 0, .6);
324 fl_end_loop();
325 fl_line_style(FL_SOLID);
326 }
327
gmsh_colormap(Fl_Color col)328 static void gmsh_colormap(Fl_Color col)
329 {
330 fl_color(FL_RED);
331 fl_begin_polygon();
332 vv(-0.8, -0.8);
333 vv(-0.3, -0.8);
334 vv(-0.3, 0.8);
335 vv(-0.8, 0.8);
336 fl_end_polygon();
337 fl_color(FL_GREEN);
338 fl_begin_polygon();
339 vv(-0.3, -0.8);
340 vv(0.2, -0.8);
341 vv(0.2, 0.8);
342 vv(-0.3, 0.8);
343 fl_end_polygon();
344 fl_color(FL_BLUE);
345 fl_begin_polygon();
346 vv(0.2, -0.8);
347 vv(0.7, -0.8);
348 vv(0.7, 0.8);
349 vv(0.2, 0.8);
350 fl_end_polygon();
351 }
352
353 #undef vv
354 #undef bl
355 #undef el
356
357 // question presence of gamepad every 3. seconds
gamepad_handler(void * data)358 static void gamepad_handler(void *data)
359 {
360 if(CTX::instance()->gamepad && CTX::instance()->gamepad->active) {
361 CTX::instance()->gamepad->read_event();
362 Fl::add_timeout(CTX::instance()->gamepad->frequency, gamepad_handler, data);
363 }
364 else {
365 Fl::add_timeout(.5, gamepad_handler, data);
366 }
367 }
368
applyColorScheme(bool redraw)369 void FlGui::applyColorScheme(bool redraw)
370 {
371 static int first = true;
372 int N = 4 + FL_NUM_GRAY;
373 static std::vector<unsigned char> r(N, 0), g(N, 0), b(N, 0);
374
375 if(first) {
376 // store default (OS-dependent) interface colors:
377 Fl::get_system_colors();
378 Fl::get_color(FL_BACKGROUND_COLOR, r[0], g[0], b[0]);
379 Fl::get_color(FL_BACKGROUND2_COLOR, r[1], g[1], b[1]);
380 Fl::get_color(FL_FOREGROUND_COLOR, r[2], g[2], b[2]);
381 Fl::get_color(FL_SELECTION_COLOR, r[3], g[3], b[3]);
382 for(int i = 0; i < FL_NUM_GRAY; i++) {
383 Fl::get_color(fl_gray_ramp(i), r[4 + i], g[4 + i], b[4 + i]);
384 }
385 }
386
387 if(CTX::instance()->guiColorScheme == 1) { // dark mode
388 Fl::set_color(FL_BACKGROUND_COLOR, 20, 20, 20);
389 Fl::set_color(FL_BACKGROUND2_COLOR, 70, 70, 70);
390 Fl::set_color(FL_FOREGROUND_COLOR, 220, 220, 220);
391 for(int i = 0; i < FL_NUM_GRAY; i++) {
392 double min = 0., max = 70.;
393 int d = (int)(min + i * (max - min) / (FL_NUM_GRAY - 1.));
394 Fl::set_color(fl_gray_ramp(i), d, d, d);
395 }
396 Fl::set_color(FL_SELECTION_COLOR, 200, 200, 200);
397 }
398 else if(!first && available() && CTX::instance()->guiColorScheme == 0) {
399 // retore default colors (only if not calling the routine from the
400 // constructor)
401 Fl::set_color(FL_BACKGROUND_COLOR, r[0], g[0], b[0]);
402 Fl::set_color(FL_BACKGROUND2_COLOR, r[1], g[1], b[1]);
403 Fl::set_color(FL_FOREGROUND_COLOR, r[2], g[2], b[2]);
404 for(int i = 0; i < FL_NUM_GRAY; i++) {
405 Fl::set_color(fl_gray_ramp(i), r[4 + i], g[4 + i], b[4 + i]);
406 }
407 Fl::set_color(FL_SELECTION_COLOR, r[3], g[3], b[3]);
408 }
409
410 first = false;
411
412 // also change default box type here (to thin versions)
413 Fl::set_boxtype(FL_UP_BOX, FL_THIN_UP_BOX);
414 Fl::set_boxtype(FL_DOWN_BOX, FL_THIN_DOWN_BOX);
415 Fl::set_boxtype(FL_UP_FRAME, FL_THIN_UP_FRAME);
416 Fl::set_boxtype(FL_DOWN_FRAME, FL_THIN_DOWN_FRAME);
417
418 // thinner scrollbars
419 Fl::scrollbar_size(std::max(10, FL_NORMAL_SIZE));
420
421 if(redraw && available()) {
422 updateViews(true, true);
423 for(Fl_Window *win = Fl::first_window(); win; win = Fl::next_window(win)) {
424 win->redraw();
425 }
426 }
427 }
428
default_error_handler(const char * fmt,...)429 static void default_error_handler(const char *fmt, ...)
430 {
431 char str[5000];
432 va_list args;
433 va_start(args, fmt);
434 vsnprintf(str, sizeof(str), fmt, args);
435 va_end(args);
436 if(!strcmp(str, "Insufficient GL support")) { // this should be fatal
437 CTX::instance()->terminal = 1;
438 Msg::Error("%s (FLTK internal error)", str);
439 Msg::Error("Your system does not seem to support OpenGL - aborting");
440 Msg::Exit(1);
441 }
442 else {
443 Msg::Error("%s (FLTK internal error)", str);
444 }
445 }
446
default_fatal_error_handler(const char * fmt,...)447 static void default_fatal_error_handler(const char *fmt, ...)
448 {
449 char str[5000];
450 va_list args;
451 va_start(args, fmt);
452 vsnprintf(str, sizeof(str), fmt, args);
453 va_end(args);
454 Msg::Error("%s (FLTK internal error)", str);
455 Msg::Exit(1);
456 }
457
FlGui(int argc,char ** argv,bool quitShouldExit,void (* error_handler)(const char * fmt,...))458 FlGui::FlGui(int argc, char **argv, bool quitShouldExit,
459 void (*error_handler)(const char *fmt, ...))
460 : _quitShouldExit(quitShouldExit), lastContextWindow(0)
461 {
462 if(error_handler) {
463 Fl::error = error_handler;
464 Fl::fatal = error_handler;
465 }
466 else {
467 Fl::error = default_error_handler;
468 Fl::fatal = default_fatal_error_handler;
469 }
470
471 #if defined(__APPLE__)
472 // the defaults use %@, which leads to (lowercase) gmsh
473 Fl_Mac_App_Menu::about = "About Gmsh";
474 Fl_Mac_App_Menu::hide = "Hide Gmsh";
475 Fl_Mac_App_Menu::quit = "Quit Gmsh";
476 Fl_Mac_App_Menu::print = ""; // this sometimes crashes
477 #endif
478
479 // tell fltk we're (potentially) in multi-threaded mode
480 Fl::lock();
481
482 // set X display
483 if(CTX::instance()->display.size())
484 Fl::display(CTX::instance()->display.c_str());
485
486 // add new box types (dx dy dw dh)
487 Fl::set_boxtype(GMSH_SIMPLE_RIGHT_BOX, simple_right_box_draw, 0, 0, 1, 0);
488 Fl::set_boxtype(GMSH_SIMPLE_TOP_BOX, simple_top_box_draw, 0, 1, 0, 1);
489
490 // apply color scheme before widget creation (noop if default color scheme is
491 // selected), so that there's no color "flashing"
492 applyColorScheme();
493
494 // add gamepad handler
495 if(CTX::instance()->gamepad)
496 Fl::add_timeout(5., gamepad_handler, (void *)nullptr);
497
498 // add global shortcuts
499 Fl::add_handler(globalShortcut);
500
501 // make sure a global drawing context is setup
502 if(!drawContext::global()) drawContext::setGlobal(new drawContextFltk);
503
504 // set default font size
505 FL_NORMAL_SIZE = drawContext::global()->getFontSize();
506
507 // handle themes and tooltip options
508 if(CTX::instance()->guiTheme.size())
509 Fl::scheme(CTX::instance()->guiTheme.c_str());
510 Fl_Tooltip::size(FL_NORMAL_SIZE);
511
512 // use retina resolution if available
513 #if(FL_MAJOR_VERSION == 1) && (FL_MINOR_VERSION == 3) && (FL_PATCH_VERSION >= 4)
514 Fl::use_high_res_GL(CTX::instance()->highResolutionGraphics);
515 #elif(FL_MAJOR_VERSION == 1) && (FL_MINOR_VERSION >= 4)
516 Fl::use_high_res_GL(CTX::instance()->highResolutionGraphics);
517 #endif
518
519 // register image formats not in core fltk library (jpeg/png)
520 fl_register_images();
521
522 // add our own icons
523 fl_add_symbol("gmsh_rewind", gmsh_rewind, 1);
524 fl_add_symbol("gmsh_back", gmsh_back, 1);
525 fl_add_symbol("gmsh_play", gmsh_play, 1);
526 fl_add_symbol("gmsh_pause", gmsh_pause, 1);
527 fl_add_symbol("gmsh_forward", gmsh_forward, 1);
528 fl_add_symbol("gmsh_rotate", gmsh_rotate, 1);
529 fl_add_symbol("gmsh_models", gmsh_models, 1);
530 fl_add_symbol("gmsh_gear", gmsh_gear, 1);
531 fl_add_symbol("gmsh_graph", gmsh_graph, 1);
532 fl_add_symbol("gmsh_search", gmsh_search, 1);
533 fl_add_symbol("gmsh_colormap", gmsh_colormap, 1);
534
535 // load default system icons (for file browser)
536 Fl_File_Icon::load_system_icons();
537
538 // FLTK >= 1.3.3 allows one to set a default global window icon
539 Fl_RGB_Image icon(&gmsh_icon_pixmap);
540 Fl_Window::default_icon(&icon);
541
542 // add callback to respond to Mac Finder
543 #if defined(__APPLE__)
544 fl_open_callback(OpenProjectMacFinder);
545 fl_mac_set_about(help_about_cb, nullptr);
546 #endif
547
548 // don't move input dialogs to follow mouse
549 fl_message_hotspot(0);
550
551 // create main graphic window (note that we create all the windows even if
552 // some are not displayed, since the shortcuts should be valid even for hidden
553 // windows, and we don't want to test for widget existence every time)
554 graph.push_back(
555 new graphicWindow(true, CTX::instance()->numTiles,
556 CTX::instance()->detachedMenu ? true : false));
557
558 graph[0]->getWindow()->show(argc > 0 ? 1 : 0, argv);
559 if(graph[0]->getMenuWindow()) graph[0]->getMenuWindow()->show();
560
561 // re-apply color scheme (necessary after open_display to get the selection
562 // color and boxtypes right)
563 applyColorScheme();
564
565 // graphic window should have the initial focus (so we can e.g. directly loop
566 // through time steps with the keyboard)
567 Fl::focus(graph[0]->gl[0]);
568
569 // get onelab tree group (FIXME: should clean this up)
570 onelab = graph.back()->getMenu();
571
572 // create additional graphic windows
573 for(int i = 1; i < CTX::instance()->numWindows; i++) {
574 graphicWindow *g = new graphicWindow(false, CTX::instance()->numTiles);
575 g->getWindow()->resize(
576 graph.back()->getWindow()->x() + 10, graph.back()->getWindow()->y() + 10,
577 graph.back()->getWindow()->w(), graph.back()->getWindow()->h());
578 g->getWindow()->show();
579 graph.push_back(g);
580 }
581 setGraphicTitle(GModel::current()->getFileName());
582
583 // create window that will be used for fullscreen display
584 fullscreen = new openglWindow(100, 100, 100, 100);
585 int mode = FL_RGB | FL_DEPTH | (CTX::instance()->db ? FL_DOUBLE : FL_SINGLE);
586 if(CTX::instance()->antialiasing) mode |= FL_MULTISAMPLE;
587 if(CTX::instance()->stereo) {
588 mode |= FL_DOUBLE;
589 mode |= FL_STEREO;
590 }
591 fullscreen->mode(mode);
592 fullscreen->end();
593
594 // create all other windows
595 options = new optionWindow(CTX::instance()->deltaFontSize);
596 fields = new fieldWindow(CTX::instance()->deltaFontSize);
597 plugins = new pluginWindow(CTX::instance()->deltaFontSize);
598 stats = new statisticsWindow(CTX::instance()->deltaFontSize);
599 visibility = new visibilityWindow(CTX::instance()->deltaFontSize);
600 highordertools = new highOrderToolsWindow(CTX::instance()->deltaFontSize);
601 clipping = new clippingWindow(CTX::instance()->deltaFontSize);
602 manip = new manipWindow(CTX::instance()->deltaFontSize);
603 elementaryContext =
604 new elementaryContextWindow(CTX::instance()->deltaFontSize);
605 transformContext = new transformContextWindow(CTX::instance()->deltaFontSize);
606 meshContext = new meshContextWindow(CTX::instance()->deltaFontSize);
607 physicalContext = new physicalContextWindow(CTX::instance()->deltaFontSize);
608 onelabContext = new onelabContextWindow(CTX::instance()->deltaFontSize);
609 help = new helpWindow();
610
611 // draw
612 for(std::size_t i = 0; i < graph.size(); i++)
613 for(std::size_t j = 0; j < graph[i]->gl.size(); j++)
614 graph[i]->gl[j]->redraw();
615
616 if(CTX::instance()->showOptionsOnStartup) options->win->show();
617 if(CTX::instance()->showMessagesOnStartup) graph[0]->showMessages();
618
619 #if defined(HAVE_TOUCHBAR)
620 showTouchBar();
621 #endif
622 }
623
~FlGui()624 FlGui::~FlGui()
625 {
626 for(std::size_t i = 0; i < graph.size(); i++) delete graph[i];
627 delete options;
628 delete fields;
629 delete plugins;
630 delete stats;
631 delete visibility;
632 delete highordertools;
633 delete clipping;
634 delete manip;
635 delete elementaryContext;
636 delete transformContext;
637 delete physicalContext;
638 delete onelabContext;
639 delete meshContext;
640 delete help;
641 delete fullscreen;
642 }
643
available()644 bool FlGui::available() { return _instance != nullptr; }
645
instance(int argc,char ** argv,bool quitShouldExit,void (* error_handler)(const char * fmt,...))646 FlGui *FlGui::instance(int argc, char **argv, bool quitShouldExit,
647 void (*error_handler)(const char *fmt, ...))
648 {
649 if(!_instance) {
650 _instance = new FlGui(argc, argv, quitShouldExit, error_handler);
651 // set all options in the new GUI
652 InitOptionsGUI(0);
653 // say welcome!
654 Msg::StatusBar(false, "Gmsh %s", GetGmshVersion());
655 // log the following for bug reports
656 Msg::Direct("-------------------------------------------------------");
657 PrintBuildInfo();
658 Msg::Direct("-------------------------------------------------------");
659 // update views (in case the GUI is created after some data has been loaded)
660 _instance->updateViews(true, true);
661 // set global bounding box in CTX (necessary if we run the gui without any
662 // model/post-processing data)
663 SetBoundingBox();
664 }
665 return _instance;
666 }
667
destroy()668 void FlGui::destroy()
669 {
670 if(!_instance) return;
671 delete _instance;
672 _instance = nullptr;
673 }
674
run()675 int FlGui::run()
676 {
677 // draw the scene
678 drawContext::global()->draw(false);
679
680 #if defined(HAVE_TOUCHBAR)
681 updateTouchBar();
682 #endif
683
684 return Fl::run();
685 }
686
testGlobalShortcuts(int event)687 int FlGui::testGlobalShortcuts(int event)
688 {
689 // we only handle shortcuts here
690 if(event != FL_SHORTCUT) return 0;
691
692 int status = 0;
693
694 if(Fl::test_shortcut('0')) {
695 geometry_reload_cb(nullptr, nullptr);
696 status = 1;
697 }
698 if(Fl::test_shortcut(FL_CTRL + '0') || Fl::test_shortcut(FL_META + '0') ||
699 Fl::test_shortcut('9')) { // for Bruno
700 onelab_reload_cb(nullptr, nullptr);
701 status = 1;
702 }
703 else if(Fl::test_shortcut('1') || Fl::test_shortcut(FL_F + 1)) {
704 mesh_1d_cb(nullptr, nullptr);
705 status = 1;
706 }
707 else if(Fl::test_shortcut('2') || Fl::test_shortcut(FL_F + 2)) {
708 mesh_2d_cb(nullptr, nullptr);
709 status = 1;
710 }
711 else if(Fl::test_shortcut('3') || Fl::test_shortcut(FL_F + 3)) {
712 mesh_3d_cb(nullptr, nullptr);
713 status = 1;
714 }
715 else if(Fl::test_shortcut(FL_CTRL + 'q') ||
716 Fl::test_shortcut(FL_META + 'q')) {
717 // only necessary when using the system menu bar, but hey, it cannot hurt...
718 file_quit_cb(nullptr, nullptr);
719 status = 1;
720 }
721 else if(Fl::test_shortcut(FL_CTRL + 't') ||
722 Fl::test_shortcut(FL_META + 't')) {
723 show_hide_menu_cb(nullptr, nullptr);
724 status = 1;
725 }
726 else if(Fl::test_shortcut('g')) {
727 FlGui::instance()->openModule("Geometry");
728 status = 1;
729 }
730 else if(Fl::test_shortcut('m')) {
731 FlGui::instance()->openModule("Mesh");
732 status = 1;
733 }
734 else if(Fl::test_shortcut('s')) {
735 FlGui::instance()->openModule("Solver");
736 status = 1;
737 }
738 else if(Fl::test_shortcut('p')) {
739 FlGui::instance()->openModule("Post-processing");
740 status = 1;
741 }
742 else if(Fl::test_shortcut('w')) {
743 file_watch_cb(nullptr, nullptr);
744 status = 1;
745 }
746 else if(Fl::test_shortcut('e')) {
747 for(std::size_t i = 0; i < graph.size(); i++)
748 for(std::size_t j = 0; j < graph[i]->gl.size(); j++)
749 graph[i]->gl[j]->endSelection = 1;
750 status = 0; // trick: do as if we didn't use it
751 }
752 else if(Fl::test_shortcut('u')) {
753 for(std::size_t i = 0; i < graph.size(); i++)
754 for(std::size_t j = 0; j < graph[i]->gl.size(); j++)
755 graph[i]->gl[j]->undoSelection = 1;
756 status = 0; // trick: do as if we didn't use it
757 }
758 else if(Fl::test_shortcut('i')) {
759 for(std::size_t i = 0; i < graph.size(); i++)
760 for(std::size_t j = 0; j < graph[i]->gl.size(); j++)
761 graph[i]->gl[j]->invertSelection = 1;
762 status = 0; // trick: do as if we didn't use it
763 }
764 else if(Fl::test_shortcut('q')) {
765 for(std::size_t i = 0; i < graph.size(); i++)
766 for(std::size_t j = 0; j < graph[i]->gl.size(); j++)
767 graph[i]->gl[j]->quitSelection = 1;
768 status = 0; // trick: do as if we didn't use it
769 }
770 else if(Fl::test_shortcut('-')) {
771 for(std::size_t i = 0; i < graph.size(); i++)
772 for(std::size_t j = 0; j < graph[i]->gl.size(); j++)
773 graph[i]->gl[j]->invertSelection = 1;
774 status = 0; // trick: do as if we didn't use it
775 }
776 else if(Fl::test_shortcut('x')) {
777 elementaryContext->butt[0]->value(!elementaryContext->butt[0]->value());
778 status = 1;
779 }
780 else if(Fl::test_shortcut('y')) {
781 elementaryContext->butt[1]->value(!elementaryContext->butt[1]->value());
782 status = 1;
783 }
784 else if(Fl::test_shortcut('z')) {
785 elementaryContext->butt[2]->value(!elementaryContext->butt[2]->value());
786 status = 1;
787 }
788 else if(Fl::test_shortcut(FL_SHIFT + 'x')) {
789 elementaryContext->butt[0]->value(0);
790 elementaryContext->butt[1]->value(1);
791 elementaryContext->butt[2]->value(1);
792 status = 1;
793 }
794 else if(Fl::test_shortcut(FL_SHIFT + 'y')) {
795 elementaryContext->butt[0]->value(1);
796 elementaryContext->butt[1]->value(0);
797 elementaryContext->butt[2]->value(1);
798 status = 1;
799 }
800 else if(Fl::test_shortcut(FL_SHIFT + 'z')) {
801 elementaryContext->butt[0]->value(1);
802 elementaryContext->butt[1]->value(1);
803 elementaryContext->butt[2]->value(0);
804 status = 1;
805 }
806 else if(Fl::test_shortcut(FL_Escape) ||
807 Fl::test_shortcut(FL_META + FL_Escape) ||
808 Fl::test_shortcut(FL_SHIFT + FL_Escape) ||
809 Fl::test_shortcut(FL_CTRL + FL_Escape) ||
810 Fl::test_shortcut(FL_ALT + FL_Escape)) {
811 if(fullscreen->shown()) {
812 window_cb(nullptr, (void *)"fullscreen");
813 status = 1;
814 }
815 else {
816 bool lasso = false;
817 for(std::size_t i = 0; i < graph.size(); i++)
818 for(std::size_t j = 0; j < graph[i]->gl.size(); j++)
819 if(graph[i]->gl[j]->lassoMode) lasso = true;
820 if(lasso) {
821 for(std::size_t i = 0; i < graph.size(); i++)
822 for(std::size_t j = 0; j < graph[i]->gl.size(); j++)
823 graph[i]->gl[j]->lassoMode = false;
824 status = 2;
825 }
826 else {
827 status_options_cb(nullptr, (void *)"S");
828 status = 1;
829 }
830 }
831 }
832 else if(Fl::test_shortcut(FL_SHIFT + 'a')) {
833 window_cb(nullptr, (void *)"front");
834 status = 1;
835 }
836 else if(Fl::test_shortcut(FL_SHIFT + 'o')) {
837 general_options_cb(nullptr, nullptr);
838 status = 1;
839 }
840 else if(Fl::test_shortcut(FL_SHIFT + 'g')) {
841 geometry_options_cb(nullptr, nullptr);
842 status = 1;
843 }
844 else if(Fl::test_shortcut(FL_SHIFT + 'm')) {
845 mesh_options_cb(nullptr, nullptr);
846 status = 1;
847 }
848 else if(Fl::test_shortcut(FL_SHIFT + 's')) {
849 solver_options_cb(nullptr, nullptr);
850 status = 1;
851 }
852 else if(Fl::test_shortcut(FL_SHIFT + 'p')) {
853 post_options_cb(nullptr, nullptr);
854 status = 1;
855 }
856 else if(Fl::test_shortcut(FL_SHIFT + 'w')) {
857 view_options_cb(nullptr, (void *)-1);
858 status = 1;
859 }
860 else if(Fl::test_shortcut(FL_SHIFT + 'u')) {
861 if(PView::list.size()) {
862 if(options->view.index >= 0 &&
863 options->view.index < (int)PView::list.size())
864 plugins->show(options->view.index);
865 else
866 plugins->show(0);
867 }
868 status = 1;
869 }
870 else if(Fl::test_shortcut(FL_ALT + 'f')) {
871 opt_general_fast_redraw(0, GMSH_SET | GMSH_GUI,
872 !opt_general_fast_redraw(0, GMSH_GET, 0));
873 status = 2;
874 }
875 else if(Fl::test_shortcut(FL_ALT + 'b')) {
876 opt_general_draw_bounding_box(
877 0, GMSH_SET | GMSH_GUI, !opt_general_draw_bounding_box(0, GMSH_GET, 0));
878 status = 2;
879 }
880 else if(Fl::test_shortcut(FL_ALT + 'i')) {
881 for(std::size_t i = 0; i < PView::list.size(); i++)
882 if(opt_view_visible(i, GMSH_GET, 0))
883 opt_view_show_scale(i, GMSH_SET | GMSH_GUI,
884 !opt_view_show_scale(i, GMSH_GET, 0));
885 status = 2;
886 }
887 else if(Fl::test_shortcut(FL_ALT + 'c')) {
888 opt_general_color_scheme(0, GMSH_SET | GMSH_GUI,
889 opt_general_color_scheme(0, GMSH_GET, 0) + 1);
890 status = 2;
891 }
892 else if(Fl::test_shortcut(FL_ALT + FL_SHIFT + 'c')) {
893 for(std::size_t i = 0; i < PView::list.size(); i++)
894 if(opt_view_visible(i, GMSH_GET, 0))
895 opt_view_colormap_number(i, GMSH_SET | GMSH_GUI,
896 opt_view_colormap_number(i, GMSH_GET, 0) + 1);
897 status = 2;
898 }
899 else if(Fl::test_shortcut(FL_ALT + 'w')) {
900 opt_geometry_light(0, GMSH_SET | GMSH_GUI,
901 !opt_geometry_light(0, GMSH_GET, 0));
902 opt_mesh_light(0, GMSH_SET | GMSH_GUI, !opt_mesh_light(0, GMSH_GET, 0));
903 for(std::size_t i = 0; i < PView::list.size(); i++)
904 if(opt_view_visible(i, GMSH_GET, 0))
905 opt_view_light(i, GMSH_SET | GMSH_GUI, !opt_view_light(i, GMSH_GET, 0));
906 status = 2;
907 }
908 else if(Fl::test_shortcut(FL_ALT + 'x') ||
909 Fl::test_shortcut(FL_ALT + FL_SHIFT + 'x')) {
910 status_xyz1p_cb(nullptr, (void *)"x");
911 status = 1;
912 }
913 else if(Fl::test_shortcut(FL_ALT + 'y') ||
914 Fl::test_shortcut(FL_ALT + FL_SHIFT + 'y')) {
915 status_xyz1p_cb(nullptr, (void *)"y");
916 status = 1;
917 }
918 else if(Fl::test_shortcut(FL_ALT + 'z') ||
919 Fl::test_shortcut(FL_ALT + FL_SHIFT + 'z')) {
920 status_xyz1p_cb(nullptr, (void *)"z");
921 status = 1;
922 }
923 else if(Fl::test_shortcut(FL_ALT + '1') ||
924 Fl::test_shortcut(FL_ALT + FL_SHIFT + '1') ||
925 Fl::test_shortcut(FL_ALT + FL_CTRL + '1') ||
926 Fl::test_shortcut(FL_ALT + FL_META + '1')) {
927 status_xyz1p_cb(nullptr, (void *)"1:1");
928 status = 1;
929 }
930 else if(Fl::test_shortcut(FL_ALT + 'o')) {
931 status_options_cb(nullptr, (void *)"p");
932 status = 1;
933 }
934 else if(Fl::test_shortcut(FL_ALT + 'a')) {
935 opt_general_axes(0, GMSH_SET | GMSH_GUI,
936 opt_general_axes(0, GMSH_GET, 0) + 1);
937 for(std::size_t i = 0; i < PView::list.size(); i++)
938 if(opt_view_visible(i, GMSH_GET, 0))
939 opt_view_axes(i, GMSH_SET | GMSH_GUI,
940 opt_view_axes(i, GMSH_GET, 0) + 1);
941 status = 2;
942 }
943 else if(Fl::test_shortcut(FL_ALT + FL_SHIFT + 'a')) {
944 opt_general_small_axes(0, GMSH_SET | GMSH_GUI,
945 !opt_general_small_axes(0, GMSH_GET, 0));
946 status = 2;
947 }
948 else if(Fl::test_shortcut(FL_ALT + 'p')) {
949 opt_geometry_points(0, GMSH_SET | GMSH_GUI,
950 !opt_geometry_points(0, GMSH_GET, 0));
951 status = 2;
952 }
953 else if(Fl::test_shortcut(FL_ALT + 'l')) {
954 opt_geometry_curves(0, GMSH_SET | GMSH_GUI,
955 !opt_geometry_curves(0, GMSH_GET, 0));
956 status = 2;
957 }
958 else if(Fl::test_shortcut(FL_ALT + 's')) {
959 opt_geometry_surfaces(0, GMSH_SET | GMSH_GUI,
960 !opt_geometry_surfaces(0, GMSH_GET, 0));
961 status = 2;
962 }
963 else if(Fl::test_shortcut(FL_ALT + 'v')) {
964 opt_geometry_volumes(0, GMSH_SET | GMSH_GUI,
965 !opt_geometry_volumes(0, GMSH_GET, 0));
966 status = 2;
967 }
968 else if(Fl::test_shortcut(FL_ALT + FL_SHIFT + 'p')) {
969 opt_mesh_nodes(0, GMSH_SET | GMSH_GUI, !opt_mesh_nodes(0, GMSH_GET, 0));
970 status = 2;
971 }
972 else if(Fl::test_shortcut(FL_ALT + FL_SHIFT + 'l')) {
973 opt_mesh_lines(0, GMSH_SET | GMSH_GUI, !opt_mesh_lines(0, GMSH_GET, 0));
974 status = 2;
975 }
976 else if(Fl::test_shortcut(FL_ALT + FL_SHIFT + 's')) {
977 opt_mesh_surface_edges(0, GMSH_SET | GMSH_GUI,
978 !opt_mesh_surface_edges(0, GMSH_GET, 0));
979 status = 2;
980 }
981 else if(Fl::test_shortcut(FL_ALT + FL_SHIFT + 'v')) {
982 opt_mesh_volume_edges(0, GMSH_SET | GMSH_GUI,
983 !opt_mesh_volume_edges(0, GMSH_GET, 0));
984 status = 2;
985 }
986 else if(Fl::test_shortcut(FL_ALT + 'd')) {
987 opt_geometry_surface_type(0, GMSH_SET | GMSH_GUI,
988 opt_geometry_surface_type(0, GMSH_GET, 0) + 1);
989 status = 2;
990 }
991 else if(Fl::test_shortcut(FL_ALT + FL_SHIFT + 'd')) {
992 opt_mesh_surface_faces(0, GMSH_SET | GMSH_GUI,
993 !opt_mesh_surface_faces(0, GMSH_GET, 0));
994 status = 2;
995 }
996 else if(Fl::test_shortcut(FL_ALT + FL_SHIFT + 'b')) {
997 opt_mesh_volume_faces(0, GMSH_SET | GMSH_GUI,
998 !opt_mesh_volume_faces(0, GMSH_GET, 0));
999 status = 2;
1000 }
1001 else if(Fl::test_shortcut(FL_ALT + 'm')) {
1002 quick_access_cb(nullptr, (void *)"mesh_toggle");
1003 status = 2;
1004 }
1005 else if(Fl::test_shortcut(FL_ALT + 't')) {
1006 for(std::size_t i = 0; i < PView::list.size(); i++)
1007 if(opt_view_visible(i, GMSH_GET, 0)) {
1008 int t = opt_view_intervals_type(i, GMSH_GET, 0) + 1;
1009 if(t == 4) t = 1; // skip numeric display
1010 opt_view_intervals_type(i, GMSH_SET | GMSH_GUI, t);
1011 }
1012 status = 2;
1013 }
1014 else if(Fl::test_shortcut(FL_ALT + FL_SHIFT + 't')) {
1015 for(std::size_t i = 0; i < PView::list.size(); i++)
1016 if(opt_view_visible(i, GMSH_GET, 0))
1017 opt_view_intervals_type(i, GMSH_SET | GMSH_GUI,
1018 opt_view_intervals_type(i, GMSH_GET, 0) + 1);
1019 status = 2;
1020 }
1021 else if(Fl::test_shortcut(FL_ALT + 'r')) {
1022 for(std::size_t i = 0; i < PView::list.size(); i++)
1023 if(opt_view_visible(i, GMSH_GET, 0))
1024 opt_view_range_type(i, GMSH_SET | GMSH_GUI,
1025 opt_view_range_type(i, GMSH_GET, 0) + 1);
1026 status = 2;
1027 }
1028 else if(Fl::test_shortcut(FL_ALT + 'n')) {
1029 for(std::size_t i = 0; i < PView::list.size(); i++)
1030 if(opt_view_visible(i, GMSH_GET, 0))
1031 opt_view_draw_strings(i, GMSH_SET | GMSH_GUI,
1032 !opt_view_draw_strings(i, GMSH_GET, 0));
1033 status = 2;
1034 }
1035 else if(Fl::test_shortcut(FL_ALT + 'e') ||
1036 Fl::test_shortcut(FL_ALT + FL_SHIFT + 'e')) {
1037 for(std::size_t i = 0; i < PView::list.size(); i++)
1038 if(opt_view_visible(i, GMSH_GET, 0))
1039 opt_view_show_element(i, GMSH_SET | GMSH_GUI,
1040 !opt_view_show_element(i, GMSH_GET, 0));
1041 status = 2;
1042 }
1043 else if(Fl::test_shortcut(FL_ALT + 'h')) {
1044 static int show = 0;
1045 for(std::size_t i = 0; i < PView::list.size(); i++)
1046 opt_view_visible(i, GMSH_SET | GMSH_GUI, show);
1047 show = !show;
1048 status = 2;
1049 }
1050 else if(testArrowShortcuts()) {
1051 status = 1;
1052 }
1053
1054 #if defined(HAVE_TOUCHBAR)
1055 updateTouchBar();
1056 #endif
1057
1058 if(status == 2) {
1059 drawContext::global()->draw();
1060 return 1;
1061 }
1062 else if(status == 1)
1063 return 1;
1064 else
1065 return 0;
1066 }
1067
testArrowShortcuts()1068 int FlGui::testArrowShortcuts()
1069 {
1070 if(Fl::test_shortcut(FL_Left)) {
1071 status_play_manual(1, -CTX::instance()->post.animStep);
1072 return 1;
1073 }
1074 else if(Fl::test_shortcut(FL_Right)) {
1075 status_play_manual(1, CTX::instance()->post.animStep);
1076 return 1;
1077 }
1078 else if(Fl::test_shortcut(FL_Up)) {
1079 status_play_manual(0, -CTX::instance()->post.animStep);
1080 return 1;
1081 }
1082 else if(Fl::test_shortcut(FL_Down)) {
1083 status_play_manual(0, CTX::instance()->post.animStep);
1084 return 1;
1085 }
1086 #if defined(HAVE_POPPLER)
1087 else if(Fl::test_shortcut('u') || Fl::test_shortcut(FL_Page_Up)) {
1088 gmshPopplerWrapper::setCurrentPageDown();
1089 drawContext::global()->draw();
1090 return 1;
1091 }
1092 else if(Fl::test_shortcut('d') || Fl::test_shortcut(FL_Page_Down)) {
1093 gmshPopplerWrapper::setCurrentPageUp();
1094 drawContext::global()->draw();
1095 return 1;
1096 }
1097 #endif
1098 return 0;
1099 }
1100
setGraphicTitle(const std::string & title)1101 void FlGui::setGraphicTitle(const std::string &title)
1102 {
1103 for(std::size_t i = 0; i < graph.size(); i++) {
1104 std::ostringstream sstream;
1105 if(title.empty())
1106 sstream << "Gmsh";
1107 else if(!i)
1108 sstream << "Gmsh - " << title;
1109 else
1110 sstream << "Gmsh - " << title << " [" << i << "]";
1111 graph[i]->setTitle(sstream.str());
1112 }
1113 }
1114
updateViews(bool numberOfViewsHasChanged,bool deleteWidgets)1115 void FlGui::updateViews(bool numberOfViewsHasChanged, bool deleteWidgets)
1116 {
1117 for(std::size_t i = 0; i < graph.size(); i++) graph[i]->checkAnimButtons();
1118 if(numberOfViewsHasChanged) {
1119 if(onelab) onelab->rebuildTree(deleteWidgets);
1120 if(onelabContext) onelabContext->rebuild(deleteWidgets);
1121 options->resetBrowser();
1122 options->resetExternalViewList();
1123 fields->loadFieldViewList();
1124 plugins->resetViewBrowser();
1125 clipping->resetBrowser();
1126 }
1127 }
1128
updateFields()1129 void FlGui::updateFields()
1130 {
1131 fields->editField(GModel::current()->getFields()->get(fields->selected_id));
1132 }
1133
resetVisibility()1134 void FlGui::resetVisibility()
1135 {
1136 if(visibility->win->shown()) visibility_cb(nullptr, nullptr);
1137 if(help->options->shown()) help_options_cb(nullptr, nullptr);
1138 }
1139
getCurrentOpenglWindow()1140 openglWindow *FlGui::getCurrentOpenglWindow()
1141 {
1142 if(openglWindow::getLastHandled())
1143 return openglWindow::getLastHandled();
1144 else
1145 return graph[0]->gl[0];
1146 }
1147
setCurrentOpenglWindow(int which)1148 void FlGui::setCurrentOpenglWindow(int which)
1149 {
1150 int ii = 0;
1151 for(std::size_t i = 0; i < graph.size(); i++) {
1152 for(std::size_t j = 0; j < graph[i]->gl.size(); j++) {
1153 if(which == ii++) {
1154 openglWindow::setLastHandled(graph[i]->gl[j]);
1155 return;
1156 }
1157 }
1158 }
1159 openglWindow::setLastHandled(graph[0]->gl[0]);
1160 }
1161
splitCurrentOpenglWindow(char how,double ratio)1162 void FlGui::splitCurrentOpenglWindow(char how, double ratio)
1163 {
1164 openglWindow *g = getCurrentOpenglWindow();
1165 for(std::size_t i = 0; i < graph.size(); i++) {
1166 if(graph[i]->split(g, how, ratio)) break;
1167 }
1168 }
1169
copyCurrentOpenglWindowToClipboard()1170 void FlGui::copyCurrentOpenglWindowToClipboard()
1171 {
1172 #if defined(WIN32)
1173 GLint width = getCurrentOpenglWindow()->w();
1174 GLint height = getCurrentOpenglWindow()->h();
1175
1176 // lines have to be 32 bytes aligned, suppose 24 bits per pixel; just crop it
1177 width -= width % 4;
1178
1179 // get pixels
1180 PixelBuffer *buffer =
1181 new PixelBuffer(width, height, GL_RGB, GL_UNSIGNED_BYTE);
1182 buffer->fill(0);
1183 unsigned char *pixels = (unsigned char *)buffer->getPixels();
1184
1185 // swap R and B since Windows bitmap format is BGR
1186 int nBytes = 3 * width * height;
1187 for(int i = 0; i < nBytes; i += 3) {
1188 unsigned char tmp = pixels[i];
1189 pixels[i] = pixels[i + 2];
1190 pixels[i + 2] = tmp;
1191 }
1192
1193 // fill header
1194 BITMAPINFOHEADER header;
1195 header.biWidth = width;
1196 header.biHeight = height;
1197 header.biSizeImage = nBytes;
1198 header.biSize = 40;
1199 header.biPlanes = 1;
1200 header.biBitCount = 3 * 8;
1201 header.biCompression = BI_RGB;
1202 header.biXPelsPerMeter = 0;
1203 header.biYPelsPerMeter = 0;
1204 header.biClrUsed = 0;
1205 header.biClrImportant = 0;
1206
1207 // generate handle
1208 HANDLE handle =
1209 (HANDLE)::GlobalAlloc(GHND, sizeof(BITMAPINFOHEADER) + nBytes);
1210 if(handle != nullptr) {
1211 // lock handle
1212 char *pData = (char *)::GlobalLock((HGLOBAL)handle);
1213 // copy header and data
1214 memcpy(pData, &header, sizeof(BITMAPINFOHEADER));
1215 memcpy(pData + sizeof(BITMAPINFOHEADER), pixels, nBytes);
1216 // unlock
1217 ::GlobalUnlock((HGLOBAL)handle);
1218 // push DIB in clipboard
1219 OpenClipboard(nullptr);
1220 EmptyClipboard();
1221 SetClipboardData(CF_DIB, handle);
1222 CloseClipboard();
1223 }
1224
1225 delete buffer;
1226 #endif
1227 }
1228
getCurrentDrawContext()1229 drawContext *FlGui::getCurrentDrawContext()
1230 {
1231 return getCurrentOpenglWindow()->getDrawContext();
1232 }
1233
selectEntity(int type)1234 char FlGui::selectEntity(int type)
1235 {
1236 return getCurrentOpenglWindow()->selectEntity(
1237 type, selectedVertices, selectedEdges, selectedFaces, selectedRegions,
1238 selectedElements, selectedPoints, selectedViews);
1239 }
1240
setStatus(const std::string & msg,bool opengl)1241 void FlGui::setStatus(const std::string &msg, bool opengl)
1242 {
1243 if(Msg::GetThreadNum() > 0) return;
1244 if(!opengl) {
1245 _lastStatus = msg;
1246 static char buff[1024];
1247 std::string tmp = std::string(" ") + msg;
1248 int ne = Msg::GetErrorCount(), nw = Msg::GetWarningCount();
1249 if((ne || nw) && graph[0]->getMessageHeight() < FL_NORMAL_SIZE) {
1250 tmp += " - ";
1251 char n[128];
1252 sprintf(n, "%d", ne ? ne : nw);
1253 tmp += n;
1254 tmp += (ne > 1) ? " Errors" :
1255 ne ? " Error" :
1256 (nw > 1) ? " Warnings" :
1257 " Warning";
1258 tmp += " : Click to show messages [ ... ";
1259 tmp += (ne ? Msg::GetFirstError() : Msg::GetFirstWarning());
1260 tmp += " ... ]";
1261 }
1262 strncpy(buff, tmp.c_str(), sizeof(buff) - 1);
1263 buff[sizeof(buff) - 1] = '\0';
1264 for(std::size_t i = 0; i < graph.size(); i++) {
1265 graph[i]->getProgress()->label(buff);
1266 graph[i]->getProgress()->redraw();
1267 }
1268 }
1269 else {
1270 openglWindow *gl = getCurrentOpenglWindow();
1271 std::vector<std::string> m = SplitString(msg, '\n');
1272 if(m.size() > 0)
1273 gl->screenMessage[0] = m[0];
1274 else
1275 gl->screenMessage[0].clear();
1276 if(m.size() > 1)
1277 gl->screenMessage[1] = m[1];
1278 else
1279 gl->screenMessage[1].clear();
1280 drawContext::global()->draw();
1281 }
1282 }
1283
setLastStatus(int col)1284 void FlGui::setLastStatus(int col)
1285 {
1286 if(Msg::GetThreadNum() > 0) return;
1287 for(std::size_t i = 0; i < graph.size(); i++) {
1288 if(col >= 0 && graph[0]->getMessageHeight() < FL_NORMAL_SIZE) {
1289 if(CTX::instance()->guiColorScheme) // dark
1290 graph[i]->getProgress()->color(col);
1291 else
1292 graph[i]->getProgress()->labelcolor(col);
1293 }
1294 else {
1295 graph[i]->getProgress()->color(FL_BACKGROUND_COLOR);
1296 graph[i]->getProgress()->labelcolor(FL_FOREGROUND_COLOR);
1297 }
1298 }
1299 setStatus(_lastStatus);
1300 }
1301
setProgress(const std::string & msg,double val,double min,double max)1302 void FlGui::setProgress(const std::string &msg, double val, double min,
1303 double max)
1304 {
1305 if(Msg::GetThreadNum() > 0) return;
1306 for(std::size_t i = 0; i < FlGui::instance()->graph.size(); i++) {
1307 if(FlGui::instance()->graph[i]->getProgress()->value() != val)
1308 FlGui::instance()->graph[i]->getProgress()->value(val);
1309 if(FlGui::instance()->graph[i]->getProgress()->minimum() != min)
1310 FlGui::instance()->graph[i]->getProgress()->minimum(min);
1311 if(FlGui::instance()->graph[i]->getProgress()->maximum() != max)
1312 FlGui::instance()->graph[i]->getProgress()->maximum(max);
1313 }
1314 setStatus(msg);
1315 }
1316
storeCurrentWindowsInfo()1317 void FlGui::storeCurrentWindowsInfo()
1318 {
1319 CTX::instance()->glPosition[0] = graph[0]->getWindow()->x();
1320 CTX::instance()->glPosition[1] = graph[0]->getWindow()->y();
1321 CTX::instance()->glSize[0] = graph[0]->getGlWidth();
1322 CTX::instance()->glSize[1] = graph[0]->getGlHeight();
1323 CTX::instance()->msgSize = graph[0]->getMessageHeight() ?
1324 graph[0]->getMessageHeight() :
1325 CTX::instance()->msgSize;
1326 CTX::instance()->menuSize[0] = graph[0]->getMenuWidth();
1327 if(graph[0]->isMenuDetached()) {
1328 CTX::instance()->detachedMenu = 1;
1329 CTX::instance()->menuSize[1] = graph[0]->getMenuHeight();
1330 CTX::instance()->menuPosition[0] = graph[0]->getMenuPositionX();
1331 CTX::instance()->menuPosition[1] = graph[0]->getMenuPositionY();
1332 }
1333 else
1334 CTX::instance()->detachedMenu = 0;
1335 CTX::instance()->optPosition[0] = options->win->x();
1336 CTX::instance()->optPosition[1] = options->win->y();
1337 CTX::instance()->pluginPosition[0] = plugins->win->x();
1338 CTX::instance()->pluginPosition[1] = plugins->win->y();
1339 CTX::instance()->pluginSize[0] = plugins->win->w();
1340 CTX::instance()->pluginSize[1] = plugins->win->h();
1341 CTX::instance()->fieldPosition[0] = fields->win->x();
1342 CTX::instance()->fieldPosition[1] = fields->win->y();
1343 CTX::instance()->fieldSize[0] = fields->win->w();
1344 CTX::instance()->fieldSize[1] = fields->win->h();
1345 CTX::instance()->statPosition[0] = stats->win->x();
1346 CTX::instance()->statPosition[1] = stats->win->y();
1347 CTX::instance()->visPosition[0] = visibility->win->x();
1348 CTX::instance()->visPosition[1] = visibility->win->y();
1349 CTX::instance()->hotPosition[0] = highordertools->win->x();
1350 CTX::instance()->hotPosition[1] = highordertools->win->y();
1351 CTX::instance()->clipPosition[0] = clipping->win->x();
1352 CTX::instance()->clipPosition[1] = clipping->win->y();
1353 CTX::instance()->manipPosition[0] = manip->win->x();
1354 CTX::instance()->manipPosition[1] = manip->win->y();
1355 if(lastContextWindow == 4) {
1356 CTX::instance()->ctxPosition[0] = onelabContext->win->x();
1357 CTX::instance()->ctxPosition[1] = onelabContext->win->y();
1358 }
1359 else if(lastContextWindow == 3) {
1360 CTX::instance()->ctxPosition[0] = physicalContext->win->x();
1361 CTX::instance()->ctxPosition[1] = physicalContext->win->y();
1362 }
1363 else if(lastContextWindow == 2) {
1364 CTX::instance()->ctxPosition[0] = meshContext->win->x();
1365 CTX::instance()->ctxPosition[1] = meshContext->win->y();
1366 }
1367 else if(lastContextWindow == 1) {
1368 CTX::instance()->ctxPosition[0] = transformContext->win->x();
1369 CTX::instance()->ctxPosition[1] = transformContext->win->y();
1370 }
1371 else {
1372 CTX::instance()->ctxPosition[0] = elementaryContext->win->x();
1373 CTX::instance()->ctxPosition[1] = elementaryContext->win->y();
1374 }
1375 #if defined(HAVE_3M)
1376 storeWindowPosition3M();
1377 #endif
1378
1379 fileChooserGetPosition(&CTX::instance()->fileChooserPosition[0],
1380 &CTX::instance()->fileChooserPosition[1]);
1381 }
1382
1383 // Callbacks
1384
redraw_cb(Fl_Widget * w,void * data)1385 void redraw_cb(Fl_Widget *w, void *data) { drawContext::global()->draw(); }
1386
window_cb(Fl_Widget * w,void * data)1387 void window_cb(Fl_Widget *w, void *data)
1388 {
1389 static int oldx = 0, oldy = 0, oldw = 0, oldh = 0, zoom = 0, fullscreen = 0;
1390
1391 std::string str((const char *)data);
1392
1393 if(str == "minimize") {
1394 for(std::size_t i = 0; i < FlGui::instance()->graph.size(); i++)
1395 if(FlGui::instance()->graph[i]->getWindow()->shown())
1396 FlGui::instance()->graph[i]->getWindow()->iconize();
1397 if(FlGui::instance()->options->win->shown())
1398 FlGui::instance()->options->win->iconize();
1399 if(FlGui::instance()->plugins->win->shown())
1400 FlGui::instance()->plugins->win->iconize();
1401 if(FlGui::instance()->fields->win->shown())
1402 FlGui::instance()->fields->win->iconize();
1403 if(FlGui::instance()->visibility->win->shown())
1404 FlGui::instance()->visibility->win->iconize();
1405 if(FlGui::instance()->highordertools->win->shown())
1406 FlGui::instance()->highordertools->win->iconize();
1407 if(FlGui::instance()->clipping->win->shown())
1408 FlGui::instance()->clipping->win->iconize();
1409 if(FlGui::instance()->manip->win->shown())
1410 FlGui::instance()->manip->win->iconize();
1411 if(FlGui::instance()->stats->win->shown())
1412 FlGui::instance()->stats->win->iconize();
1413 }
1414 else if(str == "zoom") {
1415 if(!zoom) {
1416 oldx = FlGui::instance()->graph[0]->getWindow()->x();
1417 oldy = FlGui::instance()->graph[0]->getWindow()->y();
1418 oldw = FlGui::instance()->graph[0]->getWindow()->w();
1419 oldh = FlGui::instance()->graph[0]->getWindow()->h();
1420 FlGui::instance()->graph[0]->getWindow()->resize(Fl::x(), Fl::y(),
1421 Fl::w(), Fl::h());
1422 zoom = 1;
1423 }
1424 else {
1425 FlGui::instance()->graph[0]->getWindow()->resize(oldx, oldy, oldw, oldh);
1426 zoom = 0;
1427 }
1428 }
1429 else if(str == "fullscreen") {
1430 if(!fullscreen) {
1431 int x, y, w, h;
1432 Fl::screen_xywh(x, y, w, h);
1433 FlGui::instance()->fullscreen->resize(x, y, w, h);
1434 FlGui::instance()->fullscreen->valid(0);
1435 FlGui::instance()->fullscreen->show();
1436 FlGui::instance()->fullscreen->fullscreen();
1437 while(!FlGui::instance()->fullscreen->valid()) FlGui::wait();
1438 FlGui::instance()->fullscreen->getDrawContext()->copyViewAttributes(
1439 FlGui::instance()->getCurrentOpenglWindow()->getDrawContext());
1440 openglWindow::setLastHandled(FlGui::instance()->fullscreen);
1441 for(std::size_t i = 0; i < FlGui::instance()->graph.size(); i++)
1442 FlGui::instance()->graph[i]->getWindow()->hide();
1443 drawContext::global()->draw();
1444 fullscreen = 1;
1445 }
1446 else {
1447 for(std::size_t i = 0; i < FlGui::instance()->graph.size(); i++)
1448 FlGui::instance()->graph[i]->gl[0]->valid(0);
1449 for(std::size_t i = 0; i < FlGui::instance()->graph.size(); i++)
1450 FlGui::instance()->graph[i]->getWindow()->show();
1451 for(std::size_t i = 0; i < FlGui::instance()->graph.size(); i++)
1452 while(!FlGui::instance()->graph[i]->gl[0]->valid()) FlGui::wait();
1453 FlGui::instance()->graph[0]->gl[0]->getDrawContext()->copyViewAttributes(
1454 FlGui::instance()->getCurrentOpenglWindow()->getDrawContext());
1455 openglWindow::setLastHandled(FlGui::instance()->graph[0]->gl[0]);
1456 FlGui::instance()->fullscreen->fullscreen_off();
1457 FlGui::instance()->fullscreen->hide();
1458 drawContext::global()->draw();
1459 fullscreen = 0;
1460 }
1461 }
1462 else if(str == "front") {
1463 // the order is important!
1464 for(std::size_t i = 0; i < FlGui::instance()->graph.size(); i++)
1465 FlGui::instance()->graph[i]->getWindow()->show();
1466 if(FlGui::instance()->options->win->shown())
1467 FlGui::instance()->options->win->show();
1468 if(FlGui::instance()->plugins->win->shown())
1469 FlGui::instance()->plugins->win->show();
1470 if(FlGui::instance()->fields->win->shown())
1471 FlGui::instance()->fields->win->show();
1472 if(FlGui::instance()->elementaryContext->win->shown())
1473 FlGui::instance()->elementaryContext->win->show();
1474 if(FlGui::instance()->transformContext->win->shown())
1475 FlGui::instance()->transformContext->win->show();
1476 if(FlGui::instance()->physicalContext->win->shown())
1477 FlGui::instance()->physicalContext->win->show();
1478 if(FlGui::instance()->onelabContext->win->shown())
1479 FlGui::instance()->onelabContext->win->show();
1480 if(FlGui::instance()->meshContext->win->shown())
1481 FlGui::instance()->meshContext->win->show();
1482 if(FlGui::instance()->visibility->win->shown())
1483 FlGui::instance()->visibility->win->show();
1484 if(FlGui::instance()->highordertools->win->shown())
1485 FlGui::instance()->highordertools->win->show();
1486 if(FlGui::instance()->clipping->win->shown())
1487 FlGui::instance()->clipping->win->show();
1488 if(FlGui::instance()->manip->win->shown())
1489 FlGui::instance()->manip->win->show();
1490 if(FlGui::instance()->stats->win->shown())
1491 FlGui::instance()->stats->win->show();
1492 }
1493 }
1494
addMessage(const char * msg)1495 void FlGui::addMessage(const char *msg)
1496 {
1497 for(std::size_t i = 0; i < FlGui::instance()->graph.size(); i++) {
1498 FlGui::instance()->graph[i]->addMessage(msg);
1499 }
1500 }
1501
saveMessages(const char * fileName)1502 void FlGui::saveMessages(const char *fileName)
1503 {
1504 FlGui::instance()->graph[0]->saveMessages(fileName);
1505 }
1506
rebuildTree(bool deleteWidgets)1507 void FlGui::rebuildTree(bool deleteWidgets)
1508 {
1509 if(onelab) onelab->rebuildTree(deleteWidgets);
1510 if(onelabContext) onelabContext->rebuild(deleteWidgets);
1511 }
1512
openModule(const std::string & name)1513 void FlGui::openModule(const std::string &name)
1514 {
1515 if(!onelab) return;
1516 if(!onelab->isManuallyClosed("0Modules/" + name))
1517 onelab->openTreeItem("0Modules/" + name);
1518 }
1519
openTreeItem(const std::string & name)1520 void FlGui::openTreeItem(const std::string &name)
1521 {
1522 if(!onelab) return;
1523 onelab->openTreeItem(name);
1524 }
1525
closeTreeItem(const std::string & name)1526 void FlGui::closeTreeItem(const std::string &name)
1527 {
1528 if(!onelab) return;
1529 onelab->closeTreeItem(name);
1530 }
1531
showOnelabContext(int dim,int tag)1532 void FlGui::showOnelabContext(int dim, int tag)
1533 {
1534 if(!onelabContext) return;
1535 onelabContext->show(dim, tag);
1536 }
1537