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