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