// Copyright (C) 2005 Davis E. King (davis@dlib.net), Keita Mochizuki // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_DRAWABLe_CPP_ #define DLIB_DRAWABLe_CPP_ #include "drawable.h" #include <algorithm> #include <iostream> namespace dlib { // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // ----------- drawable_window object ------------------------------------------------------------ // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- rgb_pixel drawable_window:: background_color ( ) const { auto_mutex M(wm); return bg_color; } // ---------------------------------------------------------------------------------------- void drawable_window:: set_background_color ( unsigned long red_, unsigned long green_, unsigned long blue_ ) { wm.lock(); bg_color.red = red_; bg_color.green = green_; bg_color.blue = blue_; wm.unlock(); // now repaint the window unsigned long width,height; get_size(width,height); rectangle rect(0,0,width-1,height-1); invalidate_rectangle(rect); } // ---------------------------------------------------------------------------------------- void drawable_window:: paint ( const canvas& c ) { ++event_id; c.fill(bg_color.red,bg_color.green,bg_color.blue); widgets.reset(); while (widgets.move_next()) { widgets.element().value().reset(); while (widgets.element().value().move_next()) { // only dispatch a draw() call if this widget isn't hidden if (widgets.element().value().element()->hidden == false && widgets.element().value().element()->event_id != event_id) { widgets.element().value().element()->event_id = event_id; widgets.element().value().element()->draw(c); } } } } // ---------------------------------------------------------------------------------------- void drawable_window:: on_user_event ( void* p, int i ) { drawable* d = static_cast<drawable*>(p); if (widget_set.is_member(d)) { d->on_user_event(i); } } // ---------------------------------------------------------------------------------------- void drawable_window:: on_window_moved( ) { ++event_id; window_moved.reset(); while (window_moved.move_next()) { if (window_moved.element()->event_id != event_id) { window_moved.element()->event_id = event_id; window_moved.element()->on_window_moved(); } } } // ---------------------------------------------------------------------------------------- void drawable_window:: on_window_resized( ) { ++event_id; window_resized.reset(); while (window_resized.move_next()) { if (window_resized.element()->event_id != event_id) { window_resized.element()->event_id = event_id; window_resized.element()->on_window_resized(); } } } // ---------------------------------------------------------------------------------------- void drawable_window:: on_keydown ( unsigned long key, bool is_printable, unsigned long state ) { ++event_id; keyboard.reset(); while (keyboard.move_next()) { if (keyboard.element()->event_id != event_id) { keyboard.element()->event_id = event_id; keyboard.element()->on_keydown(key,is_printable,state); } } } // ---------------------------------------------------------------------------------------- void drawable_window:: on_focus_gained ( ) { ++event_id; focus.reset(); while (focus.move_next()) { if (focus.element()->event_id != event_id) { focus.element()->event_id = event_id; focus.element()->on_focus_gained(); } } } // ---------------------------------------------------------------------------------------- void drawable_window:: on_focus_lost ( ) { ++event_id; focus.reset(); while (focus.move_next()) { if (focus.element()->event_id != event_id) { focus.element()->event_id = event_id; focus.element()->on_focus_lost(); } } } // ---------------------------------------------------------------------------------------- void drawable_window:: on_mouse_down ( unsigned long btn, unsigned long state, long x, long y, bool is_double_click ) { lastx = x; lasty = y; ++event_id; mouse_click.reset(); while (mouse_click.move_next()) { if (mouse_click.element()->event_id != event_id) { mouse_click.element()->event_id = event_id; mouse_click.element()->on_mouse_down(btn,state,x,y,is_double_click); } } } // ---------------------------------------------------------------------------------------- void drawable_window:: on_mouse_up ( unsigned long btn, unsigned long state, long x, long y ) { lastx = x; lasty = y; ++event_id; mouse_click.reset(); while (mouse_click.move_next()) { if (mouse_click.element()->event_id != event_id) { mouse_click.element()->event_id = event_id; mouse_click.element()->on_mouse_up(btn,state,x,y); } } } // ---------------------------------------------------------------------------------------- void drawable_window:: on_mouse_move ( unsigned long state, long x, long y ) { lastx = x; lasty = y; ++event_id; mouse_move.reset(); while (mouse_move.move_next()) { if (mouse_move.element()->event_id != event_id) { mouse_move.element()->event_id = event_id; mouse_move.element()->on_mouse_move(state,x,y); } } } // ---------------------------------------------------------------------------------------- void drawable_window:: on_mouse_leave ( ) { lastx = -1; lasty = -1; ++event_id; mouse_move.reset(); while (mouse_move.move_next()) { if (mouse_move.element()->event_id != event_id) { mouse_move.element()->event_id = event_id; mouse_move.element()->on_mouse_leave(); } } } // ---------------------------------------------------------------------------------------- void drawable_window:: on_mouse_enter ( ) { ++event_id; mouse_move.reset(); while (mouse_move.move_next()) { if (mouse_move.element()->event_id != event_id) { mouse_move.element()->event_id = event_id; mouse_move.element()->on_mouse_enter(); } } } // ---------------------------------------------------------------------------------------- void drawable_window:: on_wheel_up ( unsigned long state ) { ++event_id; mouse_wheel.reset(); while (mouse_wheel.move_next()) { if (mouse_wheel.element()->event_id != event_id) { mouse_wheel.element()->event_id = event_id; mouse_wheel.element()->on_wheel_up(state); } } } // ---------------------------------------------------------------------------------------- void drawable_window:: on_wheel_down ( unsigned long state ) { ++event_id; mouse_wheel.reset(); while (mouse_wheel.move_next()) { if (mouse_wheel.element()->event_id != event_id) { mouse_wheel.element()->event_id = event_id; mouse_wheel.element()->on_wheel_down(state); } } } // ---------------------------------------------------------------------------------------- void drawable_window:: on_string_put ( const std::wstring &str ) { ++event_id; string_put.reset(); while (string_put.move_next()) { if (string_put.element()->event_id != event_id) { string_put.element()->event_id = event_id; string_put.element()->on_string_put(str); } } } // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // ----------- drawable object ---------------------------------------------------------- // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- void drawable:: enable_events ( ) { auto_mutex M(m); if (enabled_events == false) { enabled_events = true; drawable* temp = this; long zo = z_order_value; drawable_window::set_of_drawables* sod = parent.widgets[zo]; if (sod == 0) { // this drawable is the first widget at this z order so we need // to make its containing set drawable_window::set_of_drawables s; s.add(temp); parent.widgets.add(zo,s); } else { sod->add(temp); } temp = this; parent.widget_set.add(temp); if (events & MOUSE_MOVE) { temp = this; parent.mouse_move.add(temp); } if (events & MOUSE_CLICK) { temp = this; parent.mouse_click.add(temp); } if (events & MOUSE_WHEEL) { temp = this; parent.mouse_wheel.add(temp); } if (events & WINDOW_RESIZED) { temp = this; parent.window_resized.add(temp); } if (events & KEYBOARD_EVENTS) { temp = this; parent.keyboard.add(temp); } if (events & FOCUS_EVENTS) { temp = this; parent.focus.add(temp); } if (events & WINDOW_MOVED) { temp = this; parent.window_moved.add(temp); } if (events & STRING_PUT) { temp = this; parent.string_put.add(temp); } parent.invalidate_rectangle(rect); } } // ---------------------------------------------------------------------------------------- void drawable:: set_z_order ( long order ) { auto_mutex M(m); if (order != z_order_value && enabled_events) { // first remove this drawable from widgets drawable_window::set_of_drawables* sod = parent.widgets[z_order_value]; drawable* junk; sod->remove(this,junk); // if there are no more drawables at this z order then destroy the // set for this order if (sod->size() == 0) parent.widgets.destroy(z_order_value); // now add this drawable to its new z order sod = parent.widgets[order]; if (sod == 0) { // this drawable is the first widget at this z order so we need // to make its containing set drawable_window::set_of_drawables s, x; s.add(junk); long temp_order = order; parent.widgets.add(temp_order,s); } else { sod->add(junk); } parent.invalidate_rectangle(rect); } z_order_value = order; } // ---------------------------------------------------------------------------------------- void drawable:: disable_events ( ) { auto_mutex M(m); if (enabled_events) { enabled_events = false; // first remove this drawable from widgets drawable_window::set_of_drawables* sod = parent.widgets[z_order_value]; drawable* junk; sod->remove(this,junk); // if there are no more drawables at this z order then destroy the // set for this order if (sod->size() == 0) parent.widgets.destroy(z_order_value); parent.widget_set.remove(this,junk); // now unregister this drawable from all the events it has registered for. if (events & MOUSE_MOVE) parent.mouse_move.remove(this,junk); if (events & MOUSE_CLICK) parent.mouse_click.remove(this,junk); if (events & MOUSE_WHEEL) parent.mouse_wheel.remove(this,junk); if (events & WINDOW_RESIZED) parent.window_resized.remove(this,junk); if (events & KEYBOARD_EVENTS) parent.keyboard.remove(this,junk); if (events & FOCUS_EVENTS) parent.focus.remove(this,junk); if (events & WINDOW_MOVED) parent.window_moved.remove(this,junk); if (events & STRING_PUT) parent.string_put.remove(this,junk); } } // ---------------------------------------------------------------------------------------- drawable:: ~drawable ( ) { try { DLIB_ASSERT(events_are_enabled() == false, "\tdrawable::~drawable()" << "\n\tYou must disable events for drawable objects in their destructor by calling disable_events()." << "\n\tthis: " << this ); } catch (std::exception& e) { std::cerr << e.what() << std::endl; assert(false); abort(); } disable_events(); } // ---------------------------------------------------------------------------------------- } #endif // DLIB_DRAWABLe_CPP_