#include #include #include "font.h" #include "engine.h" #include "widgets.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "gettext.h" mogltk::widget * dragged_widget = 0; class widget_mouse_event : public mogltk::engine::mouseevent { public: widget_mouse_event(mogltk::widget *); virtual void move(SDL_MouseMotionEvent); virtual void action(SDL_MouseButtonEvent); private: mogltk::widget * root; int mouse_x_down, mouse_y_down; bool mouse_down, mouse_drag; Uint32 old_click; }; widget_mouse_event::widget_mouse_event(mogltk::widget * _root) : root(_root), mouse_down(false), mouse_drag(false) { } void widget_mouse_event::move(SDL_MouseMotionEvent m) { bool out_threshold; if (mouse_down) { int dx, dy; dx = ABS(mouse_x_down - mogltk::engine::mouseX()); dy = ABS(mouse_y_down - mogltk::engine::mouseY()); out_threshold = (dx <= 1) && (dy <= 1); } if (mouse_down && (out_threshold || mouse_drag)) { if (!mouse_drag) { printm(M_INFO, "mouse_start_drag\n"); // generate a mouse_start_drag event root->m_event(mouse_x_down, mouse_y_down, mogltk::E_MOUSE_START_DRAG); } if (dragged_widget) { printm(M_INFO, "mouse_drag_over"); // generate a mouse_drag_over event dragged_widget->m_event(mogltk::engine::mouseX(), mogltk::engine::mouseY(), mogltk::E_MOUSE_DRAG_OVER); } printm(M_INFO, "mouse_drag\n"); // generate a mouse_drag event root->m_event(mogltk::engine::mouseX(), mogltk::engine::mouseY(), mogltk::E_MOUSE_DRAG); mouse_drag = true; } else { printm(M_INFO, "mouse_move\n"); root->m_event(mogltk::engine::mouseX(), mogltk::engine::mouseY(), mogltk::E_MOUSE_MOVE); // generate a mouse_move event } } void widget_mouse_event::action(SDL_MouseButtonEvent b) { if (b.button == 1) { if (b.state) { mouse_x_down = mogltk::engine::mouseX(); mouse_y_down = mogltk::engine::mouseY(); mouse_down = true; printm(M_INFO, "mouse_down\n"); root->m_event(mogltk::engine::mouseX(), mogltk::engine::mouseY(), mogltk::E_MOUSE_DOWN); // generate a mouse_down event; } else { mouse_down = false; if (mouse_drag) { mouse_drag = false; printm(M_INFO, "mouse_end_drag\n"); root->m_event(mogltk::engine::mouseX(), mogltk::engine::mouseY(), mogltk::E_MOUSE_END_DRAG); // generate a mouse_end_drag event if (dragged_widget) { printm(M_INFO, "mouse_end_drag_over"); dragged_widget->m_event(mogltk::engine::mouseX(), mogltk::engine::mouseY(), mogltk::E_MOUSE_END_DRAG_OVER); // generate a mouse_end_drag_over event dragged_widget = 0; } } else { printm(M_INFO, "mouse_click\n"); root->m_event(mogltk::engine::mouseX(), mogltk::engine::mouseY(), mogltk::E_MOUSE_CLICK); // generate a mouse_click event if ((SDL_GetTicks() - old_click) < 500) { printm(M_INFO, "mouse_dbl_click\n"); root->m_event(mogltk::engine::mouseX(), mogltk::engine::mouseY(), mogltk::E_MOUSE_DBL_CLICK); // generate a mouse_dbl_click event } old_click = SDL_GetTicks(); } printm(M_INFO, "mouse_up\n"); root->m_event(mogltk::engine::mouseX(), mogltk::engine::mouseY(), mogltk::E_MOUSE_UP); // generate a mouse_up event. } } } mogltk::widget * mogltk::widget::focused = 0; mogltk::widget::widget(widget * _father, int _x, int _y, int _sx, int _sy, int _type, String _name, mogltk::shape * _sh) : x(_x), y(_y), sx(_sx), sy(_sy), father(_father), type(_type), name(_name), sh(_sh), exclusive(0) { if (!father) { root = this; father = this; next = 0; x = 0; y = 0; sx = engine::base_o->GetWidth(); sy = engine::base_o->GetHeight(); } else { next = father->child; if (next) next->prev = this; father->child = this; root = father->root; } prev = 0; child = 0; computeabs(); } mogltk::widget::~widget() { while(child) delete child; if (prev) prev->next = next; else father->child = next; if (next) next->prev = prev; } void mogltk::widget::computeabs() { if (father != this) { ax = father->ax + x; ay = father->ay + y; } else { ax = x; ay = y; } ax2 = ax + sx; ay2 = ay + sy; } void mogltk::widget::move(int nx, int ny) { x = nx; y = ny; computeabs(); if (child) child->icomputeabs(); } void mogltk::widget::resize(int nsx, int nsy) { sx = nsx; sy = nsy; ax2 = ax + sx; ay2 = ay + sy; } int mogltk::widget::GetX() { return x; } int mogltk::widget::GetY() { return y; } int mogltk::widget::GetH() { return sy; } int mogltk::widget::GetW() { return sx; } int mogltk::widget::GetAX() { return ax; } int mogltk::widget::GetAY() { return ay; } int mogltk::widget::GetAX2() { return ax2; } int mogltk::widget::GetAY2() { return ay2; } mogltk::widget * mogltk::widget::Father() { return father; } mogltk::widget * mogltk::widget::Child() { return child; } mogltk::widget * mogltk::widget::Next() { return next; } mogltk::widget * mogltk::widget::Prev() { return prev; } mogltk::shape * mogltk::widget::Shaper() { return sh; } void mogltk::widget::fulldraw() { bool was2D = true; if (mogltk::engine::glbase_o) if (!(was2D = mogltk::engine::glbase_o->is2D())) mogltk::engine::glbase_o->Enter2DMode(); texture::Unbind(); mogltk::ColorP::Max = WHITE; mogltk::ColorP::Min = BLACK; mogltk::ColorP::Min.A = 0; root->idraw(); if (!was2D) mogltk::engine::glbase_o->Leave2DMode(); } void mogltk::widget::idraw() { int x1, y1, x2, y2; if (next) next->idraw(); x1 = MAX(GetAX(), father->GetAX()); y1 = MAX(GetAY(), father->GetAY()); x2 = MIN(GetAX2(), father->GetAX2()); y2 = MIN(GetAY2(), father->GetAY2()); engine::base_o->changeviewport(x1, y1, x2 - x1, y2 - y1); draw(); if (child) child->idraw(); } bool mogltk::widget::inside(int xe, int ye) { return !((xe < ax) || (xe > ax2) || (ye < ay) || (ye > ay2)); } void mogltk::widget::m_event(int x, int y, mogltk::event_t event) { switch (event) { case E_MOUSE_DRAG_OVER: case E_MOUSE_END_DRAG_OVER: process_event(x, y, event); break; default: ievent(x, y, event); } } bool mogltk::widget::ievent(int xe, int ye, mogltk::event_t event) { if (next) if (next->ievent(xe, ye, event)) return true; if (!inside(xe, ye)) return false; if (exclusive) return exclusive->ievent(xe, ye, event); if (child) if (child->ievent(xe, ye, event)) return true; return process_event(xe, ye, event); } void mogltk::widget::draw() { } bool mogltk::widget::process_event(int, int, mogltk::event_t) { return false; } void mogltk::widget::icomputeabs() { computeabs(); if (next) next->computeabs(); if (child) child->computeabs(); } void mogltk::widget::set_exclusive(mogltk::widget * w) { w->exclusive = this; } void mogltk::widget::unset_exclusive(mogltk::widget * w) { w->exclusive = 0; } /* * Predefined widgets. */ /* Here is Root */ mogltk::widgets::Root::Root(mogltk::shape * sh, mogltk::widgets::drawer * _dr) : widget(0, 0, 0, 0, 0, 0, "Root", sh), dr(_dr) { if (engine::root) delete engine::root; engine::root = this; } void mogltk::widgets::Root::draw() { if (dr) dr->draw(this); else Shaper()->box(GetAX(), GetAY(), GetAX2(), GetAY2()); } void mogltk::widgets::Root::setdrawer(drawer * _dr) { dr = _dr; } mogltk::widgets::Button::Button(action * _a, shape * sh, widget * father, int x, int y, int w, int h, const String & _caption) : widget(father, x, y, w, h, 0, "Button", sh), bevel(false), dragging(false), a(_a) { caption = _caption; } void mogltk::widgets::Button::draw() { Shaper()->button(GetAX() + 1, GetAY() + 1, GetAX2() - 1, GetAY2() - 1, caption, bevel); } bool mogltk::widgets::Button::process_event(int xe, int ye, mogltk::event_t event) { switch (event) { case E_MOUSE_DOWN: bevel = true; return true; case E_MOUSE_CLICK: bevel = false; // action here. if (a) a->do_action(this); return true; case E_MOUSE_START_DRAG: dragged_widget = this; dragging = true; return true; case E_MOUSE_DRAG_OVER: bevel = inside(xe, ye); return true; case E_MOUSE_END_DRAG_OVER: dragging = false; if (bevel); // action here. if (a) a->do_action(this); bevel = false; return true; } return false; } mogltk::widgets::SmartBox::SmartBox(shape * sh, mogltk::widget * father, int x, int y, int w, int h, const String & _caption) : widget(father, x, y, w, h, 0, "SmartBox", sh) { caption = _caption; } void mogltk::widgets::SmartBox::draw() { Shaper()->window(GetAX(), GetAY(), GetAX2(), GetAY2(), caption); } bool mogltk::widgets::SmartBox::process_event(int x, int y, mogltk::event_t event) { switch (event) { case E_MOUSE_START_DRAG: if ((GetAY() + 20) > y) { dragged_widget = this; ox = x; oy = y; oax = GetX(); oay = GetY(); return true; } break; case E_MOUSE_DRAG_OVER: move(x - ox + oax, y - oy + oay); return true; } return false; } class MessageBoxAction : public mogltk::widgets::action { public: MessageBoxAction(mogltk::widget * _parent) : parent(_parent) { } virtual void do_action(mogltk::widget *) { delete parent; delete this; } private: mogltk::widget * parent; }; mogltk::widgets::MsgBox::MsgBox(shape * sh, mogltk::widget * father, const String & caption, const String & text) : SmartBox(sh, father, 0, 0, 0, 0, caption) { rect size = SystemFont->size(text); rect lsize = size; size.w += 12; size.h += 60; size.x = (father->GetW() - size.w) / 2; size.y = (father->GetH() - size.h) / 2; resize(size.w, size.h); move(size.x, size.y); new Button(new MessageBoxAction(this), sh, this, size.w / 2 - 25, size.h - 30, 50, 24, "Ok"); new Label(sh, this, 6, 24, lsize.w, lsize.h, text, BLACK); set_exclusive(father); } mogltk::widgets::MsgBox::~MsgBox() { unset_exclusive(Father()); } mogltk::widgets::Label::Label(shape * sh, mogltk::widget * father, int x, int y, int w, int h, const String & _caption, const ColorP & _color) : widget(father, x, y, w, h, 0, "Label", sh), color(_color) { caption = _caption; } void mogltk::widgets::Label::draw() { Shaper()->text(GetAX(), GetAY(), caption, color); } void mogltk::widget::mainloop() { bool end_event_loop = false; widget_mouse_event * mouse = new widget_mouse_event(this); while (!end_event_loop && !engine::quitrequested()) { root->fulldraw(); Shaper()->pixel(engine::mouseX(), engine::mouseY(), BLACK); engine::base_o->Flip(); } delete mouse; }