1 // Copyright (C) 2005 Davis E. King (davis@dlib.net), Keita Mochizuki 2 // License: Boost Software License See LICENSE.txt for the full license. 3 #undef DLIB_GUI_CORE_KERNEl_ABSTRACT_ 4 #ifdef DLIB_GUI_CORE_KERNEl_ABSTRACT_ 5 6 #include <string> 7 #include "../algs.h" 8 #include "../geometry/rectangle_abstract.h" 9 #include "../unicode/unicode_abstract.h" 10 11 namespace dlib 12 { 13 14 /*! 15 OVERVIEW: 16 This is a set of objects and functions which provide a very basic 17 framework for manipulating windows. It is intended to provide a 18 portable interface which can be used to build a more complex windowing 19 toolkit. 20 21 EXCEPTIONS 22 Do not let an exception leave any of the base_window event handlers. 23 The results of doing so are undefined. 24 25 THREAD SAFETY 26 Event Handlers 27 All event handlers are executed in a special event handling thread. 28 This means that you must not do anything that will take a long time or 29 block while in an event handler. Doing so will freeze all event 30 processing. 31 32 Also, don't rely on get_thread_id() always returning the same ID from 33 inside event handlers. 34 35 canvas 36 Never access a canvas object outside of the paint() callback 37 that supplied it. Only access a canvas object from the event 38 handling thread. After the paint() event handler has returned do 39 not access that canvas object again. 40 41 base_window 42 All methods for this class are thread safe. You may call them 43 from any thread and do not need to serialize access. 44 !*/ 45 46 // ---------------------------------------------------------------------------------------- 47 48 void put_on_clipboard ( 49 const std::string& str 50 ); 51 /*! 52 ensures 53 - posts the contents of str to the system clipboard 54 throws 55 - std::bad_alloc 56 - dlib::gui_error 57 - dlib::thread_error 58 !*/ 59 60 // overloads for wide character strings 61 void put_on_clipboard (const std::wstring& str); 62 void put_on_clipboard (const dlib::ustring& str); 63 64 // ---------------------------------------------------------------------------------------- 65 66 void get_from_clipboard ( 67 std::string& str 68 ); 69 /*! 70 ensures 71 - if (there is string data on the system clipboard) then 72 - #str == the data from the clipboard 73 - else 74 - #str == "" 75 throws 76 - std::bad_alloc 77 - dlib::gui_error 78 - dlib::thread_error 79 !*/ 80 81 // overloads for wide character strings 82 void get_from_clipboard (std::wtring& str); 83 void get_from_clipboard (dlib::utring& str); 84 85 // ---------------------------------------------------------------------------------------- 86 87 88 class canvas : public rectangle 89 { 90 /*! 91 POINTERS AND REFERENCES TO INTERNAL DATA 92 All functions of this object may invalidate pointers and references 93 to internal data. 94 95 INITIAL VALUE 96 The initial value of each pixel is undefined. 97 is_empty() == false 98 99 WHAT THIS OBJECT REPRESENTS 100 This object represents a rectangular area of a window that you 101 can draw on. 102 103 Each pixel can be accessed with the following syntax: 104 canvas_instance[y][x].red == the red value for this pixel 105 canvas_instance[y][x].blue == the blue value for this pixel 106 canvas_instance[y][x].green == the green value for this pixel 107 108 The origin, i.e. (0,0), of the x,y coordinate plane of the canvas is in 109 the upper left corner of the canvas. Note that the upper left corner 110 of the canvas appears at the point (left(),top()) in its window. 111 !*/ 112 113 public: 114 115 struct pixel 116 { 117 /*! 118 WHAT THIS OBJECT REPRESENTS 119 This object represents a single pixel. Each pixel's value 120 ranges from 0 to 255 with 0 indicating that the color is not 121 present in the pixel at all and 255 indicating that the color 122 is present in the pixel with maximum intensity. 123 124 Note that the structure, order, and size of this struct are 125 implementation dependent. It will always contain fields called 126 red, green, and blue but they may not be in that order and there 127 may be padding. 128 129 Also note that pixel_traits<> is defined for this pixel type, 130 thus you can use it in assign_pixel() calls. 131 !*/ 132 unsigned char red; 133 unsigned char green; 134 unsigned char blue; 135 }; 136 137 138 pixel* operator[] ( 139 unsigned long row 140 ) const; 141 /*! 142 requires 143 - row < height() 144 ensures 145 - returns an array of width() pixel structs that represents the given 146 row of pixels in the canvas. 147 !*/ 148 149 void fill ( 150 unsigned char red, 151 unsigned char green, 152 unsigned char blue 153 ) const; 154 /*! 155 ensures 156 - for all valid values of x and y: 157 - (#*this)[y][x].red = red 158 - (#*this)[y][x].green = green 159 - (#*this)[y][x].blue = blue 160 !*/ 161 162 private: 163 164 // restricted functions 165 canvas(); // normal constructor 166 canvas(canvas&); // copy constructor 167 canvas& operator=(canvas&); // assignment operator 168 }; 169 170 // ---------------------------------------------------------------------------------------- 171 172 class base_window 173 { 174 175 /*! 176 WHAT THIS OBJECT REPRESENTS 177 This object represents a window on the desktop. A window has a "client 178 area" that is a region of the screen that you can draw whatever you like 179 on. You implement the paint() callback and use the canvas object to do 180 this drawing. 181 182 INITIAL STATE 183 - The initial state of the window is to be hidden. This means you need 184 to call show() to make it appear. 185 - is_closed() == false 186 187 paint() callback: 188 This is where you will do all your drawing. It is triggered when 189 part of the window needs to be drawn/redrawn. 190 191 mouse events: 192 It is important to note a few things about the mouse events. First, 193 the on_mouse_move() event is not triggered for each pixel the mouse crosses 194 but rather its frequency and precision is implementation dependent. 195 196 Second, it is possible that a mouse button may be depressed but the 197 corresponding button release event does not go to the window. For instance, 198 if the mouse is outside the window and some other application jumps to the 199 top it is possible that the new application will receive any mouse button 200 release events rather than the original window. But the point is that 201 you should not rely on always getting a button up event for every button 202 down event. 203 204 keydown event: 205 Note that the existence of a typematic action (holding down a key 206 and having it start to repeat itself after a moment) for each key is 207 totally implementation dependent. So don't rely on it for any key 208 and conversely don't assume it isn't present either. 209 210 The base_window::wm mutex 211 This is a reference to a global rmutex. All instances of base_window make 212 reference to the same global rmutex. It is used to synchronize access to 213 the base_window to make it thread safe. It is also always locked before 214 an event handler is called. 215 !*/ 216 217 public: 218 219 enum on_close_return_code 220 { 221 DO_NOT_CLOSE_WINDOW, 222 CLOSE_WINDOW 223 }; 224 225 enum mouse_state_masks 226 { 227 /*! 228 These constants represent the various buttons referenced by 229 mouse events. 230 !*/ 231 NONE = 0, 232 LEFT = 1, 233 RIGHT = 2, 234 MIDDLE = 4, 235 SHIFT = 8, 236 CONTROL = 16 237 }; 238 239 enum keyboard_state_masks 240 { 241 /*! 242 These constants represent the various modifier buttons that 243 could be in effect during a key press on the keyboard 244 !*/ 245 KBD_MOD_NONE = 0, 246 KBD_MOD_SHIFT = 1, 247 KBD_MOD_CONTROL = 2, 248 KBD_MOD_ALT = 4, 249 KBD_MOD_META = 8, 250 KBD_MOD_CAPS_LOCK = 16, 251 KBD_MOD_NUM_LOCK = 32, 252 KBD_MOD_SCROLL_LOCK = 64 253 }; 254 255 enum non_printable_keyboard_keys 256 { 257 KEY_BACKSPACE, 258 KEY_SHIFT, 259 KEY_CTRL, 260 KEY_ALT, 261 KEY_PAUSE, 262 KEY_CAPS_LOCK, 263 KEY_ESC, 264 KEY_PAGE_UP, 265 KEY_PAGE_DOWN, 266 KEY_END, 267 KEY_HOME, 268 KEY_LEFT, // This is the left arrow key 269 KEY_RIGHT, // This is the right arrow key 270 KEY_UP, // This is the up arrow key 271 KEY_DOWN, // This is the down arrow key 272 KEY_INSERT, 273 KEY_DELETE, 274 KEY_SCROLL_LOCK, 275 276 // Function Keys 277 KEY_F1, 278 KEY_F2, 279 KEY_F3, 280 KEY_F4, 281 KEY_F5, 282 KEY_F6, 283 KEY_F7, 284 KEY_F8, 285 KEY_F9, 286 KEY_F10, 287 KEY_F11, 288 KEY_F12 289 }; 290 291 base_window ( 292 bool resizable = true, 293 bool undecorated = false 294 ); 295 /*! 296 requires 297 - if (undecorated == true) then 298 - resizable == false 299 ensures 300 - #*this has been properly initialized 301 - if (resizable == true) then 302 - this window will be resizable by the user 303 - else 304 - this window will not be resizable by the user 305 - if (undecorated == true) then 306 - this window will not have any graphical elements outside 307 of its drawable area or appear in the system task bar. It 308 also won't take the input focus from other windows. 309 (it is suitable for making things such as popup menus) 310 throws 311 - std::bad_alloc 312 - dlib::thread_error 313 - dlib::gui_error 314 This exception is thrown if there is an error while 315 creating this window. 316 !*/ 317 318 virtual ~base_window ( 319 ); 320 /*! 321 ensures 322 - does NOT trigger the on_window_close() event 323 - all resources associated with *this have been released 324 - closes this window 325 !*/ 326 327 void close_window ( 328 ); 329 /*! 330 ensures 331 - #is_closed() == true 332 (i.e. permanently closes this window. The window is removed from the 333 screen and no more events will be dispatched to this window. ) 334 - does NOT trigger the on_window_close() event 335 !*/ 336 337 void wait_until_closed ( 338 ) const; 339 /*! 340 ensures 341 - blocks until is_closed() == true 342 !*/ 343 344 bool is_closed ( 345 ) const; 346 /*! 347 ensures 348 - returns true if this window has been closed, false otherwise. 349 (Note that closed windows do not receive any callbacks at all. 350 They are also not visible on the screen.) 351 !*/ 352 353 void set_title ( 354 const std::string& title 355 ); 356 /*! 357 ensures 358 - if (is_closed() == false) then 359 - sets the title of the window 360 !*/ 361 362 void set_title ( 363 const std::wstring& title 364 ); 365 /*! 366 ensures 367 - if (is_closed() == false) then 368 - sets the title of the window 369 !*/ 370 371 void set_title ( 372 const dlib::ustring& title 373 ); 374 /*! 375 ensures 376 - if (is_closed() == false) then 377 - sets the title of the window 378 !*/ 379 380 virtual void show ( 381 ); 382 /*! 383 ensures 384 - if (is_closed() == false) then 385 - this window will appear on the screen 386 !*/ 387 388 virtual void hide( 389 ); 390 /*! 391 ensures 392 - if (is_closed() == false) then 393 - the window does not appear on the screen 394 !*/ 395 396 void set_size ( 397 int width, 398 int height 399 ); 400 /*! 401 ensures 402 - if (is_closed() == false) then 403 - The width of the client area of this window is at least width 404 pixels. 405 - The height of the client area of this window is at least height 406 pixels. 407 - if (the window wasn't already this size) then 408 - triggers the on_window_resized() callback 409 !*/ 410 411 void set_pos ( 412 long x, 413 long y 414 ); 415 /*! 416 ensures 417 - if (is_closed() == false) then 418 - sets the upper left corner of this window to the position (x,y) 419 on the desktop. Note that the origin (0,0) is at the upper left 420 corner of the desktop. 421 !*/ 422 423 void get_pos ( 424 long& x, 425 long& y 426 ) const; 427 /*! 428 ensures 429 - if (is_closed() == false) then 430 - #x == the x coordinate of the upper left corner of the client area of 431 this window. 432 - #y == the y coordinate of the upper left corner of the client area of 433 this window. 434 - i.e. the point (#x,#y) on the desktop is coincident with the point 435 (0,0) in the client area of this window. 436 - else 437 - #x == 0 438 - #y == 0 439 !*/ 440 441 void get_size ( 442 unsigned long& width, 443 unsigned long& height 444 ) const; 445 /*! 446 ensures 447 - if (is_closed() == false) then 448 - #width == the width of the client area of this window in pixels 449 - #height == the height of the client area of this window in pixels 450 - else 451 - #width == 0 452 - #height == 0 453 !*/ 454 455 void get_display_size ( 456 unsigned long& width, 457 unsigned long& height 458 ) const; 459 /*! 460 ensures 461 - if (is_closed() == false) then 462 - #width == the width in pixels of the display device that contains this window 463 - #height == the height in pixels of the display device that contains this window 464 - else 465 - #width == 0 466 - #height == 0 467 !*/ 468 469 void invalidate_rectangle ( 470 const rectangle& rect 471 ); 472 /*! 473 ensures 474 - if (is_closed() == false) then 475 - causes the area of this window defined by rect to become invalid. 476 This means that a paint() message will be dispatched to repaint 477 this area of the window. Note that it is possible that the 478 resulting paint() message may include a bigger rectangle than 479 the one defined by rect. 480 !*/ 481 482 void trigger_user_event ( 483 void* p, 484 int i 485 ); 486 /*! 487 ensures 488 - will never block (even if some other thread has a lock on the 489 global mutex referenced by wm.) 490 - if (is_closed() == false) then 491 - causes the on_user_event() event to be called with 492 the given arguments. 493 !*/ 494 495 void set_im_pos ( 496 long x_, 497 long y_ 498 ); 499 /*! 500 ensures 501 - if (is_closed() == false) then 502 - sets the left-top position of input method rectangle used 503 for wide character input methods. 504 !*/ 505 506 protected: 507 const rmutex& wm; 508 509 // let the window close by default on_window_close()510 virtual on_close_return_code on_window_close( 511 ){return CLOSE_WINDOW;} 512 /*! 513 requires 514 - is_closed() == false 515 - mutex wm is locked 516 - is called when the user attempts to close this window 517 - if (this function returns CLOSE_WINDOW) then 518 - #is_closed() == true (i.e. this window will be closed) 519 - it is safe to call "delete this;" inside on_window_close() 520 if *this was allocated on the heap and no one will try to 521 access *this anymore. 522 - else 523 - this window will not be closed and the attempt to close it 524 by the user will have no effect. 525 - #is_closed() == false 526 ensures 527 - does not change the state of mutex wm 528 !*/ 529 530 // do nothing by default on_user_event(void * p,int i)531 virtual void on_user_event ( 532 void* p, 533 int i 534 ){} 535 /*! 536 requires 537 - is_closed() == false 538 - mutex wm is locked 539 - is called whenever someone calls trigger_user_event() 540 ensures 541 - does not change the state of mutex wm 542 !*/ 543 544 // do nothing by default on_window_resized()545 virtual void on_window_resized( 546 ){} 547 /*! 548 requires 549 - is_closed() == false 550 - mutex wm is locked 551 - is called when this window is resized 552 ensures 553 - does not change the state of mutex wm 554 !*/ 555 556 // do nothing by default on_window_moved()557 virtual void on_window_moved( 558 ){} 559 /*! 560 requires 561 - is_closed() == false 562 - mutex wm is locked 563 - is called when this window's position changes 564 ensures 565 - does not change the state of mutex wm 566 !*/ 567 568 // do nothing by default on_mouse_down(unsigned long btn,unsigned long state,long x,long y,bool is_double_click)569 virtual void on_mouse_down ( 570 unsigned long btn, 571 unsigned long state, 572 long x, 573 long y, 574 bool is_double_click 575 ){} 576 /*! 577 requires 578 - is_closed() == false 579 - mutex wm is locked 580 - is called when the user depresses one of the mouse buttons 581 - btn == the button that was depressed. (either LEFT, MIDDLE, or RIGHT) 582 - state == the bitwise OR of the buttons that are currently depressed 583 excluding the button given by btn. (from the mouse_state_masks enum) 584 - (x,y) == the position of the mouse (relative to the upper left corner 585 of the window) when this event occurred. Note that the mouse may be 586 outside the window. 587 - if (this is the second button press of a double click) then 588 - is_double_click == true 589 - else 590 - is_double_click == false 591 ensures 592 - does not change the state of mutex wm 593 !*/ 594 595 // do nothing by default on_mouse_up(unsigned long btn,unsigned long state,long x,long y)596 virtual void on_mouse_up ( 597 unsigned long btn, 598 unsigned long state, 599 long x, 600 long y 601 ){} 602 /*! 603 requires 604 - is_closed() == false 605 - mutex wm is locked 606 - is called when the user releases one of the mouse buttons 607 - btn == the button that was released. (either LEFT, MIDDLE, or RIGHT) 608 - state == the bitwise OR of the buttons that are currently depressed 609 (from the mouse_state_masks enum) 610 - (x,y) == the position of the mouse (relative to the upper left corner 611 of the window) when this event occurred. Note that the mouse may be 612 outside the window. 613 ensures 614 - does not change the state of mutex wm 615 !*/ 616 617 // do nothing by default on_mouse_move(unsigned long state,long x,long y)618 virtual void on_mouse_move ( 619 unsigned long state, 620 long x, 621 long y 622 ){} 623 /*! 624 requires 625 - is_closed() == false 626 - mutex wm is locked 627 - is called when the user moves the mouse 628 - state == the bitwise OR of the buttons that are currently depressed 629 (from the mouse_state_masks enum) 630 - (x,y) == the position of the mouse (relative to the upper left corner 631 of the window) when this event occurred. 632 - if (the user is holding down one or more of the mouse buttons) then 633 - the mouse move events will continue to track the mouse even if 634 it goes out of the window. This will continue until the user 635 releases all the mouse buttons. 636 ensures 637 - does not change the state of mutex wm 638 !*/ 639 640 // do nothing by default on_mouse_leave()641 virtual void on_mouse_leave ( 642 ){} 643 /*! 644 requires 645 - is_closed() == false 646 - mutex wm is locked 647 - is called when the mouse leaves this window 648 ensures 649 - does not change the state of mutex wm 650 !*/ 651 652 // do nothing by default on_mouse_enter()653 virtual void on_mouse_enter ( 654 ){} 655 /*! 656 requires 657 - is_closed() == false 658 - mutex wm is locked 659 - is called when the mouse enters this window 660 ensures 661 - does not change the state of mutex wm 662 !*/ 663 664 // do nothing by default on_focus_gained()665 virtual void on_focus_gained ( 666 ){} 667 /*! 668 requires 669 - is_closed() == false 670 - mutex wm is locked 671 - is called when this window gains input focus 672 ensures 673 - does not change the state of mutex wm 674 !*/ 675 676 // do nothing by default on_focus_lost()677 virtual void on_focus_lost ( 678 ){} 679 /*! 680 requires 681 - is_closed() == false 682 - mutex wm is locked 683 - is called when this window loses input focus 684 ensures 685 - does not change the state of mutex wm 686 !*/ 687 688 // do nothing by default on_wheel_up(unsigned long state)689 virtual void on_wheel_up ( 690 unsigned long state 691 ){} 692 /*! 693 requires 694 - is_closed() == false 695 - mutex wm is locked 696 - is called every time the mouse wheel is scrolled up one notch 697 - state == the bitwise OR of the buttons that are currently depressed 698 (from the mouse_state_masks enum) 699 ensures 700 - does not change the state of mutex wm 701 !*/ 702 703 // do nothing by default on_wheel_down(unsigned long state)704 virtual void on_wheel_down ( 705 unsigned long state 706 ){} 707 /*! 708 requires 709 - is_closed() == false 710 - mutex wm is locked 711 - is called every time the mouse wheel is scrolled down one notch 712 - state == the bitwise OR of the buttons that are currently depressed 713 (from the mouse_state_masks enum) 714 ensures 715 - does not change the state of mutex wm 716 !*/ 717 718 // do nothing by default on_keydown(unsigned long key,bool is_printable,unsigned long state)719 virtual void on_keydown ( 720 unsigned long key, 721 bool is_printable, 722 unsigned long state 723 ){} 724 /*! 725 requires 726 - is_closed() == false 727 - mutex wm is locked 728 - is called when a keyboard key is pressed or if a key is held 729 down then this is called repeatedly at a certain rate once the 730 typematic action begins (note that some keys might not have any 731 typematic action on some platforms). 732 - if (is_printable) then 733 - key == the character that was pressed. (e.g. 'a', 'b', '1' etc.) 734 - this is a printable character. Note that ' ', '\t', and 735 '\n' (this is the return/enter key) are all considered printable. 736 - else 737 - key == one of the non_printable_keyboard_keys enums. 738 - state == the bitwise OR of the keyboard modifiers that are currently 739 depressed (taken from keyboard_state_masks). 740 - if (key is not in the range 'a' to 'z' or 'A' to 'Z') then 741 - if (the shift key was down when this key was pressed) then 742 - (state & KBD_MOD_SHIFT) != 0 743 - else 744 - (state & KBD_MOD_SHIFT) == 0 745 - else 746 - the state of the shift key is implementation defined 747 ensures 748 - does not change the state of mutex wm 749 !*/ 750 on_string_put(const std::wstring & str)751 virtual void on_string_put ( 752 const std::wstring &str 753 ){} 754 /*! 755 requires 756 - is_closed() == false 757 - mutex wm is locked 758 - is called when a wide/multibyte character input method determines a string 759 that is being input to the window. 760 - str == the string that is being input 761 ensures 762 - does not change the state of mutex wm 763 !*/ 764 765 private: 766 767 virtual void paint ( 768 const canvas& c 769 ) =0; 770 /*! 771 requires 772 - is_closed() == false 773 - mutex wm is locked 774 - is called when part of the window needs to be repainted for 775 any reason. 776 - c == a canvas object that represents the invalid area of this 777 window which needs to be painted. 778 ensures 779 - does not change the state of mutex wm 780 !*/ 781 782 base_window(base_window&); // copy constructor 783 base_window& operator=(base_window&); // assignment operator 784 785 }; 786 787 // ---------------------------------------------------------------------------------------- 788 789 } 790 791 #endif // DLIB_GUI_CORE_KERNEl_ABSTRACT_ 792 793