// Copyright (C) 2005 Davis E. King ([email protected]) | |
// License: Boost Software License See LICENSE.txt for the full license. | |
namespace dlib | |
{ | |
/*! | |
GENERAL REMARKS | |
This file defines the drawable interface class and the drawable_window which | |
is just a window that is capable of displaying drawable objects (i.e. objects | |
that implement the drawable interface). | |
The drawable interface is a simple framework for creating more complex | |
graphical widgets. It provides a default set of functionality and a | |
set of events which a gui widget may use. | |
THREAD SAFETY | |
All objects and functions defined in this file are thread safe. You may | |
call them from any thread without serializing access to them. | |
!*/ | |
// ---------------------------------------------------------------------------------------- | |
// ---------------------------------------------------------------------------------------- | |
// class drawable_window | |
// ---------------------------------------------------------------------------------------- | |
// ---------------------------------------------------------------------------------------- | |
class drawable_window : public base_window | |
{ | |
/*! | |
WHAT THIS OBJECT REPRESENTS | |
This object represents a window on the desktop that is capable of | |
containing drawable objects. | |
INITIAL STATE | |
The initial state of the drawable_window is to be hidden. This means | |
you need to call show() to make it appear. | |
EVENTS | |
The drawable_window object uses all the events provided by base_window | |
except for the on_window_close() event. This means that if you | |
define handlers for these events yourself you will have to call | |
the drawable_window's version of them so that the drawable_window | |
can continue to process and forward these events to its drawable | |
objects. | |
!*/ | |
public: | |
drawable_window ( | |
bool resizable = true, | |
bool undecorated = false | |
); | |
/*! | |
requires | |
- if (undecorated == true) then | |
- resizable == false | |
ensures | |
- #*this has been properly initialized | |
- #background_color() == rgb_pixel(212,208,200) | |
- 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. | |
(e.g. a popup menu) | |
throws | |
- std::bad_alloc | |
- dlib::thread_error | |
- dlib::gui_error | |
This exception is thrown if there is an error while | |
creating this window. | |
!*/ | |
virtual ~drawable_window( | |
)=0; | |
/*! | |
ensures | |
- if (this window has not already been closed) then | |
- closes the window | |
- does NOT trigger the on_window_close() event | |
- all resources associated with *this have been released | |
!*/ | |
void set_background_color ( | |
unsigned long red, | |
unsigned long green, | |
unsigned long blue | |
); | |
/*! | |
ensures | |
- #background_color().red == red | |
- #background_color().green == green | |
- #background_color().blue == blue | |
!*/ | |
rgb_pixel background_color ( | |
) const; | |
/*! | |
ensures | |
- returns the background color this window paints its canvas | |
with before it passes it onto its drawable widgets | |
!*/ | |
private: | |
// restricted functions | |
drawable_window(drawable_window&); // copy constructor | |
drawable_window& operator=(drawable_window&); // assignment operator | |
friend class drawable; | |
}; | |
// ---------------------------------------------------------------------------------------- | |
// ---------------------------------------------------------------------------------------- | |
// class drawable | |
// ---------------------------------------------------------------------------------------- | |
// ---------------------------------------------------------------------------------------- | |
enum | |
{ | |
MOUSE_MOVE = 1, | |
MOUSE_CLICK = 2, | |
MOUSE_WHEEL = 4, | |
WINDOW_RESIZED = 8, | |
KEYBOARD_EVENTS = 16, | |
FOCUS_EVENTS = 32, | |
WINDOW_MOVED = 64, | |
STRING_PUT = 128 | |
}; | |
class drawable | |
{ | |
/*! | |
INITIAL VALUE | |
top() == 0 | |
left() == 0 | |
right() == -1 | |
bottom() == -1 | |
get_rect().is_empty() == true | |
is_hidden() == false | |
is_enabled() == true | |
z_order() == 0 | |
main_font() == default_font::get_font() | |
WHAT THIS OBJECT REPRESENTS | |
This is an interface that all drawable widgets implement. It | |
provides a standard method (draw()) to draw a widget onto a canvas | |
and many other convenient functions for drawable objects. | |
EVENT FORWARDING | |
All the events that come to a drawable object are forwarded from its | |
parent window. Additionally, there is no filtering. This means that | |
if a drawable registers to receive a certain kind of event then whenever | |
its parent window receives that event the drawable object will get a | |
forwarded copy of it as well even if the event occurred outside the | |
drawable's rectangle. | |
The only events that have anything in the way of filtering are the | |
draw() and on_user_event() events. draw() is only called on a drawable | |
object when that object is not hidden. on_user_event() is only called | |
for drawables that the on_user_event()'s first argument specifically | |
references. All other events are not filtered at all though. | |
Z ORDER | |
Z order defines the order in which drawable objects are drawn. The | |
lower numbered drawables are drawn first and then the higher numbered | |
ones. So a drawable with a z order of 0 is drawn before one with a | |
z order of 1 and so on. | |
!*/ | |
public: | |
friend class drawable_window; | |
drawable ( | |
drawable_window& w, | |
unsigned long events = 0 | |
) : | |
m(w.wm), | |
parent(w), | |
hidden(false), | |
enabled(true) | |
{} | |
/*! | |
ensures | |
- #*this is properly initialized | |
- #parent_window() == w | |
- #*this will not receive any events or draw() requests until | |
enable_events() is called | |
- once events_are_enabled() == true this drawable will receive | |
the on_user_event() event. (i.e. you always get this event, you don't | |
have to enable it by setting something in the events bitset). | |
- if (events & MOUSE_MOVE) then | |
- once events_are_enabled() == true this drawable will receive | |
the following events related to mouse movement: on_mouse_move, | |
on_mouse_leave, and on_mouse_enter. | |
- if (events & MOUSE_CLICK) then | |
- once events_are_enabled() == true this drawable will receive | |
the following events related to mouse clicks: on_mouse_down and | |
on_mouse_up. | |
- if (events & MOUSE_WHEEL) then | |
- once events_are_enabled() == true this drawable will receive | |
the following events related to mouse wheel scrolling: | |
on_wheel_up and on_wheel_down. | |
- if (events & WINDOW_RESIZED) then | |
- once events_are_enabled() == true this drawable will receive | |
the following event related to its parent window resizing: | |
on_window_resized. | |
- if (events & KEYBOARD_EVENTS) then | |
- once events_are_enabled() == true this drawable will receive | |
the following keyboard event: on_keydown. | |
- if (events & FOCUS_EVENTS) then | |
- once events_are_enabled() == true this drawable will receive | |
the following focus events: on_focus_gained and on_focus_lost. | |
- if (events & WINDOW_MOVED) then | |
- once events_are_enabled() == true this drawable will receive | |
the following event related to its parent window moving: | |
on_window_moved. | |
- if (events & STRING_PUT) then | |
- once events_are_enabled() == true this drawable will receive | |
the following event related to wide character string input: | |
on_string_put. | |
throws | |
- std::bad_alloc | |
- dlib::thread_error | |
!*/ | |
virtual ~drawable ( | |
); | |
/*! | |
requires | |
- events_are_enabled() == false | |
ensures | |
- any resources associated with *this have been released | |
- *this has been removed from its containing window parent_window() and | |
its parent window will no longer try to dispatch events to it. | |
Note that this does not trigger a redraw of the parent window. If you | |
want to do that you must do it yourself. | |
!*/ | |
long z_order ( | |
) const; | |
/*! | |
ensures | |
- returns the z order for this drawable. | |
!*/ | |
virtual void set_z_order ( | |
long order | |
); | |
/*! | |
ensures | |
- #z_order() == order | |
- if (events_are_enabled() == true) then | |
- parent_window() is updated to reflect the new state of #*this | |
throws | |
- std::bad_alloc | |
!*/ | |
const rectangle get_rect ( | |
) const; | |
/*! | |
ensures | |
- returns the rectangle that defines the area and position of this | |
drawable inside its containing window parent_window(). | |
!*/ | |
long bottom ( | |
) const; | |
/*! | |
ensures | |
- returns get_rect().bottom() | |
!*/ | |
long top ( | |
) const; | |
/*! | |
ensures | |
- returns get_rect().top() | |
!*/ | |
long left ( | |
) const; | |
/*! | |
ensures | |
- returns get_rect().left() | |
!*/ | |
long right ( | |
) const; | |
/*! | |
ensures | |
- returns get_rect().right() | |
!*/ | |
unsigned long width ( | |
) const; | |
/*! | |
ensures | |
- returns get_rect().width() | |
!*/ | |
unsigned long height ( | |
) const; | |
/*! | |
ensures | |
- returns get_rect().height() | |
!*/ | |
virtual void set_pos ( | |
long x, | |
long y | |
); | |
/*! | |
ensures | |
- #top() == y | |
- #left() == x | |
- #width() == width() | |
- #height() == height() | |
- if (events_are_enabled() == true) then | |
- parent_window() is updated to reflect the new state of #*this | |
- i.e. This just sets the upper left corner of this drawable to the | |
location (x,y) | |
!*/ | |
bool is_enabled ( | |
) const; | |
/*! | |
ensures | |
- returns true if this object is enabled and false otherwise. | |
(it is up to derived classes to define exactly what it means to be | |
"enabled") | |
!*/ | |
virtual void enable ( | |
); | |
/*! | |
ensures | |
- #is_enabled() == true | |
- if (events_are_enabled() == true) then | |
- parent_window() is updated to reflect the new state of #*this | |
!*/ | |
virtual void disable ( | |
); | |
/*! | |
ensures | |
- #is_enabled() == false | |
- if (events_are_enabled() == true) then | |
- parent_window() is updated to reflect the new state of #*this | |
!*/ | |
virtual void set_main_font ( | |
const shared_ptr_thread_safe<font>& f | |
); | |
/*! | |
ensures | |
- #main_font() == f | |
- if (events_are_enabled() == true) then | |
- parent_window() is updated to reflect the new state of #*this | |
!*/ | |
const shared_ptr_thread_safe<font> main_font ( | |
) const; | |
/*! | |
ensures | |
- returns the current main font being used by this widget | |
!*/ | |
bool is_hidden ( | |
) const; | |
/*! | |
ensures | |
- returns true if this object is NOT currently displayed on parent_window() | |
and false otherwise. | |
!*/ | |
virtual void show ( | |
); | |
/*! | |
ensures | |
- #is_hidden() == false | |
- if (events_are_enabled() == true) then | |
- parent_window() is updated to reflect the new state of #*this | |
!*/ | |
virtual void hide ( | |
); | |
/*! | |
ensures | |
- #is_hidden() == true | |
- if (events_are_enabled() == true) then | |
- parent_window() is updated to reflect the new state of #*this | |
!*/ | |
drawable_window& parent_window ( | |
); | |
/*! | |
ensures | |
- returns a reference to the drawable_window that this drawable is | |
being drawn on and receiving events from. | |
!*/ | |
const drawable_window& parent_window ( | |
) const; | |
/*! | |
ensures | |
- returns a const reference to the drawable_window that this drawable | |
is being drawn on and receiving events from. | |
!*/ | |
virtual int next_free_user_event_number ( | |
)const { return 0; } | |
/*! | |
ensures | |
- returns the smallest number, i, that is the next user event number you | |
can use in calls to parent.trigger_user_event((void*)this,i). | |
- This function exists because of the following scenario. Suppose | |
you make a class called derived1 that inherits from drawable and | |
in derived1 you use a user event to do something. Then suppose | |
you inherit from derived1 to make derived2. Now in derived2 you | |
may want to use a user event to do something as well. How are you | |
to know which user event numbers are in use already? This function | |
solves that problem. You would define derived1::next_free_user_event_number() | |
so that it returned a number bigger than any user event numbers used by | |
derived1 or its ancestors. Then derived2 could just call | |
derived1::next_free_user_event_number() to find out what numbers it could use. | |
!*/ | |
protected: | |
/*!A drawable_protected_variables | |
These protected members are provided because they are needed to | |
implement drawable widgets. | |
!*/ | |
// This is the rectangle that is returned by get_rect() | |
rectangle rect; | |
// This is the mutex used to serialize access to this class. | |
const rmutex& m; | |
// This is the parent window of this drawable | |
drawable_window& parent; | |
// This is the bool returned by is_hidden() | |
bool hidden; | |
// This is the bool returned by is_enabled() | |
bool enabled; | |
// This is the font pointer returned by main_font() | |
shared_ptr_thread_safe<font> mfont; | |
// This is the x coordinate that we last saw the mouse at or -1 if the mouse | |
// is outside the parent window. | |
const long& lastx; | |
// This is the y coordinate that we last saw the mouse at or -1 if the mouse | |
// is outside the parent window. | |
const long& lasty; | |
void enable_events ( | |
); | |
/*! | |
ensures | |
- #events_are_enabled() == true | |
!*/ | |
void disable_events ( | |
); | |
/*! | |
ensures | |
- #events_are_enabled() == false | |
!*/ | |
bool events_are_enabled ( | |
) const; | |
/*! | |
ensures | |
- returns true if this object is receiving events and draw() | |
requests from its parent window. | |
- returns false otherwise | |
!*/ | |
// ---------------- EVENT HANDLERS ------------------ | |
virtual void on_user_event ( | |
int i | |
){} | |
/*! | |
requires | |
- events_are_enabled() == true | |
- mutex m is locked | |
- is called whenever the parent window receives an on_user_event(p,i) event | |
where p == this. (i.e. this is just a redirect of on_user_event for | |
cases where the first argument of on_user_event is equal to the | |
this pointer). | |
ensures | |
- does not change the state of mutex m. | |
!*/ | |
virtual void on_window_resized( | |
){} | |
/*! | |
requires | |
- events_are_enabled() == true | |
- mutex m is locked | |
- this is just the base_window::on_window_resized() event forwarded to | |
this object. See the gui_core specs for the details about this event. | |
ensures | |
- does not change the state of mutex m. | |
!*/ | |
virtual void on_window_moved( | |
){} | |
/*! | |
requires | |
- events_are_enabled() == true | |
- mutex m is locked | |
- this is just the base_window::on_window_moved() event forwarded to | |
this object. See the gui_core specs for the details about this event. | |
ensures | |
- does not change the state of mutex m. | |
!*/ | |
virtual void on_mouse_down ( | |
unsigned long btn, | |
unsigned long state, | |
long x, | |
long y, | |
bool is_double_click | |
){} | |
/*! | |
requires | |
- events_are_enabled() == true | |
- mutex m is locked | |
- this is just the base_window::on_mouse_down() event forwarded to | |
this object. See the gui_core specs for the details about this event. | |
ensures | |
- does not change the state of mutex m. | |
!*/ | |
virtual void on_mouse_up ( | |
unsigned long btn, | |
unsigned long state, | |
long x, | |
long y | |
){} | |
/*! | |
requires | |
- events_are_enabled() == true | |
- mutex m is locked | |
- this is just the base_window::on_mouse_up() event forwarded to | |
this object. See the gui_core specs for the details about this event. | |
ensures | |
- does not change the state of mutex m. | |
!*/ | |
virtual void on_mouse_move ( | |
unsigned long state, | |
long x, | |
long y | |
){} | |
/*! | |
requires | |
- events_are_enabled() == true | |
- mutex m is locked | |
- x == lastx | |
- y == lasty | |
- this is just the base_window::on_mouse_move() event forwarded to | |
this object. See the gui_core specs for the details about this event. | |
ensures | |
- does not change the state of mutex m. | |
!*/ | |
virtual void on_mouse_leave ( | |
){} | |
/*! | |
requires | |
- events_are_enabled() == true | |
- mutex m is locked | |
- this is just the base_window::on_mouse_leave() event forwarded to | |
this object. See the gui_core specs for the details about this event. | |
ensures | |
- does not change the state of mutex m. | |
!*/ | |
virtual void on_mouse_enter ( | |
){} | |
/*! | |
requires | |
- events_are_enabled() == true | |
- mutex m is locked | |
- this is just the base_window::on_mouse_enter() event forwarded to | |
this object. See the gui_core specs for the details about this event. | |
ensures | |
- does not change the state of mutex m. | |
!*/ | |
virtual void on_wheel_up ( | |
unsigned long state | |
){} | |
/*! | |
requires | |
- events_are_enabled() == true | |
- mutex m is locked | |
- this is just the base_window::on_wheel_up() event forwarded to | |
this object. See the gui_core specs for the details about this event. | |
ensures | |
- does not change the state of mutex m. | |
!*/ | |
virtual void on_wheel_down ( | |
unsigned long state | |
){} | |
/*! | |
requires | |
- events_are_enabled() == true | |
- mutex m is locked | |
- this is just the base_window::on_wheel_down() event forwarded to | |
this object. See the gui_core specs for the details about this event. | |
ensures | |
- does not change the state of mutex m. | |
!*/ | |
virtual void on_focus_gained ( | |
){} | |
/*! | |
requires | |
- events_are_enabled() == true | |
- mutex m is locked | |
- this is just the base_window::on_focus_gained() event forwarded to | |
this object. See the gui_core specs for the details about this event. | |
ensures | |
- does not change the state of mutex m. | |
!*/ | |
virtual void on_focus_lost ( | |
){} | |
/*! | |
requires | |
- events_are_enabled() == true | |
- mutex m is locked | |
- this is just the base_window::on_focus_lost() event forwarded to | |
this object. See the gui_core specs for the details about this event. | |
ensures | |
- does not change the state of mutex m. | |
!*/ | |
virtual void on_keydown ( | |
unsigned long key, | |
bool is_printable, | |
unsigned long state | |
){} | |
/*! | |
requires | |
- events_are_enabled() == true | |
- mutex m is locked | |
- this is just the base_window::on_keydown() event forwarded to | |
this object. See the gui_core specs for the details about this event. | |
ensures | |
- does not change the state of mutex m. | |
!*/ | |
virtual void on_string_put ( | |
const std::wstring &str | |
){} | |
/*! | |
requires | |
- events_are_enabled() == true | |
- mutex m is locked | |
- this is just the base_window::on_put_string() event forwarded to | |
this object. See the gui_core specs for the details about this event. | |
ensures | |
- does not change the state of mutex m. | |
!*/ | |
virtual void draw ( | |
const canvas& c | |
) const=0; | |
/*! | |
requires | |
- events_are_enabled() == true | |
- mutex m is locked | |
- is_hidden() == false | |
- is called by parent_window() when it needs to repaint itself. | |
- c == the canvas object for the area of parent_window() that needs | |
to be repainted. | |
ensures | |
- does not change the state of mutex m. | |
- draws the area of *this that intersects with the canvas onto | |
the canvas object c. | |
!*/ | |
private: | |
// restricted functions | |
drawable(drawable&); // copy constructor | |
drawable& operator=(drawable&); // assignment operator | |
}; | |
// ---------------------------------------------------------------------------------------- | |
} | |