GCC Code Coverage Report


Directory: ./
File: lib/geogram_gfx/gui/application.h
Date: 2026-09-07 02:28:19
Exec Total Coverage
Lines: 0 20 0.0%
Functions: 0 2 0.0%
Branches: 0 52 0.0%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2000-2022 Inria
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the ALICE Project-Team nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Contact: Bruno Levy
30 *
31 * https://www.inria.fr/fr/bruno-levy
32 *
33 * Inria,
34 * Domaine de Voluceau,
35 * 78150 Le Chesnay - Rocquencourt
36 * FRANCE
37 *
38 */
39
40 #ifndef H_GEOGRAM_GFX_GUI_APPLICATION_H
41 #define H_GEOGRAM_GFX_GUI_APPLICATION_H
42
43 #include <geogram_gfx/basic/common.h>
44 #include <geogram_gfx/gui/events.h>
45 #include <atomic>
46
47 #ifndef GEO_OS_ANDROID
48 # define GEO_GLFW
49 #endif
50
51 /**
52 * \file geogram_gfx/gui/application.h
53 * \brief Base class for all applications.
54 */
55
56 #ifdef GEO_OS_WINDOWS
57 #define GEO_APPLICATION_GLOBALS \
58 extern "C" { __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000000; }
59 #else
60 #define GEO_APPLICATION_GLOBALS
61 #endif
62
63 namespace GEO {
64
65 class Image;
66 class ApplicationData;
67
68 /**
69 * \brief Base class for all applications.
70 * \details This class handles the cross-platform creation of a window,
71 * OpenGL context, and ImGui. Client code may use SimpleApplication
72 * instead.
73 */
74 class GEOGRAM_GFX_API Application {
75 public:
76
77 /**
78 * \brief Application constructor.
79 * \param[in] name the name of the application
80 */
81 Application(const std::string& name);
82
83 /**
84 * \brief Application destructor.
85 */
86 virtual ~Application();
87
88 /**
89 * \brief Gets the instance.
90 * \return a pointer to the instance.
91 */
92 static Application* instance() {
93 return instance_;
94 }
95
96
97 /**
98 * \brief Gets the name of this application.
99 * \return the name.
100 */
101 const std::string& name() const {
102 return name_;
103 }
104
105
106 /**
107 * \brief Starts the main event loop of the application.
108 * \param[in] argc , argv optional command line parameters. If specified
109 * then they are used to initialize geogram, else geogram is supposed
110 * to be already initialized by caller.
111 */
112 virtual void start(int argc=0, char** argv=nullptr);
113
114 /**
115 * \brief Stops the application.
116 */
117 virtual void stop();
118
119 /**
120 * \brief Gets the style.
121 * \return a string with the current style;
122 */
123 const std::string& get_style() const {
124 return style_;
125 }
126
127 /**
128 * \brief Sets the style of the application.
129 * \param[in] value one of Dark, Light, DarkGray, LightGray
130 * \see get_styles()
131 */
132 virtual void set_style(const std::string& value);
133
134 /**
135 * \brief Gets the possible styles.
136 * \return A semi-colon separated list of the possible
137 * styles.
138 */
139 static std::string get_styles();
140
141 /**
142 * \brief Sets the font size.
143 * \param[in] value the font size.
144 */
145 void set_font_size(index_t value);
146
147 /**
148 * \brief Gets the font size.
149 * \return the font size.
150 */
151 index_t get_font_size() const {
152 return font_size_;
153 }
154
155 /**
156 * \brief Indicates that the main window should be redrawn.
157 */
158 virtual void update();
159
160 /**
161 * \brief Draws a dockspace that fills the current
162 * window.
163 */
164 void draw_dock_space();
165
166 /**
167 * \brief Lock updates.
168 * \details If this function is called, updates are ignored.
169 * It is useful when a RenderingContext operation is occuring, to
170 * prevent the Console for triggering a drawing operation.
171 */
172 void lock_updates() {
173 ++nb_update_locks_;
174 }
175
176 /**
177 * \brief Unlock updates.
178 */
179 void unlock_updates() {
180 // Note: Under Windows, when the Graphite window is iconified,
181 // it can happen that nb_update_locks_ is already 0 when
182 // reaching this point.
183 if(nb_update_locks_ > 0) {
184 --nb_update_locks_;
185 }
186 }
187
188 /**
189 * \brief Tests whether graphic updates are locked
190 * \details This function should be called before triggering graphic
191 * redraw to avoid reentrant calls in ImGUI functions, for instance
192 * when graphic redraw is triggered from Console or ProgressBar
193 * \see lock_updates(), unlock_updates()
194 * \return true if graphic updates are locked, false otherwise
195 */
196 bool updates_locked() const {
197 return (nb_update_locks_ > 0);
198 }
199
200 /**
201 * \brief Redraws the main window.
202 * \details This function is called by commands that animate
203 * objects during computation, by the progress bar and by
204 * console output.
205 */
206 virtual void draw();
207
208 /**
209 * \brief Gets the global scaling to be applied to all GUI elements.
210 * \return 1.0 if the default font is used, more/less if a larger/
211 * smaller font is used.
212 */
213 double scaling() const;
214
215 /**
216 * \brief Sets full-screen mode.
217 * \details All arguments to zero sets default mode.
218 * \param[in] w , h width and height in pixels
219 * \param[in] hz refresh rate in Hz
220 * \param[in] monitor the id of the monitor
221 */
222 void set_full_screen_mode(
223 index_t w=0, index_t h=0, index_t hz=0,
224 index_t monitor=0
225 );
226
227 /**
228 * \brief Sets windowed mode.
229 * \param[in] w , h width and height in pixels. If
230 * zero, use current dimensions.
231 */
232 void set_windowed_mode(index_t w=0, index_t h=0);
233
234 /**
235 * \brief Lists the video modes that can be used for
236 * set_full_screen_mode()
237 * \details The video modes are listed in the terminal.
238 */
239 void list_video_modes();
240
241 /**
242 * \brief Iconifies this application.
243 */
244 void iconify();
245
246 /**
247 * \brief Restores this application.
248 */
249 void restore();
250
251 /**
252 * \brief Sets the gui state.
253 * \param[in] x a string that encodes
254 * the windows geometries and docking configuration
255 * obtained through get_gui_state()
256 */
257 void set_gui_state(std::string x);
258
259 /**
260 * \brief Gets the gui state.
261 * \return a string that encodes
262 * the windows geometries and docking configuration
263 */
264 std::string get_gui_state() const;
265
266 /**
267 * \brief Sets full-screen mode.
268 * \param[in] x true if full-screen mode should be used,
269 * false if windowed-mode should be used.
270 */
271 void set_full_screen(bool x);
272
273 /**
274 * \brief Tests whether this application is in full-screen mode.
275 * \retval true if full-screen mode is used.
276 * \retval false if windowed mode is used.
277 */
278 bool get_full_screen() const;
279
280 /**
281 * \brief Gets the width of the window.
282 * \return the width of the window in pixels.
283 * \details important note: for OpenGL operations, use
284 * get_framebuffer_width() instead, that applies pixel scaling
285 * (MacOS/X retina non-sense)
286 */
287 index_t get_width() const {
288 return width_;
289 }
290
291 /**
292 * \brief Gets the height of the window.
293 * \return the height of the window in pixels.
294 * \details important note: for OpenGL operations, use
295 * get_framebuffer_height() instead, that applies pixel scaling
296 * (MacOS/X retina non-sense)
297 */
298 index_t get_height() const {
299 return height_;
300 }
301
302 /**
303 * \brief Gets the width of the frame buffer.
304 * \return the width of the frame buffer in pixels.
305 * \details On MacOSX, frame buffer can have a higher resolution than
306 * the window.
307 */
308 index_t get_frame_buffer_width() const {
309 return frame_buffer_width_;
310 }
311
312 /**
313 * \brief Gets the height of the frame buffer.
314 * \return the height of the frame buffer in pixels.
315 * \details On MacOSX, frame buffer can have a higher resolution than
316 * the window.
317 */
318 index_t get_frame_buffer_height() const {
319 return frame_buffer_height_;
320 }
321
322 /**
323 * \brief Sets whether drag and drop events should be
324 * taken into account.
325 * \param[in] value true if drag and drop events should be taken into
326 * account, false otherwise
327 */
328 void set_accept_drops(bool value) {
329 accept_drops_ = value;
330 }
331
332 /**
333 * \brief Tests whether drag and drop events are taken into
334 * account.
335 * \retval true if drag and drop events are taken into account
336 * \retval false otherwise
337 */
338 bool get_accept_drops() const {
339 return accept_drops_;
340 }
341
342 /**
343 * \brief Sets the icon of the window.
344 * \param[in] image a pointer to the image to be used as the icon.
345 */
346 void set_window_icon(Image* image);
347
348 /**
349 * \brief Callback called whenenver a mouse button changed.
350 * \param[in] button the button
351 * \param[in] action the action (one of
352 * EVENT_ACTION_UP, EVENT_ACTION_DOWN, EVENT_ACTION_DRAG)
353 * \param[in] mods the current key modifiers (not implemented yet)
354 * \param[in] source the event source (one of EVENT_SOURCE_MOUSE,
355 * EVENT_SOURCE_FINGER, EVENT_SOURCE_STYLUS)
356 */
357 virtual void mouse_button_callback(
358 int button, int action, int mods=0, int source=EVENT_SOURCE_MOUSE
359 );
360
361 /**
362 * \brief Callback called whenenver the mouse wheel is moved.
363 * \param[in] xoffset , yoffset wheel displacement
364 */
365 virtual void scroll_callback(double xoffset, double yoffset);
366
367 /**
368 * \brief Callback called whenever the mouse cursor is moved.
369 * \param[in] x , y the new position of the mouse cursor, in
370 * 'window pixels', with origin at top-left corner.
371 * \param[in] source the event source (one of EVENT_SOURCE_MOUSE,
372 * EVENT_SOURCE_FINGER, EVENT_SOURCE_STYLUS)
373 * \details The function divides by retina scaling internally
374 * to get OpenGL window coordinates (in framebuffer pixels)
375 * and flips the Y coordinate (origin at bottom-left corner).
376 */
377 virtual void cursor_pos_callback(
378 double x, double y, int source=EVENT_SOURCE_MOUSE
379 );
380
381 /**
382 * \brief Callback called whenever files are dropped in the window.
383 * \param[in] nb number of files.
384 * \param[in] f the array of file names.
385 */
386 virtual void drop_callback(int nb, const char** f);
387
388 /**
389 * \brief Callback called whenever a key is pushed (high level version)
390 * \param[in] c the ASCII code of the character that corresponds to the
391 * pushed key.
392 */
393 virtual void char_callback(unsigned int c);
394
395 /**
396 * \brief Callback called whenever a key is pushed (low level version)
397 * \param[in] key key code (window system specific)
398 * \param[in] scancode scan code (window system specific)
399 * \param[in] action push or release (window system specific)
400 * \param[in] mods current key modifieds (window system specific)
401 */
402 virtual void key_callback(int key, int scancode, int action, int mods);
403
404 /**
405 * \brief Restarts the gui.
406 * \details A flag is set and the gui is restarted at the next frame.
407 */
408 void restart_gui() {
409 ImGui_restart_ = true;
410 }
411
412 /**
413 * \brief Gets a pointer to the implementation-specific data.
414 * \details For internal use only.
415 * \return a pointer to the implementation-specific data.
416 */
417 ApplicationData* impl_data() {
418 return data_;
419 }
420
421 /**
422 * \brief Gets a pointer to the implementation-specific window.
423 * \details For internal use only.
424 * \return a pointer to the implementation-specific window.
425 */
426 void* impl_window();
427
428 /**
429 * \brief MacOS non-sense
430 * \details Computed as glfwGetFramebufferSize() / glfwGetWindowSize(),
431 * where FramebufferSize corresponds to OpenGL pixels (passed to glViewport)
432 * and WindowSize, the size of the window in screen coordinates. On Mac
433 * Retina screens they can differ.
434 * \return a scaling factor between real pixels and logical
435 * pixels or something, well I do not understand. Sometimes
436 * you need to multiply by it, sometimes to divide, and
437 * sometimes you need to use pixel_ratio() instead.
438 */
439 double hidpi_scaling() const {
440 return hidpi_scaling_;
441 }
442
443 /**
444 * \brief More MacOS non-sense
445 * \details Computed as glfwGetWindowContentScale(), that is, ratio between
446 * current DPI and platform's default DPI.
447 * \return something like hidpi_scaling(), that is a scaling
448 * factor between real pixels and logical
449 * pixels or something, well I do not understand.
450 * \details
451 * Sometimes you need to multiply by it, sometimes to divide,
452 * and sometimes you need to use hidpi_scaling() instead.
453 * If I understood well, frame buffer size corresponds to
454 * window size times pixel ratio.
455 */
456 double pixel_ratio() const {
457 return pixel_ratio_;
458 }
459
460 /**
461 * \brief Used internally.
462 */
463 void reset_soft_keyboard_flag() {
464 soft_keyboard_visible_ = false;
465 }
466
467 //protected:
468 public:
469
470 /**
471 * \brief Converts a key to a symbolic string with the name of the key.
472 * \param[in] key the key.
473 * \return a string with the symbolic name of the key.
474 */
475 const char* key_to_string(int key);
476
477 /**
478 * \brief This function is called when the GUI should be redisplayed.
479 * \details This function is meant to be overloaded by subclasses.
480 * default implementation does nothing.
481 */
482 virtual void draw_gui();
483
484 /**
485 * \brief This function is called when the 3d content should be
486 * redisplayed.
487 * \details This function is meant to be overloaded by subclasses.
488 * default implementation does nothing.
489 */
490 virtual void draw_graphics();
491
492 /**
493 * \brief This function is called before starting drawing operations.
494 * \details Some implementations use it to initialize / restore graphic
495 * objects.
496 */
497 virtual void pre_draw();
498
499 /**
500 * \brief This function is called after all drawing operations.
501 * \details It can be used to execute queued commands.
502 */
503 virtual void post_draw();
504
505 /**
506 * \brief Tests whether the window needs to be redrawn.
507 * \retval true if the window needs to be redrawn.
508 * \retval false if the window is up to date.
509 */
510 virtual bool needs_to_redraw() const;
511
512 /**
513 * \brief Creates the window using GLFW.
514 */
515 virtual void create_window();
516
517 /**
518 * \brief Deletes the window created by GLFW.
519 */
520 virtual void delete_window();
521
522 /**
523 * \brief Called whenever window size changes
524 * \param[in] w , h the new window width and height in pixels.
525 * \param[in] fb_w , fb_h the new framebuffer width and height in
526 * pixels.
527 * \details Called whenenver the size of the window does not
528 * match the current size.
529 */
530 virtual void resize(index_t w, index_t h, index_t fb_w, index_t fb_h);
531
532 /**
533 * \brief Draws one frame.
534 * \details This triggers a GUI and/or a scene update as needed.
535 */
536 virtual void one_frame(bool draw_GUI = true);
537
538 /**
539 * \brief Enters the main application loop.
540 * \details create_window() needs to be called before.
541 * This initializes OpenGL and ImGui before the first frame is
542 * displayed.
543 */
544 virtual void main_loop();
545
546 /**
547 * \brief Initializes OpenGL and GLUP objects.
548 */
549 virtual void GL_initialize();
550
551 /**
552 * \brief Deallocates OpenGL and GLUP objects.
553 */
554 virtual void GL_terminate();
555
556 /**
557 * \brief Initializes the ImGui library.
558 */
559 virtual void ImGui_initialize();
560
561 /**
562 * \brief Loads the fonts in ImGui.
563 */
564 virtual void ImGui_load_fonts();
565
566 /**
567 * \brief Deallocates objects used by the ImGui library.
568 */
569 virtual void ImGui_terminate();
570
571 /**
572 * \brief Notifies ImGui that a new frame has just started.
573 */
574 virtual void ImGui_new_frame();
575
576 /*
577 * \param[in] argc , argv command line parameters, used
578 * to initialize geogram.
579 */
580 virtual void geogram_initialize(int argc, char** argv);
581
582 /**
583 * \brief Called by geogram_initialize(), right before parsing
584 * command line arguments.
585 * \details Derived application class declare their args by overriding
586 * this function.
587 */
588 virtual void declare_args();
589
590 /**
591 * \brief Initializes the callbacks if not already initialized.
592 */
593 void callbacks_initialize();
594
595 /**
596 * \brief Gets all the filenames specified on the command line.
597 * \return a const reference to a vector of strings with the filenames.
598 */
599 const std::vector<std::string>& filenames() const {
600 return filenames_;
601 }
602
603 bool animate() const {
604 return animate_;
605 }
606
607 bool* animate_ptr() {
608 return &animate_;
609 }
610
611 void start_animation() {
612 animate_ = true;
613 }
614
615 void stop_animation() {
616 animate_ = false;
617 }
618
619 /**
620 * \Brief Used to emulate pre-v1.92 ImGUI API
621 */
622 float get_font_size(index_t font_id) const {
623 geo_assert(font_id < font_sizes_.size());
624 return font_sizes_[font_id];
625 }
626
627 /**
628 * \Brief Used to emulate pre-v1.92 ImGUI API
629 */
630 float get_font_global_scale() const {
631 return font_global_scale_;
632 }
633
634 /**
635 * \Brief Used to emulate pre-v1.92 ImGUI API
636 */
637 void set_font_global_scale(float s) {
638 font_global_scale_ = s;
639 }
640
641 private:
642 static Application* instance_; /**< a pointer to the instance */
643 ApplicationData* data_; /**< implementation dependent */
644 index_t width_; /**< window width */
645 index_t height_; /**< window height */
646 index_t frame_buffer_width_; /**< frame buffer width (glViewport) */
647 index_t frame_buffer_height_; /**< frame buffer height (glViewport) */
648 bool in_main_loop_; /**< main loop is running */
649 bool accept_drops_; /**< app. accepts dropping files */
650 double scaling_; /**< global scaling for to all sizes */
651 std::atomic<index_t> nb_update_locks_; /**< lock graphic updates */
652 std::string style_; /**< ImGui style (Dark, Light, ...) */
653 bool ImGui_restart_; /**< ImGui needs to be restarted */
654 bool ImGui_reload_font_; /**< font size has changed */
655 bool ImGui_initialized_; /**< ImGui was initialized */
656 index_t font_size_; /**< current font size */
657 index_t nb_frames_update_; /**< if 0, take a small sleep */
658 double hidpi_scaling_; /**< for retina displays */
659 double pixel_ratio_; /**< for retina displays */
660 std::string name_; /**< application name */
661 bool currently_drawing_gui_; /**< currently drawing ImGui elements */
662 std::vector<std::string> filenames_; /**< from the command line */
663 bool animate_; /**< true if drawing always */
664 vector<float> font_sizes_; /**< emulate pre-v1.92 ImGUI API*/
665 float font_global_scale_; /**< emulate pre-v1.92 ImGUI API*/
666
667 protected:
668 bool ImGui_firsttime_init_; /**< true if ImGui was once initialized */
669 bool menubar_visible_;
670 bool phone_screen_; /**< true if running on a phone */
671 bool soft_keyboard_visible_;
672
673 #ifdef GEO_OS_EMSCRIPTEN
674 friend void emscripten_one_frame();
675 #endif
676 };
677
678 }
679
680 #endif
681