// Copyright (C) 2005 Davis E. King (davis@dlib.net), Keita Mochizuki // License: Boost Software License See LICENSE.txt for the full license. #undef DLIB_GUI_CORE_KERNEl_ABSTRACT_ #ifdef DLIB_GUI_CORE_KERNEl_ABSTRACT_ #include <string> #include "../algs.h" #include "../geometry/rectangle_abstract.h" #include "../unicode/unicode_abstract.h" namespace dlib { /*! OVERVIEW: This is a set of objects and functions which provide a very basic framework for manipulating windows. It is intended to provide a portable interface which can be used to build a more complex windowing toolkit. EXCEPTIONS Do not let an exception leave any of the base_window event handlers. The results of doing so are undefined. THREAD SAFETY Event Handlers All event handlers are executed in a special event handling thread. This means that you must not do anything that will take a long time or block while in an event handler. Doing so will freeze all event processing. Also, don't rely on get_thread_id() always returning the same ID from inside event handlers. canvas Never access a canvas object outside of the paint() callback that supplied it. Only access a canvas object from the event handling thread. After the paint() event handler has returned do not access that canvas object again. base_window All methods for this class are thread safe. You may call them from any thread and do not need to serialize access. !*/ // ---------------------------------------------------------------------------------------- void put_on_clipboard ( const std::string& str ); /*! ensures - posts the contents of str to the system clipboard throws - std::bad_alloc - dlib::gui_error - dlib::thread_error !*/ // overloads for wide character strings void put_on_clipboard (const std::wstring& str); void put_on_clipboard (const dlib::ustring& str); // ---------------------------------------------------------------------------------------- void get_from_clipboard ( std::string& str ); /*! ensures - if (there is string data on the system clipboard) then - #str == the data from the clipboard - else - #str == "" throws - std::bad_alloc - dlib::gui_error - dlib::thread_error !*/ // overloads for wide character strings void get_from_clipboard (std::wtring& str); void get_from_clipboard (dlib::utring& str); // ---------------------------------------------------------------------------------------- class canvas : public rectangle { /*! POINTERS AND REFERENCES TO INTERNAL DATA All functions of this object may invalidate pointers and references to internal data. INITIAL VALUE The initial value of each pixel is undefined. is_empty() == false WHAT THIS OBJECT REPRESENTS This object represents a rectangular area of a window that you can draw on. Each pixel can be accessed with the following syntax: canvas_instance[y][x].red == the red value for this pixel canvas_instance[y][x].blue == the blue value for this pixel canvas_instance[y][x].green == the green value for this pixel The origin, i.e. (0,0), of the x,y coordinate plane of the canvas is in the upper left corner of the canvas. Note that the upper left corner of the canvas appears at the point (left(),top()) in its window. !*/ public: struct pixel { /*! WHAT THIS OBJECT REPRESENTS This object represents a single pixel. Each pixel's value ranges from 0 to 255 with 0 indicating that the color is not present in the pixel at all and 255 indicating that the color is present in the pixel with maximum intensity. Note that the structure, order, and size of of this struct are implementation dependent. It will always contain fields called red, green, and blue but they may not be in that order and there may be padding. Also note that pixel_traits<> is defined for this pixel type, thus you can use it in assign_pixel() calls. !*/ unsigned char red; unsigned char green; unsigned char blue; }; pixel* operator[] ( unsigned long row ) const; /*! requires - row < height() ensures - returns an array of width() pixel structs that represents the given row of pixels in the canvas. !*/ void fill ( unsigned char red, unsigned char green, unsigned char blue ) const; /*! ensures - for all valid values of x and y: - (#*this)[y][x].red = red - (#*this)[y][x].green = green - (#*this)[y][x].blue = blue !*/ private: // restricted functions canvas(); // normal constructor canvas(canvas&); // copy constructor canvas& operator=(canvas&); // assignment operator }; // ---------------------------------------------------------------------------------------- class base_window { /*! WHAT THIS OBJECT REPRESENTS This object represents a window on the desktop. A window has a "client area" that is a region of the screen that you can draw whatever you like on. You implement the paint() callback and use the canvas object to do this drawing. INITIAL STATE - The initial state of the window is to be hidden. This means you need to call show() to make it appear. - is_closed() == false paint() callback: This is where you will do all your drawing. It is triggered when part of the window needs to be drawn/redrawn. mouse events: It is important to note a few things about the mouse events. First, the on_mouse_move() event is not triggered for each pixel the mouse crosses but rather its frequency and precision is implementation dependent. Second, it is possible that a mouse button may be depressed but the corresponding button release event does not go to the window. For instance, if the mouse is outside the window and some other application jumps to the top it is possible that the new application will receive any mouse button release events rather than the original window. But the point is that you should not rely on always getting a button up event for every button down event. keydown event: Note that the existence of a typematic action (holding down a key and having it start to repeat itself after a moment) for each key is totally implementation dependent. So don't rely on it for any key and conversely don't assume it isn't present either. The base_window::wm mutex This is a reference to a global rmutex. All instances of base_window make reference to the same global rmutex. It is used to synchronize access to the base_window to make it thread safe. It is also always locked before an event handler is called. !*/ public: enum on_close_return_code { DO_NOT_CLOSE_WINDOW, CLOSE_WINDOW }; enum mouse_state_masks { /*! These constants represent the various buttons referenced by mouse events. !*/ NONE = 0, LEFT = 1, RIGHT = 2, MIDDLE = 4, SHIFT = 8, CONTROL = 16 }; enum keyboard_state_masks { /*! These constants represent the various modifier buttons that could be in effect during a key press on the keyboard !*/ KBD_MOD_NONE = 0, KBD_MOD_SHIFT = 1, KBD_MOD_CONTROL = 2, KBD_MOD_ALT = 4, KBD_MOD_META = 8, KBD_MOD_CAPS_LOCK = 16, KBD_MOD_NUM_LOCK = 32, KBD_MOD_SCROLL_LOCK = 64 }; enum non_printable_keyboard_keys { KEY_BACKSPACE, KEY_SHIFT, KEY_CTRL, KEY_ALT, KEY_PAUSE, KEY_CAPS_LOCK, KEY_ESC, KEY_PAGE_UP, KEY_PAGE_DOWN, KEY_END, KEY_HOME, KEY_LEFT, // This is the left arrow key KEY_RIGHT, // This is the right arrow key KEY_UP, // This is the up arrow key KEY_DOWN, // This is the down arrow key KEY_INSERT, KEY_DELETE, KEY_SCROLL_LOCK, // Function Keys KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12 }; base_window ( bool resizable = true, bool undecorated = false ); /*! requires - if (undecorated == true) then - resizable == false ensures - #*this has been properly initialized - if (resizable == true) then - this window will be resizable by the user - else - this window will not be resizable by the user - if (undecorated == true) then - this window will not have any graphical elements outside of its drawable area or appear in the system task bar. It also won't take the input focus from other windows. (it is suitable for making things such as popup menus) throws - std::bad_alloc - dlib::thread_error - dlib::gui_error This exception is thrown if there is an error while creating this window. !*/ virtual ~base_window ( ); /*! ensures - does NOT trigger the on_window_close() event - all resources associated with *this have been released - closes this window !*/ void close_window ( ); /*! ensures - #is_closed() == true (i.e. permanently closes this window. The window is removed from the screen and no more events will be dispatched to this window. ) - does NOT trigger the on_window_close() event !*/ void wait_until_closed ( ) const; /*! ensures - blocks until is_closed() == true !*/ bool is_closed ( ) const; /*! ensures - returns true if this window has been closed, false otherwise. (Note that closed windows do not receive any callbacks at all. They are also not visible on the screen.) !*/ void set_title ( const std::string& title ); /*! ensures - if (is_closed() == false) then - sets the title of the window !*/ void set_title ( const std::wstring& title ); /*! ensures - if (is_closed() == false) then - sets the title of the window !*/ void set_title ( const dlib::ustring& title ); /*! ensures - if (is_closed() == false) then - sets the title of the window !*/ virtual void show ( ); /*! ensures - if (is_closed() == false) then - this window will appear on the screen !*/ virtual void hide( ); /*! ensures - if (is_closed() == false) then - the window does not appear on the screen !*/ void set_size ( int width, int height ); /*! ensures - if (is_closed() == false) then - The width of the client area of this window is at least width pixels. - The height of the client area of this window is at least height pixels. - if (the window wasn't already this size) then - triggers the on_window_resized() callback !*/ void set_pos ( long x, long y ); /*! ensures - if (is_closed() == false) then - sets the upper left corner of this window to the position (x,y) on the desktop. Note that the origin (0,0) is at the upper left corner of the desktop. !*/ void get_pos ( long& x, long& y ) const; /*! ensures - if (is_closed() == false) then - #x == the x coordinate of the upper left corner of the client area of this window. - #y == the y coordinate of the upper left corner of the client area of this window. - i.e. the point (#x,#y) on the desktop is coincident with the point (0,0) in the client area of this window. - else - #x == 0 - #y == 0 !*/ void get_size ( unsigned long& width, unsigned long& height ) const; /*! ensures - if (is_closed() == false) then - #width == the width of the client area of this window in pixels - #height == the height of the client area of this window in pixels - else - #width == 0 - #height == 0 !*/ void get_display_size ( unsigned long& width, unsigned long& height ) const; /*! ensures - if (is_closed() == false) then - #width == the width in pixels of the display device that contains this window - #height == the height in pixels of the display device that contains this window - else - #width == 0 - #height == 0 !*/ void invalidate_rectangle ( const rectangle& rect ); /*! ensures - if (is_closed() == false) then - causes the area of this window defined by rect to become invalid. This means that a paint() message will be dispatched to repaint this area of the window. Note that it is possible that the resulting paint() message may include a bigger rectangle than the one defined by rect. !*/ void trigger_user_event ( void* p, int i ); /*! ensures - will never block (even if some other thread has a lock on the global mutex referenced by wm.) - if (is_closed() == false) then - causes the on_user_event() event to be called with the given arguments. !*/ void set_im_pos ( long x_, long y_ ); /*! ensures - if (is_closed() == false) then - sets the left-top position of input method rectangle used for wide character input methods. !*/ protected: const rmutex& wm; // let the window close by default virtual on_close_return_code on_window_close( ){return CLOSE_WINDOW;} /*! requires - is_closed() == false - mutex wm is locked - is called when the user attempts to close this window - if (this function returns CLOSE_WINDOW) then - #is_closed() == true (i.e. this window will be closed) - it is safe to call "delete this;" inside on_window_close() if *this was allocated on the heap and no one will try to access *this anymore. - else - this window will not be closed and the attempt to close it by the user will have no effect. - #is_closed() == false ensures - does not change the state of mutex wm !*/ // do nothing by default virtual void on_user_event ( void* p, int i ){} /*! requires - is_closed() == false - mutex wm is locked - is called whenever someone calls trigger_user_event() ensures - does not change the state of mutex wm !*/ // do nothing by default virtual void on_window_resized( ){} /*! requires - is_closed() == false - mutex wm is locked - is called when this window is resized ensures - does not change the state of mutex wm !*/ // do nothing by default virtual void on_window_moved( ){} /*! requires - is_closed() == false - mutex wm is locked - is called when this window's position changes ensures - does not change the state of mutex wm !*/ // do nothing by default virtual void on_mouse_down ( unsigned long btn, unsigned long state, long x, long y, bool is_double_click ){} /*! requires - is_closed() == false - mutex wm is locked - is called when the user depresses one of the mouse buttons - btn == the button that was depressed. (either LEFT, MIDDLE, or RIGHT) - state == the bitwise OR of the buttons that are currently depressed excluding the button given by btn. (from the mouse_state_masks enum) - (x,y) == the position of the mouse (relative to the upper left corner of the window) when this event occurred. Note that the mouse may be outside the window. - if (this is the second button press of a double click) then - is_double_click == true - else - is_double_click == false ensures - does not change the state of mutex wm !*/ // do nothing by default virtual void on_mouse_up ( unsigned long btn, unsigned long state, long x, long y ){} /*! requires - is_closed() == false - mutex wm is locked - is called when the user releases one of the mouse buttons - btn == the button that was released. (either LEFT, MIDDLE, or RIGHT) - state == the bitwise OR of the buttons that are currently depressed (from the mouse_state_masks enum) - (x,y) == the position of the mouse (relative to the upper left corner of the window) when this event occurred. Note that the mouse may be outside the window. ensures - does not change the state of mutex wm !*/ // do nothing by default virtual void on_mouse_move ( unsigned long state, long x, long y ){} /*! requires - is_closed() == false - mutex wm is locked - is called when the user moves the mouse - state == the bitwise OR of the buttons that are currently depressed (from the mouse_state_masks enum) - (x,y) == the position of the mouse (relative to the upper left corner of the window) when this event occurred. - if (the user is holding down one or more of the mouse buttons) then - the mouse move events will continue to track the mouse even if it goes out of the window. This will continue until the user releases all the mouse buttons. ensures - does not change the state of mutex wm !*/ // do nothing by default virtual void on_mouse_leave ( ){} /*! requires - is_closed() == false - mutex wm is locked - is called when the mouse leaves this window ensures - does not change the state of mutex wm !*/ // do nothing by default virtual void on_mouse_enter ( ){} /*! requires - is_closed() == false - mutex wm is locked - is called when the mouse enters this window ensures - does not change the state of mutex wm !*/ // do nothing by default virtual void on_focus_gained ( ){} /*! requires - is_closed() == false - mutex wm is locked - is called when this window gains input focus ensures - does not change the state of mutex wm !*/ // do nothing by default virtual void on_focus_lost ( ){} /*! requires - is_closed() == false - mutex wm is locked - is called when this window loses input focus ensures - does not change the state of mutex wm !*/ // do nothing by default virtual void on_wheel_up ( unsigned long state ){} /*! requires - is_closed() == false - mutex wm is locked - is called every time the mouse wheel is scrolled up one notch - state == the bitwise OR of the buttons that are currently depressed (from the mouse_state_masks enum) ensures - does not change the state of mutex wm !*/ // do nothing by default virtual void on_wheel_down ( unsigned long state ){} /*! requires - is_closed() == false - mutex wm is locked - is called every time the mouse wheel is scrolled down one notch - state == the bitwise OR of the buttons that are currently depressed (from the mouse_state_masks enum) ensures - does not change the state of mutex wm !*/ // do nothing by default virtual void on_keydown ( unsigned long key, bool is_printable, unsigned long state ){} /*! requires - is_closed() == false - mutex wm is locked - is called when a keyboard key is pressed or if a key is held down then this is called repeatedly at a certain rate once the typematic action begins (note that some keys might not have any typematic action on some platforms). - if (is_printable) then - key == the character that was pressed. (e.g. 'a', 'b', '1' etc.) - this is a printable character. Note that ' ', '\t', and '\n' (this is the return/enter key) are all considered printable. - else - key == one of the non_printable_keyboard_keys enums. - state == the bitwise OR of the keyboard modifiers that are currently depressed (taken from keyboard_state_masks). - if (key is not in the range 'a' to 'z' or 'A' to 'Z') then - if (the shift key was down when this key was pressed) then - (state & KBD_MOD_SHIFT) != 0 - else - (state & KBD_MOD_SHIFT) == 0 - else - the state of the shift key is implementation defined ensures - does not change the state of mutex wm !*/ virtual void on_string_put ( const std::wstring &str ){} /*! requires - is_closed() == false - mutex wm is locked - is called when a wide/multibyte character input method determines a string that is being input to the window. - str == the string that is being input ensures - does not change the state of mutex wm !*/ private: virtual void paint ( const canvas& c ) =0; /*! requires - is_closed() == false - mutex wm is locked - is called when part of the window needs to be repainted for any reason. - c == a canvas object that represents the invalid area of this window which needs to be painted. ensures - does not change the state of mutex wm !*/ base_window(base_window&); // copy constructor base_window& operator=(base_window&); // assignment operator }; // ---------------------------------------------------------------------------------------- } #endif // DLIB_GUI_CORE_KERNEl_ABSTRACT_