1 // Copyright (C) 2005 Davis E. King (davis@dlib.net) 2 // License: Boost Software License See LICENSE.txt for the full license. 3 4 #undef DLIB_DRAWABLe_ABSTRACT_ 5 #ifdef DLIB_DRAWABLe_ABSTRACT_ 6 7 #include "../gui_core.h" 8 #include "fonts_abstract.h" 9 #include "canvas_drawing_abstract.h" 10 11 namespace dlib 12 { 13 14 /*! 15 GENERAL REMARKS 16 This file defines the drawable interface class and the drawable_window which 17 is just a window that is capable of displaying drawable objects (i.e. objects 18 that implement the drawable interface). 19 20 The drawable interface is a simple framework for creating more complex 21 graphical widgets. It provides a default set of functionality and a 22 set of events which a gui widget may use. 23 24 THREAD SAFETY 25 All objects and functions defined in this file are thread safe. You may 26 call them from any thread without serializing access to them. 27 !*/ 28 29 // ---------------------------------------------------------------------------------------- 30 // ---------------------------------------------------------------------------------------- 31 // class drawable_window 32 // ---------------------------------------------------------------------------------------- 33 // ---------------------------------------------------------------------------------------- 34 35 class drawable_window : public base_window 36 { 37 /*! 38 WHAT THIS OBJECT REPRESENTS 39 This object represents a window on the desktop that is capable of 40 containing drawable objects. 41 42 INITIAL STATE 43 The initial state of the drawable_window is to be hidden. This means 44 you need to call show() to make it appear. 45 46 EVENTS 47 The drawable_window object uses all the events provided by base_window 48 except for the on_window_close() event. This means that if you 49 define handlers for these events yourself you will have to call 50 the drawable_window's version of them so that the drawable_window 51 can continue to process and forward these events to its drawable 52 objects. 53 !*/ 54 public: 55 56 drawable_window ( 57 bool resizable = true, 58 bool undecorated = false 59 ); 60 /*! 61 requires 62 - if (undecorated == true) then 63 - resizable == false 64 ensures 65 - #*this has been properly initialized 66 - #background_color() == rgb_pixel(212,208,200) 67 - if (resizable == true) then 68 - this window will be resizable by the user 69 - else 70 - this window will not be resizable by the user 71 - if (undecorated == true) then 72 - this window will not have any graphical elements outside 73 of its drawable area or appear in the system task bar. 74 (e.g. a popup menu) 75 throws 76 - std::bad_alloc 77 - dlib::thread_error 78 - dlib::gui_error 79 This exception is thrown if there is an error while 80 creating this window. 81 !*/ 82 83 virtual ~drawable_window( 84 )=0; 85 /*! 86 ensures 87 - if (this window has not already been closed) then 88 - closes the window 89 - does NOT trigger the on_window_close() event 90 - all resources associated with *this have been released 91 !*/ 92 93 void set_background_color ( 94 unsigned long red, 95 unsigned long green, 96 unsigned long blue 97 ); 98 /*! 99 ensures 100 - #background_color().red == red 101 - #background_color().green == green 102 - #background_color().blue == blue 103 !*/ 104 105 rgb_pixel background_color ( 106 ) const; 107 /*! 108 ensures 109 - returns the background color this window paints its canvas 110 with before it passes it onto its drawable widgets 111 !*/ 112 113 private: 114 // restricted functions 115 drawable_window(drawable_window&); // copy constructor 116 drawable_window& operator=(drawable_window&); // assignment operator 117 118 friend class drawable; 119 }; 120 121 // ---------------------------------------------------------------------------------------- 122 // ---------------------------------------------------------------------------------------- 123 // class drawable 124 // ---------------------------------------------------------------------------------------- 125 // ---------------------------------------------------------------------------------------- 126 127 enum 128 { 129 MOUSE_MOVE = 1, 130 MOUSE_CLICK = 2, 131 MOUSE_WHEEL = 4, 132 WINDOW_RESIZED = 8, 133 KEYBOARD_EVENTS = 16, 134 FOCUS_EVENTS = 32, 135 WINDOW_MOVED = 64, 136 STRING_PUT = 128 137 }; 138 139 class drawable 140 { 141 /*! 142 INITIAL VALUE 143 top() == 0 144 left() == 0 145 right() == -1 146 bottom() == -1 147 get_rect().is_empty() == true 148 is_hidden() == false 149 is_enabled() == true 150 z_order() == 0 151 main_font() == default_font::get_font() 152 153 WHAT THIS OBJECT REPRESENTS 154 This is an interface that all drawable widgets implement. It 155 provides a standard method (draw()) to draw a widget onto a canvas 156 and many other convenient functions for drawable objects. 157 158 EVENT FORWARDING 159 All the events that come to a drawable object are forwarded from its 160 parent window. Additionally, there is no filtering. This means that 161 if a drawable registers to receive a certain kind of event then whenever 162 its parent window receives that event the drawable object will get a 163 forwarded copy of it as well even if the event occurred outside the 164 drawable's rectangle. 165 166 The only events that have anything in the way of filtering are the 167 draw() and on_user_event() events. draw() is only called on a drawable 168 object when that object is not hidden. on_user_event() is only called 169 for drawables that the on_user_event()'s first argument specifically 170 references. All other events are not filtered at all though. 171 172 Z ORDER 173 Z order defines the order in which drawable objects are drawn. The 174 lower numbered drawables are drawn first and then the higher numbered 175 ones. So a drawable with a z order of 0 is drawn before one with a 176 z order of 1 and so on. 177 !*/ 178 179 public: 180 181 friend class drawable_window; 182 183 drawable ( 184 drawable_window& w, 185 unsigned long events = 0 186 ) : 187 m(w.wm), 188 parent(w), 189 hidden(false), 190 enabled(true) 191 {} 192 /*! 193 ensures 194 - #*this is properly initialized 195 - #parent_window() == w 196 - #*this will not receive any events or draw() requests until 197 enable_events() is called 198 - once events_are_enabled() == true this drawable will receive 199 the on_user_event() event. (i.e. you always get this event, you don't 200 have to enable it by setting something in the events bitset). 201 - if (events & MOUSE_MOVE) then 202 - once events_are_enabled() == true this drawable will receive 203 the following events related to mouse movement: on_mouse_move, 204 on_mouse_leave, and on_mouse_enter. 205 - if (events & MOUSE_CLICK) then 206 - once events_are_enabled() == true this drawable will receive 207 the following events related to mouse clicks: on_mouse_down and 208 on_mouse_up. 209 - if (events & MOUSE_WHEEL) then 210 - once events_are_enabled() == true this drawable will receive 211 the following events related to mouse wheel scrolling: 212 on_wheel_up and on_wheel_down. 213 - if (events & WINDOW_RESIZED) then 214 - once events_are_enabled() == true this drawable will receive 215 the following event related to its parent window resizing: 216 on_window_resized. 217 - if (events & KEYBOARD_EVENTS) then 218 - once events_are_enabled() == true this drawable will receive 219 the following keyboard event: on_keydown. 220 - if (events & FOCUS_EVENTS) then 221 - once events_are_enabled() == true this drawable will receive 222 the following focus events: on_focus_gained and on_focus_lost. 223 - if (events & WINDOW_MOVED) then 224 - once events_are_enabled() == true this drawable will receive 225 the following event related to its parent window moving: 226 on_window_moved. 227 - if (events & STRING_PUT) then 228 - once events_are_enabled() == true this drawable will receive 229 the following event related to wide character string input: 230 on_string_put. 231 throws 232 - std::bad_alloc 233 - dlib::thread_error 234 !*/ 235 236 virtual ~drawable ( 237 ); 238 /*! 239 requires 240 - events_are_enabled() == false 241 ensures 242 - any resources associated with *this have been released 243 - *this has been removed from its containing window parent_window() and 244 its parent window will no longer try to dispatch events to it. 245 Note that this does not trigger a redraw of the parent window. If you 246 want to do that you must do it yourself. 247 !*/ 248 249 long z_order ( 250 ) const; 251 /*! 252 ensures 253 - returns the z order for this drawable. 254 !*/ 255 256 virtual void set_z_order ( 257 long order 258 ); 259 /*! 260 ensures 261 - #z_order() == order 262 - if (events_are_enabled() == true) then 263 - parent_window() is updated to reflect the new state of #*this 264 throws 265 - std::bad_alloc 266 !*/ 267 268 const rectangle get_rect ( 269 ) const; 270 /*! 271 ensures 272 - returns the rectangle that defines the area and position of this 273 drawable inside its containing window parent_window(). 274 !*/ 275 276 long bottom ( 277 ) const; 278 /*! 279 ensures 280 - returns get_rect().bottom() 281 !*/ 282 283 long top ( 284 ) const; 285 /*! 286 ensures 287 - returns get_rect().top() 288 !*/ 289 290 long left ( 291 ) const; 292 /*! 293 ensures 294 - returns get_rect().left() 295 !*/ 296 297 long right ( 298 ) const; 299 /*! 300 ensures 301 - returns get_rect().right() 302 !*/ 303 304 unsigned long width ( 305 ) const; 306 /*! 307 ensures 308 - returns get_rect().width() 309 !*/ 310 311 unsigned long height ( 312 ) const; 313 /*! 314 ensures 315 - returns get_rect().height() 316 !*/ 317 318 virtual void set_pos ( 319 long x, 320 long y 321 ); 322 /*! 323 ensures 324 - #top() == y 325 - #left() == x 326 - #width() == width() 327 - #height() == height() 328 - if (events_are_enabled() == true) then 329 - parent_window() is updated to reflect the new state of #*this 330 - i.e. This just sets the upper left corner of this drawable to the 331 location (x,y) 332 !*/ 333 334 bool is_enabled ( 335 ) const; 336 /*! 337 ensures 338 - returns true if this object is enabled and false otherwise. 339 (it is up to derived classes to define exactly what it means to be 340 "enabled") 341 !*/ 342 343 virtual void enable ( 344 ); 345 /*! 346 ensures 347 - #is_enabled() == true 348 - if (events_are_enabled() == true) then 349 - parent_window() is updated to reflect the new state of #*this 350 !*/ 351 352 virtual void disable ( 353 ); 354 /*! 355 ensures 356 - #is_enabled() == false 357 - if (events_are_enabled() == true) then 358 - parent_window() is updated to reflect the new state of #*this 359 !*/ 360 361 virtual void set_main_font ( 362 const shared_ptr_thread_safe<font>& f 363 ); 364 /*! 365 ensures 366 - #main_font() == f 367 - if (events_are_enabled() == true) then 368 - parent_window() is updated to reflect the new state of #*this 369 !*/ 370 371 const shared_ptr_thread_safe<font> main_font ( 372 ) const; 373 /*! 374 ensures 375 - returns the current main font being used by this widget 376 !*/ 377 378 bool is_hidden ( 379 ) const; 380 /*! 381 ensures 382 - returns true if this object is NOT currently displayed on parent_window() 383 and false otherwise. 384 !*/ 385 386 virtual void show ( 387 ); 388 /*! 389 ensures 390 - #is_hidden() == false 391 - if (events_are_enabled() == true) then 392 - parent_window() is updated to reflect the new state of #*this 393 !*/ 394 395 virtual void hide ( 396 ); 397 /*! 398 ensures 399 - #is_hidden() == true 400 - if (events_are_enabled() == true) then 401 - parent_window() is updated to reflect the new state of #*this 402 !*/ 403 404 drawable_window& parent_window ( 405 ); 406 /*! 407 ensures 408 - returns a reference to the drawable_window that this drawable is 409 being drawn on and receiving events from. 410 !*/ 411 412 const drawable_window& parent_window ( 413 ) const; 414 /*! 415 ensures 416 - returns a const reference to the drawable_window that this drawable 417 is being drawn on and receiving events from. 418 !*/ 419 next_free_user_event_number()420 virtual int next_free_user_event_number ( 421 )const { return 0; } 422 /*! 423 ensures 424 - returns the smallest number, i, that is the next user event number you 425 can use in calls to parent.trigger_user_event((void*)this,i). 426 - This function exists because of the following scenario. Suppose 427 you make a class called derived1 that inherits from drawable and 428 in derived1 you use a user event to do something. Then suppose 429 you inherit from derived1 to make derived2. Now in derived2 you 430 may want to use a user event to do something as well. How are you 431 to know which user event numbers are in use already? This function 432 solves that problem. You would define derived1::next_free_user_event_number() 433 so that it returned a number bigger than any user event numbers used by 434 derived1 or its ancestors. Then derived2 could just call 435 derived1::next_free_user_event_number() to find out what numbers it could use. 436 !*/ 437 438 protected: 439 /*!A drawable_protected_variables 440 441 These protected members are provided because they are needed to 442 implement drawable widgets. 443 !*/ 444 445 // This is the rectangle that is returned by get_rect() 446 rectangle rect; 447 448 // This is the mutex used to serialize access to this class. 449 const rmutex& m; 450 451 // This is the parent window of this drawable 452 drawable_window& parent; 453 454 // This is the bool returned by is_hidden() 455 bool hidden; 456 457 // This is the bool returned by is_enabled() 458 bool enabled; 459 460 // This is the font pointer returned by main_font() 461 shared_ptr_thread_safe<font> mfont; 462 463 // This is the x coordinate that we last saw the mouse at or -1 if the mouse 464 // is outside the parent window. 465 const long& lastx; 466 467 // This is the y coordinate that we last saw the mouse at or -1 if the mouse 468 // is outside the parent window. 469 const long& lasty; 470 471 472 void enable_events ( 473 ); 474 /*! 475 ensures 476 - #events_are_enabled() == true 477 !*/ 478 479 void disable_events ( 480 ); 481 /*! 482 ensures 483 - #events_are_enabled() == false 484 !*/ 485 486 bool events_are_enabled ( 487 ) const; 488 /*! 489 ensures 490 - returns true if this object is receiving events and draw() 491 requests from its parent window. 492 - returns false otherwise 493 !*/ 494 495 // ---------------- EVENT HANDLERS ------------------ 496 on_user_event(int i)497 virtual void on_user_event ( 498 int i 499 ){} 500 /*! 501 requires 502 - events_are_enabled() == true 503 - mutex m is locked 504 - is called whenever the parent window receives an on_user_event(p,i) event 505 where p == this. (i.e. this is just a redirect of on_user_event for 506 cases where the first argument of on_user_event is equal to the 507 this pointer). 508 ensures 509 - does not change the state of mutex m. 510 !*/ 511 on_window_resized()512 virtual void on_window_resized( 513 ){} 514 /*! 515 requires 516 - events_are_enabled() == true 517 - mutex m is locked 518 - this is just the base_window::on_window_resized() event forwarded to 519 this object. See the gui_core specs for the details about this event. 520 ensures 521 - does not change the state of mutex m. 522 !*/ 523 on_window_moved()524 virtual void on_window_moved( 525 ){} 526 /*! 527 requires 528 - events_are_enabled() == true 529 - mutex m is locked 530 - this is just the base_window::on_window_moved() event forwarded to 531 this object. See the gui_core specs for the details about this event. 532 ensures 533 - does not change the state of mutex m. 534 !*/ 535 on_mouse_down(unsigned long btn,unsigned long state,long x,long y,bool is_double_click)536 virtual void on_mouse_down ( 537 unsigned long btn, 538 unsigned long state, 539 long x, 540 long y, 541 bool is_double_click 542 ){} 543 /*! 544 requires 545 - events_are_enabled() == true 546 - mutex m is locked 547 - this is just the base_window::on_mouse_down() event forwarded to 548 this object. See the gui_core specs for the details about this event. 549 ensures 550 - does not change the state of mutex m. 551 !*/ 552 on_mouse_up(unsigned long btn,unsigned long state,long x,long y)553 virtual void on_mouse_up ( 554 unsigned long btn, 555 unsigned long state, 556 long x, 557 long y 558 ){} 559 /*! 560 requires 561 - events_are_enabled() == true 562 - mutex m is locked 563 - this is just the base_window::on_mouse_up() event forwarded to 564 this object. See the gui_core specs for the details about this event. 565 ensures 566 - does not change the state of mutex m. 567 !*/ 568 on_mouse_move(unsigned long state,long x,long y)569 virtual void on_mouse_move ( 570 unsigned long state, 571 long x, 572 long y 573 ){} 574 /*! 575 requires 576 - events_are_enabled() == true 577 - mutex m is locked 578 - x == lastx 579 - y == lasty 580 - this is just the base_window::on_mouse_move() event forwarded to 581 this object. See the gui_core specs for the details about this event. 582 ensures 583 - does not change the state of mutex m. 584 !*/ 585 on_mouse_leave()586 virtual void on_mouse_leave ( 587 ){} 588 /*! 589 requires 590 - events_are_enabled() == true 591 - mutex m is locked 592 - this is just the base_window::on_mouse_leave() event forwarded to 593 this object. See the gui_core specs for the details about this event. 594 ensures 595 - does not change the state of mutex m. 596 !*/ 597 on_mouse_enter()598 virtual void on_mouse_enter ( 599 ){} 600 /*! 601 requires 602 - events_are_enabled() == true 603 - mutex m is locked 604 - this is just the base_window::on_mouse_enter() event forwarded to 605 this object. See the gui_core specs for the details about this event. 606 ensures 607 - does not change the state of mutex m. 608 !*/ 609 on_wheel_up(unsigned long state)610 virtual void on_wheel_up ( 611 unsigned long state 612 ){} 613 /*! 614 requires 615 - events_are_enabled() == true 616 - mutex m is locked 617 - this is just the base_window::on_wheel_up() event forwarded to 618 this object. See the gui_core specs for the details about this event. 619 ensures 620 - does not change the state of mutex m. 621 !*/ 622 on_wheel_down(unsigned long state)623 virtual void on_wheel_down ( 624 unsigned long state 625 ){} 626 /*! 627 requires 628 - events_are_enabled() == true 629 - mutex m is locked 630 - this is just the base_window::on_wheel_down() event forwarded to 631 this object. See the gui_core specs for the details about this event. 632 ensures 633 - does not change the state of mutex m. 634 !*/ 635 on_focus_gained()636 virtual void on_focus_gained ( 637 ){} 638 /*! 639 requires 640 - events_are_enabled() == true 641 - mutex m is locked 642 - this is just the base_window::on_focus_gained() event forwarded to 643 this object. See the gui_core specs for the details about this event. 644 ensures 645 - does not change the state of mutex m. 646 !*/ 647 on_focus_lost()648 virtual void on_focus_lost ( 649 ){} 650 /*! 651 requires 652 - events_are_enabled() == true 653 - mutex m is locked 654 - this is just the base_window::on_focus_lost() event forwarded to 655 this object. See the gui_core specs for the details about this event. 656 ensures 657 - does not change the state of mutex m. 658 !*/ 659 on_keydown(unsigned long key,bool is_printable,unsigned long state)660 virtual void on_keydown ( 661 unsigned long key, 662 bool is_printable, 663 unsigned long state 664 ){} 665 /*! 666 requires 667 - events_are_enabled() == true 668 - mutex m is locked 669 - this is just the base_window::on_keydown() event forwarded to 670 this object. See the gui_core specs for the details about this event. 671 ensures 672 - does not change the state of mutex m. 673 !*/ 674 on_string_put(const std::wstring & str)675 virtual void on_string_put ( 676 const std::wstring &str 677 ){} 678 /*! 679 requires 680 - events_are_enabled() == true 681 - mutex m is locked 682 - this is just the base_window::on_put_string() event forwarded to 683 this object. See the gui_core specs for the details about this event. 684 ensures 685 - does not change the state of mutex m. 686 !*/ 687 688 virtual void draw ( 689 const canvas& c 690 ) const=0; 691 /*! 692 requires 693 - events_are_enabled() == true 694 - mutex m is locked 695 - is_hidden() == false 696 - is called by parent_window() when it needs to repaint itself. 697 - c == the canvas object for the area of parent_window() that needs 698 to be repainted. 699 ensures 700 - does not change the state of mutex m. 701 - draws the area of *this that intersects with the canvas onto 702 the canvas object c. 703 !*/ 704 705 private: 706 707 // restricted functions 708 drawable(drawable&); // copy constructor 709 drawable& operator=(drawable&); // assignment operator 710 }; 711 712 // ---------------------------------------------------------------------------------------- 713 714 } 715 716 #endif // DLIB_DRAWABLe_ABSTRACT_ 717 718