1 /* 2 * Copyright (c) 2012-2016, Bruno Levy 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 * If you modify this software, you should include a notice giving the 30 * name of the person performing the modification, the date of modification, 31 * and the reason for such modification. 32 * 33 * Contact: Bruno Levy 34 * 35 * Bruno.Levy@inria.fr 36 * http://www.loria.fr/~levy 37 * 38 * ALICE Project 39 * LORIA, INRIA Lorraine, 40 * Campus Scientifique, BP 239 41 * 54506 VANDOEUVRE LES NANCY CEDEX 42 * FRANCE 43 * 44 */ 45 46 #ifndef H_GEOGRAM_GFX_GUI_APPLICATION_H 47 #define H_GEOGRAM_GFX_GUI_APPLICATION_H 48 49 #include <geogram_gfx/basic/common.h> 50 #include <geogram_gfx/gui/events.h> 51 52 #ifndef GEO_OS_ANDROID 53 # define GEO_GLFW 54 #endif 55 56 /** 57 * \file geogram_gfx/gui/application.h 58 * \brief Base class for all applications. 59 */ 60 61 namespace GEO { 62 63 class Image; 64 class ApplicationData; 65 66 /** 67 * \brief Base class for all applications. 68 * \details This class handles the cross-platform creation of a window, 69 * OpenGL context, and ImGui. Client code may use SimpleApplication 70 * instead. 71 */ 72 class GEOGRAM_GFX_API Application { 73 public: 74 75 /** 76 * \brief Application constructor. 77 * \param[in] name the name of the application 78 */ 79 Application(const std::string& name); 80 81 /** 82 * \brief Application destructor. 83 */ 84 virtual ~Application(); 85 86 /** 87 * \brief Gets the instance. 88 * \return a pointer to the instance. 89 */ instance()90 static Application* instance() { 91 return instance_; 92 } 93 94 95 /** 96 * \brief Gets the name of this application. 97 * \return the name. 98 */ name()99 const std::string& name() const { 100 return name_; 101 } 102 103 104 /** 105 * \brief Starts the main event loop of the application. 106 * \param[in] argc , argv optional command line parameters. If specified 107 * then they are used to initialize geogram, else geogram is supposed 108 * to be already initialized by caller. 109 */ 110 virtual void start(int argc=0, char** argv=nullptr); 111 112 /** 113 * \brief Stops the application. 114 */ 115 virtual void stop(); 116 117 /** 118 * \brief Gets the style. 119 * \return a string with the current style; 120 */ get_style()121 const std::string& get_style() const { 122 return style_; 123 } 124 125 /** 126 * \brief Sets the style of the application. 127 * \param[in] value one of Dark, Light, DarkGray, LightGray 128 * \see get_styles() 129 */ 130 virtual void set_style(const std::string& value); 131 132 /** 133 * \brief Gets the possible styles. 134 * \return A semi-colon separated list of the possible 135 * styles. 136 */ 137 static std::string get_styles(); 138 139 /** 140 * \brief Sets the font size. 141 * \param[in] value the font size. 142 */ 143 void set_font_size(index_t value); 144 145 /** 146 * \brief Gets the font size. 147 * \return the font size. 148 */ get_font_size()149 index_t get_font_size() const { 150 return font_size_; 151 } 152 153 /** 154 * \brief Indicates that the main window should be redrawn. 155 */ 156 virtual void update(); 157 158 /** 159 * \brief Draws a dockspace that fills the current 160 * window. 161 */ 162 void draw_dock_space(); 163 164 /** 165 * \brief Lock updates. 166 * \details If this function is called, updates are ignored. 167 * It is useful when a RenderingContext operation is occuring, to 168 * prevent the Console for triggering a drawing operation. 169 */ lock_updates()170 void lock_updates() { 171 ++nb_update_locks_; 172 } 173 174 /** 175 * \brief Unlock updates. 176 */ unlock_updates()177 void unlock_updates() { 178 // Note: Under Windows, when the Graphite window is iconified, 179 // it can happen that nb_update_locks_ is already 0 when 180 // reaching this point. 181 if(nb_update_locks_ > 0) { 182 --nb_update_locks_; 183 } 184 } 185 186 /** 187 * \brief Redraws the main window. 188 * \details This function is called by commands that animate 189 * objects during computation, by the progress bar and by 190 * console output. 191 */ 192 virtual void draw(); 193 194 /** 195 * \brief Gets the global scaling to be applied to all GUI elements. 196 * \return 1.0 if the default font is used, more/less if a larger/ 197 * smaller font is used. 198 */ 199 double scaling() const; 200 201 /** 202 * \brief Sets full-screen mode. 203 * \details All arguments to zero sets default mode. 204 * \param[in] w , h width and height in pixels 205 * \param[in] hz refresh rate in Hz 206 * \param[in] monitor the id of the monitor 207 */ 208 void set_full_screen_mode( 209 index_t w=0, index_t h=0, index_t hz=0, 210 index_t monitor=0 211 ); 212 213 /** 214 * \brief Sets windowed mode. 215 * \param[in] w , h width and height in pixels. If 216 * zero, use current dimensions. 217 */ 218 void set_windowed_mode(index_t w=0, index_t h=0); 219 220 /** 221 * \brief Lists the video modes that can be used for 222 * set_full_screen_mode() 223 * \details The video modes are listed in the terminal. 224 */ 225 void list_video_modes(); 226 227 /** 228 * \brief Iconifies this application. 229 */ 230 void iconify(); 231 232 /** 233 * \brief Restores this application. 234 */ 235 void restore(); 236 237 /** 238 * \brief Sets the gui state. 239 * \param[in] x a string that encodes 240 * the windows geometries and docking configuration 241 * obtained through get_gui_state() 242 */ 243 void set_gui_state(std::string x); 244 245 /** 246 * \brief Gets the gui state. 247 * \return a string that encodes 248 * the windows geometries and docking configuration 249 */ 250 std::string get_gui_state() const; 251 252 /** 253 * \brief Sets full-screen mode. 254 * \param[in] x true if full-screen mode should be used, 255 * false if windowed-mode should be used. 256 */ 257 void set_full_screen(bool x); 258 259 /** 260 * \brief Tests whether this application is in full-screen mode. 261 * \retval true if full-screen mode is used. 262 * \retval false if windowed mode is used. 263 */ 264 bool get_full_screen() const; 265 266 /** 267 * \brief Gets the width of the window. 268 * \return the width of the window in pixels. 269 */ get_width()270 index_t get_width() const { 271 return width_; 272 } 273 274 /** 275 * \brief Gets the height of the window. 276 * \return the height of the window in pixels. 277 */ get_height()278 index_t get_height() const { 279 return height_; 280 } 281 282 /** 283 * \brief Gets the width of the window. 284 * \return the width of the frame buffer in pixels. 285 */ get_frame_buffer_width()286 index_t get_frame_buffer_width() const { 287 return frame_buffer_width_; 288 } 289 290 /** 291 * \brief Gets the height of the window. 292 * \return the height of the frame buffer in pixels. 293 */ get_frame_buffer_height()294 index_t get_frame_buffer_height() const { 295 return frame_buffer_height_; 296 } 297 298 /** 299 * \brief Sets whether drag and drop events should be 300 * taken into account. 301 * \param[in] value true if drag and drop events should be taken into 302 * account, false otherwise 303 */ set_accept_drops(bool value)304 void set_accept_drops(bool value) { 305 accept_drops_ = value; 306 } 307 308 /** 309 * \brief Tests whether drag and drop events are taken into 310 * account. 311 * \retval true if drag and drop events are taken into account 312 * \retval false otherwise 313 */ get_accept_drops()314 bool get_accept_drops() const { 315 return accept_drops_; 316 } 317 318 /** 319 * \brief Sets the icon of the window. 320 * \param[in] image a pointer to the image to be used as the icon. 321 */ 322 void set_window_icon(Image* image); 323 324 /** 325 * \brief Callback called whenenver a mouse button changed. 326 * \param[in] button the button 327 * \param[in] action the action (one of 328 * EVENT_ACTION_UP, EVENT_ACTION_DOWN, EVENT_ACTION_DRAG) 329 * \param[in] mods the current key modifiers (not implemented yet) 330 * \param[in] source the event source (one of EVENT_SOURCE_MOUSE, 331 * EVENT_SOURCE_FINGER, EVENT_SOURCE_STYLUS) 332 */ 333 virtual void mouse_button_callback( 334 int button, int action, int mods=0, int source=EVENT_SOURCE_MOUSE 335 ); 336 337 /** 338 * \brief Callback called whenenver the mouse wheel is moved. 339 * \param[in] xoffset , yoffset wheel displacement 340 */ 341 virtual void scroll_callback(double xoffset, double yoffset); 342 343 /** 344 * \brief Callback called whenever the mouse cursor is moved. 345 * \param[in] x , y the new position of the mouse cursor. 346 * \param[in] source the event source (one of EVENT_SOURCE_MOUSE, 347 * EVENT_SOURCE_FINGER, EVENT_SOURCE_STYLUS) 348 */ 349 virtual void cursor_pos_callback( 350 double x, double y, int source=EVENT_SOURCE_MOUSE 351 ); 352 353 /** 354 * \brief Callback called whenever files are dropped in the window. 355 * \param[in] nb number of files. 356 * \param[in] f the array of file names. 357 */ 358 virtual void drop_callback(int nb, const char** f); 359 360 /** 361 * \brief Callback called whenever a key is pushed (high level version) 362 * \param[in] c the ASCII code of the character that corresponds to the 363 * pushed key. 364 */ 365 virtual void char_callback(unsigned int c); 366 367 /** 368 * \brief Callback called whenever a key is pushed (low level version) 369 * \param[in] key key code (window system specific) 370 * \param[in] scancode scan code (window system specific) 371 * \param[in] action push or release (window system specific) 372 * \param[in] mods current key modifieds (window system specific) 373 */ 374 virtual void key_callback(int key, int scancode, int action, int mods); 375 376 /** 377 * \brief Restarts the gui. 378 * \details A flag is set and the gui is restarted at the next frame. 379 */ restart_gui()380 void restart_gui() { 381 ImGui_restart_ = true; 382 } 383 384 /** 385 * \brief Gets a pointer to the implementation-specific data. 386 * \details For internal use only. 387 * \return a pointer to the implementation-specific data. 388 */ impl_data()389 ApplicationData* impl_data() { 390 return data_; 391 } 392 393 /** 394 * \brief Gets a pointer to the implementation-specific window. 395 * \details For internal use only. 396 * \return a pointer to the implementation-specific window. 397 */ 398 void* impl_window(); 399 400 /** 401 * \brief MacOS non-sense 402 * \return a scaling factor between real pixels and logical 403 * pixels or something, well I do not understand. Sometimes 404 * you need to multiply by it, sometimes to divide, and 405 * sometimes you need to use pixel_ratio() instead. 406 */ hidpi_scaling()407 double hidpi_scaling() const { 408 return hidpi_scaling_; 409 } 410 411 /** 412 * \brief More MacOS non-sense 413 * \return something like hidpi_scaling(), that is a scaling 414 * factor between real pixels and logical 415 * pixels or something, well I do not understand. 416 * Sometimes you need to multiply by it, sometimes to divide, 417 * and sometimes you need to use hidpi_scaling() instead. 418 */ pixel_ratio()419 double pixel_ratio() const { 420 return pixel_ratio_; 421 } 422 423 /** 424 * \brief Used internally. 425 */ reset_soft_keyboard_flag()426 void reset_soft_keyboard_flag() { 427 soft_keyboard_visible_ = false; 428 } 429 430 protected: 431 432 /** 433 * \brief Converts a key to a symbolic string with the name of the key. 434 * \param[in] key the key. 435 * \return a string with the symbolic name of the key. 436 */ 437 const char* key_to_string(int key); 438 439 /** 440 * \brief This function is called when the GUI should be redisplayed. 441 * \details This function is meant to be overloaded by subclasses. 442 * default implementation does nothing. 443 */ 444 virtual void draw_gui(); 445 446 /** 447 * \brief This function is called when the 3d content should be 448 * redisplayed. 449 * \details This function is meant to be overloaded by subclasses. 450 * default implementation does nothing. 451 */ 452 virtual void draw_graphics(); 453 454 /** 455 * \brief This function is called before starting drawing operations. 456 * \details Some implementations use it to initialize / restore graphic 457 * objects. 458 */ 459 virtual void pre_draw(); 460 461 /** 462 * \brief This function is called after all drawing operations. 463 * \details It can be used to execute queued commands. 464 */ 465 virtual void post_draw(); 466 467 /** 468 * \brief Tests whether the window needs to be redrawn. 469 * \retval true if the window needs to be redrawn. 470 * \retval false if the window is up to date. 471 */ 472 virtual bool needs_to_redraw() const; 473 474 /** 475 * \brief Creates the window using GLFW. 476 */ 477 virtual void create_window(); 478 479 /** 480 * \brief Deletes the window created by GLFW. 481 */ 482 virtual void delete_window(); 483 484 /** 485 * \brief Called whenever window size changes 486 * \param[in] w , h the new window width and height in pixels. 487 * \param[in] fb_w , fb_h the new framebuffer width and height in 488 * pixels. 489 * \details Called whenenver the size of the window does not 490 * match the current size. 491 */ 492 virtual void resize(index_t w, index_t h, index_t fb_w, index_t fb_h); 493 494 /** 495 * \brief Draws one frame. 496 * \details This triggers a GUI and/or a scene update as needed. 497 */ 498 virtual void one_frame(); 499 500 /** 501 * \brief Enters the main application loop. 502 * \details create_window() needs to be called before. 503 * This initializes OpenGL and ImGui before the first frame is 504 * displayed. 505 */ 506 virtual void main_loop(); 507 508 /** 509 * \brief Initializes OpenGL and GLUP objects. 510 */ 511 virtual void GL_initialize(); 512 513 /** 514 * \brief Deallocates OpenGL and GLUP objects. 515 */ 516 virtual void GL_terminate(); 517 518 /** 519 * \brief Initializes the ImGui library. 520 */ 521 virtual void ImGui_initialize(); 522 523 /** 524 * \brief Loads the fonts in ImGui. 525 */ 526 virtual void ImGui_load_fonts(); 527 528 /** 529 * \brief Deallocates objects used by the ImGui library. 530 */ 531 virtual void ImGui_terminate(); 532 533 /** 534 * \brief Notifies ImGui that a new frame has just started. 535 */ 536 virtual void ImGui_new_frame(); 537 538 /* 539 * \param[in] argc , argv command line parameters, used 540 * to initialize geogram. 541 */ 542 virtual void geogram_initialize(int argc, char** argv); 543 544 /** 545 * \brief Initializes the callbacks if not already initialized. 546 */ 547 void callbacks_initialize(); 548 549 /** 550 * \brief Gets all the filenames specified on the command line. 551 * \return a const reference to a vector of strings with the filenames. 552 */ filenames()553 const std::vector<std::string>& filenames() const { 554 return filenames_; 555 } 556 animate()557 bool animate() const { 558 return animate_; 559 } 560 animate_ptr()561 bool* animate_ptr() { 562 return &animate_; 563 } 564 start_animation()565 void start_animation() { 566 animate_ = true; 567 } 568 stop_animation()569 void stop_animation() { 570 animate_ = false; 571 } 572 573 private: 574 static Application* instance_; /**< a pointer to the instance */ 575 ApplicationData* data_; /**< implementation dependent */ 576 index_t width_; /**< window width */ 577 index_t height_; /**< window height */ 578 index_t frame_buffer_width_; /**< frame buffer width (glViewport) */ 579 index_t frame_buffer_height_; /**< frame buffer height (glViewport) */ 580 bool in_main_loop_; /**< main loop is running */ 581 bool accept_drops_; /**< app. accepts dropping files */ 582 double scaling_; /**< global scaling for to all sizes */ 583 index_t nb_update_locks_; /**< lock graphic updates */ 584 std::string style_; /**< ImGui style (Dark, Light, ...) */ 585 bool ImGui_restart_; /**< ImGui needs to be restarted */ 586 bool ImGui_reload_font_; /**< font size has changed */ 587 bool ImGui_initialized_; /**< ImGui was initialized */ 588 index_t font_size_; /**< current font size */ 589 index_t nb_frames_update_; /**< if 0, take a small sleep */ 590 double hidpi_scaling_; /**< for retina displays */ 591 double pixel_ratio_; /**< for retina displays */ 592 std::string name_; /**< application name */ 593 bool currently_drawing_gui_; /**< currently drawing ImGui elements */ 594 std::vector<std::string> filenames_; /**< from the command line */ 595 bool animate_; /**< true if drawing always */ 596 597 598 protected: 599 bool ImGui_firsttime_init_; /**< true if ImGui was once initialized */ 600 bool menubar_visible_; 601 bool phone_screen_; /**< true if running on a phone */ 602 bool soft_keyboard_visible_; 603 604 #ifdef GEO_OS_EMSCRIPTEN 605 friend void emscripten_one_frame(); 606 #endif 607 }; 608 609 } 610 611 #endif 612 613