/* * mogltk * Copyright (C) 1999-2004 Nicolas "Pixel" Noble * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* $Id: widgets.cc,v 1.9 2004-10-19 01:27:30 pixel Exp $ */ #include #include #include #include "font.h" #include "engine.h" #include "widgets.h" #include "sprite.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "gettext.h" mogltk::widget * dragged_widget = 0; std::vector out_move, out_click; std::vector mogltk::widget::timed_events; 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) { int mx, my; bool out_threshold; std::vector::iterator i; std::vector out_move_stack; mx = mogltk::engine::mouseX(); my = mogltk::engine::mouseY(); if (mouse_down) { int dx, dy; dx = ABS(mouse_x_down - mx); dy = ABS(mouse_y_down - my); 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(mx, my, mogltk::E_MOUSE_DRAG_OVER); } printm(M_INFO, "mouse_drag\n"); // generate a mouse_drag event root->m_event(mx, my, mogltk::E_MOUSE_DRAG); mouse_drag = true; } else { printm(M_INFO, "mouse_move\n"); root->m_event(mx, my, mogltk::E_MOUSE_MOVE); // generate a mouse_move event } for (i = out_move.begin(); i != out_move.end(); i++) { out_move_stack.push_back(*i); } for (i = out_move_stack.begin(); i != out_move_stack.end(); i++) { if (!(*i)->inside(mx, my)) { (*i)->m_event(mx, my, mogltk::E_MOUSE_OUT); // generate a mouse_out event } } out_move_stack.empty(); } void widget_mouse_event::action(SDL_MouseButtonEvent b) { int mx, my; std::vector::iterator i; std::vector out_click_stack; mx = mogltk::engine::mouseX(); my = mogltk::engine::mouseY(); if (b.button == 1) { if (b.state) { mouse_x_down = mx; mouse_y_down = my; mouse_down = true; printm(M_INFO, "mouse_down\n"); root->m_event(mx, my, mogltk::E_MOUSE_DOWN); // generate a mouse_down event; for (i = out_click.begin(); i != out_click.end(); i++) { out_click_stack.push_back(*i); } for (i = out_click_stack.begin(); i != out_click_stack.end(); i++) { if (!(*i)->inside(mx, my)) { (*i)->m_event(mx, my, mogltk::E_MOUSE_OUT_CLICK); // generate a mouse_out_click event } } out_click_stack.empty(); } else { mouse_down = false; if (mouse_drag) { mouse_drag = false; printm(M_INFO, "mouse_end_drag\n"); root->m_event(mx, my, 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(mx, my, 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(mx, my, mogltk::E_MOUSE_CLICK); // generate a mouse_click event for (i = out_click.begin(); i != out_click.end(); i++) { out_click_stack.push_back(*i); } for (i = out_click_stack.begin(); i != out_click_stack.end(); i++) { if (!(*i)->inside(mx, my)) { (*i)->m_event(mx, my, mogltk::E_MOUSE_OUT_CLICK); // generate a mouse_out_click event } } out_click_stack.empty(); if ((SDL_GetTicks() - old_click) < 500) { printm(M_INFO, "mouse_dbl_click\n"); root->m_event(mx, my, mogltk::E_MOUSE_DBL_CLICK); // generate a mouse_dbl_click event } old_click = SDL_GetTicks(); } printm(M_INFO, "mouse_up\n"); root->m_event(mx, my, 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), prev(0), child(0), last(0), panel(0), type(_type), name(_name), sh(_sh), exclusive(0), visible(true), enabled(true) { 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; if (!father->last) father->last = this; father->child = this; root = father->root; } computeabs(); } mogltk::widget::~widget() { while(child) delete child; if (prev) prev->next = next; else father->child = next; if (next) next->prev = prev; else father->last = 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; if (child) child->iresize_notify(); } 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::rect mogltk::widget::GetDrawRect() { rect r; r.x = 0; r.y = 0; r.w = GetW(); r.h = GetH(); return r; } 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::widget * mogltk::widget::InnerPanel() { if (!panel) panel = create_panel(); return panel; } mogltk::widget * mogltk::widget::find_widget(int _x, int _y) { widget * r = 0; if (visible && enabled && (_x >= ax) && (_y >= ay) && (_x <= ax2) && (_y <= ay2)) { if (child) r = child->find_widget(_x, _y); if (!r) r = this; } if (!r && next) { r = next->find_widget(_x, _y); } return r; } 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(); if (!visible) return; 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) { if (!visible) return false; 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: case E_MOUSE_OUT: case E_MOUSE_OUT_CLICK: process_event(x, y, event); break; default: ievent(x, y, event); } } bool mogltk::widget::ievent(int xe, int ye, mogltk::event_t event) { if (prev) if (prev->ievent(xe, ye, event)) return true; if (!inside(xe, ye)) return false; if (exclusive) return exclusive->ievent(xe, ye, event); if (last) if (last->ievent(xe, ye, event)) return true; if (!enabled || !visible) return false; 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::resize_notify() { } mogltk::widget * mogltk::widget::create_panel() { mogltk::rect r = GetDrawRect(); return new widgets::Panel(Shaper(), this, r.x, r.y, r.w, r.h); } void mogltk::widget::icomputeabs() { computeabs(); if (next) next->computeabs(); if (child) child->computeabs(); } void mogltk::widget::iresize_notify() { if (next) next->iresize_notify(); if (child) child->iresize_notify(); resize_notify(); } void mogltk::widget::set_exclusive(mogltk::widget * w) { w->exclusive = this; } void mogltk::widget::unset_exclusive(mogltk::widget * w) { w->exclusive = 0; } bool mogltk::widget::GetVisible() { return visible; } void mogltk::widget::SetVisible(bool _visible) { visible = _visible; } bool mogltk::widget::GetEnabled() { return enabled; } void mogltk::widget::SetEnabled(bool _enabled) { enabled = _enabled; } void mogltk::widget::MoveOnTop() { if (!prev) return; if (!next) { father->last = prev; } else { next->prev = prev; } prev->next = next; prev = 0; next = father->child; next->prev = this; father->child = this; } void mogltk::widget::check_timed_events() { std::vector::iterator i; Uint32 t = SDL_GetTicks(); widget * w; for (i = timed_events.begin(); i != timed_events.end(); i++) { if (i->t <= t) { w = i->w; timed_events.erase(i); w->process_event(engine::mouseX(), engine::mouseY(), E_TIMER); i = timed_events.begin(); if (i == timed_events.end()) return ; } } } void mogltk::widget::add_out_move() { std::vector::iterator i; for (i = out_move.begin(); i != out_move.end(); i++) { if (*i == this) return; } out_move.push_back(this); } void mogltk::widget::remove_out_move() { std::vector::iterator i; for (i = out_move.begin(); i != out_move.end(); i++) { if (*i == this) { out_move.erase(i); return; } } } void mogltk::widget::add_out_click() { std::vector::iterator i; for (i = out_click.begin(); i != out_click.end(); i++) { if (*i == this) return; } out_click.push_back(this); } void mogltk::widget::remove_out_click() { std::vector::iterator i; for (i = out_click.begin(); i != out_click.end(); i++) { if (*i == this) { out_click.erase(i); return; } } } void mogltk::widget::set_timed_event(Uint32 t) { timed_events.push_back(timed_event(this, SDL_GetTicks() + t)); } void mogltk::widget::set_absolute_timed_event(Uint32 t) { timed_events.push_back(timed_event(this, t)); } /* * 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; } /************************** * A simple clipping Panel * **************************/ mogltk::widgets::Panel::Panel(shape * sh, widget * father, int x, int y, int w, int h) : widget(father, x, y, w, h, 0, "Panel", sh) { } /*********************** * The classical Button * ***********************/ 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; } /********************** * The SmartBox window * **********************/ 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); MoveOnTop(); return true; } return false; } mogltk::rect mogltk::widgets::SmartBox::GetDrawRect() { rect r; r.x = 2; r.y = 21; r.w = GetW() - 4; r.h = GetH() - 23; return r; } /*********************** * The MessageBox child * ***********************/ 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()); } /***************** * A simple Label * *****************/ 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); } /************************* * The classical 3D Frame * *************************/ mogltk::widgets::Frame::Frame(shape * sh, widget * father, int x, int y, int w, int h) : widget(father, x, y, w, h, 0, "Frame", sh) { } void mogltk::widgets::Frame::draw() { Shaper()->obox3d(GetAX(), GetAY(), GetAX2(), GetAY2()); } mogltk::rect mogltk::widgets::Frame::GetDrawRect() { rect r; r.x = 4; r.y = 4; r.w = GetW() - 8; r.h = GetH() - 8; return r; } /*********************************** * The huge and bloated ContextMenu * ***********************************/ mogltk::widgets::ContextMenu::node::node(const String & _caption, int _x, int _y, int _w, int _h, mogltk::widgets::action * _a, mogltk::widgets::ContextMenu * _sub, mogltk::widgets::ContextMenu * _father, bool _line) : caption(_caption), x(_x), y(_y), w(_w), h(_h), a(_a), sub(_sub), father(_father), line(_line), enabled(true) { } String mogltk::widgets::ContextMenu::node::GetCaption() { return caption; } mogltk::widgets::action * mogltk::widgets::ContextMenu::node::GetAction() { return a; } mogltk::widgets::ContextMenu * mogltk::widgets::ContextMenu::node::GetFather() { return father; } mogltk::widgets::ContextMenu * mogltk::widgets::ContextMenu::node::GetSub() { return sub; } bool mogltk::widgets::ContextMenu::node::GetLine() { return line; } bool mogltk::widgets::ContextMenu::node::GetEnabled() { return enabled; } void mogltk::widgets::ContextMenu::node::SetEnabled(bool _enabled) { enabled = _enabled; } int mogltk::widgets::ContextMenu::node::GetX() { return x; } int mogltk::widgets::ContextMenu::node::GetY() { return y; } int mogltk::widgets::ContextMenu::node::GetW() { return w; } int mogltk::widgets::ContextMenu::node::GetH() { return h; } mogltk::widgets::ContextMenu::ContextMenu(shape * sh, mogltk::widget * father, int x, int y) : widget(father, x, y, 8, 4, 1, "ContextMenu", sh), selected(-1), subselected(0), in_click(false), sticky(false) { } mogltk::widgets::ContextMenu::~ContextMenu() { std::vector::iterator i; ContextMenu * sub; for (i = nodes.begin(); i != nodes.end(); i++) { if ((sub = i->GetSub())) delete sub; } } void mogltk::widgets::ContextMenu::addnode(const String & caption, mogltk::widgets::action * a) { rect size; size = SystemFont->size(caption); nodes.push_back(node(caption, 4, GetH() - 2, size.w, size.h, a, 0, this, false)); size.w += 8; if (GetW() > size.w) size.w = GetW(); resize(size.w, GetH() + size.h); } void mogltk::widgets::ContextMenu::addsub(const String & caption, mogltk::widgets::ContextMenu * sub) { rect size; size = SystemFont->size(caption + " >"); nodes.push_back(node(caption + " >", 4, GetH() - 2, size.w, size.h, 0, sub, this, false)); size.w += 8; if (GetW() > size.w) size.w = GetW(); resize(size.w, GetH() + size.h); } void mogltk::widgets::ContextMenu::addline() { nodes.push_back(node("", 2, GetH() - 1, 0, 0, 0, 0, this, true)); resize(GetW(), GetH() + 4); } mogltk::widgets::ContextMenu * mogltk::widgets::ContextMenu::createsub(const String & caption) { ContextMenu * r; r = new ContextMenu(Shaper(), Father(), GetX() + GetW(), GetY() + GetH()); r->SetVisible(false); addsub(caption, r); return r; } void mogltk::widgets::ContextMenu::move(int x, int y) { int dx, dy; std::vector::iterator i; ContextMenu * sub; dx = x - GetX(); dy = y - GetY(); widget::move(x, y); for (i = nodes.begin(); i != nodes.end(); i++) { if ((sub = i->GetSub())) sub->move(sub->GetX() + dx, sub->GetY() + dy); } } void mogltk::widgets::ContextMenu::resize(int w, int h) { int dw; std::vector::iterator i; ContextMenu * sub; dw = w - GetW(); widget::resize(w, h); for (i = nodes.begin(); i != nodes.end(); i++) { if ((sub = i->GetSub())) sub->move(sub->GetX() + dw, sub->GetY()); } } void mogltk::widgets::ContextMenu::SetVisible(bool visible) { if (!visible && sticky) return; widget::SetVisible(visible); if (!visible && subselected) { subselected->SetVisible(false); } if (visible) { add_out_click(); MoveOnTop(); } } void mogltk::widgets::ContextMenu::SetEnabled(int i, bool e) { nodes[i].SetEnabled(e); } void mogltk::widgets::ContextMenu::StickyDisplay() { sticky = true; SetVisible(true); } void mogltk::widgets::ContextMenu::draw() { std::vector::iterator i; int n; rect size; Shaper()->box3d(GetAX(), GetAY(), GetAX2(), GetAY2()); for (i = nodes.begin(), n = 0; i != nodes.end(); i++, n++) { size = SystemFont->size(i->GetCaption()); if (i->GetLine()) { Shaper()->hline3d(GetAX() + i->GetX(), GetAX() + i->GetX() + GetW() - 4, GetAY() + i->GetY()); } else { if (n == selected) { Shaper()->box(GetAX() + 2, GetAY() + i->GetY(), GetAX() + GetW() - 2, GetAY() + i->GetY() + i->GetH(), DOS_MAGENTA); } Shaper()->text(GetAX() + i->GetX(), GetAY() + i->GetY(), i->GetCaption(), i->GetEnabled() ? BLACK : DOS_GRAY); } } } bool mogltk::widgets::ContextMenu::process_event(int xe, int ye, mogltk::event_t event) { std::vector::iterator i; action * a; int n; switch (event) { case E_MOUSE_MOVE: sticky = false; selected = -1; for (i = nodes.begin(), n = 0; i != nodes.end(); i++, n++) { if (!i->GetLine()) { int ax, ax2, ay, ay2; ax = GetAX() + 2; ay = GetAY() + i->GetY(); ax2 = GetAX() + GetW() - 2; ay2 = GetAY() + i->GetY() + i->GetH(); if (!((xe < ax) || (xe > ax2) || (ye < ay) || (ye > ay2))) { selected = n; if (subselected) { subselected->SetVisible(false); subselected->selected = -1; subselected->subselected = 0; } if ((subselected = i->GetSub())) { subselected->SetVisible(true); subselected->selected = -1; subselected->subselected = 0; } } } } add_out_move(); return true; case E_MOUSE_CLICK: a = 0; if (selected != -1) { if ((a = nodes[selected].GetAction()) && nodes[selected].GetEnabled()) { a->do_action(this); in_click = false; SetVisible(false); return true; } } in_click = true; break; case E_MOUSE_DOWN: in_click = true; break; case E_MOUSE_OUT: selected = -1; remove_out_move(); in_click = false; return true; case E_MOUSE_OUT_CLICK: if (iin_click()) return true; selected = -1; subselected = 0; SetVisible(false); return true; } return false; } bool mogltk::widgets::ContextMenu::iin_click() { if (in_click) return true; if (subselected) return subselected->iin_click(); return false; } /******************** * The Menu topframe * ********************/ mogltk::widgets::Menu::node::node(const String & _caption, mogltk::widgets::ContextMenu * _sub, mogltk::widgets::action * _a, int _x) : caption(_caption), sub(_sub), a(_a), x(_x) { } String mogltk::widgets::Menu::node::GetCaption() { return caption; } void mogltk::widgets::Menu::node::SetCaption(const String & s) { caption = s; } mogltk::widgets::ContextMenu * mogltk::widgets::Menu::node::GetSub() { return sub; } mogltk::widgets::action * mogltk::widgets::Menu::node::GetAction() { return a; } int mogltk::widgets::Menu::node::GetX() { return x; } bool mogltk::widgets::Menu::node::GetEnabled() { return enabled; } void mogltk::widgets::Menu::node::SetEnabled(bool _enabled) { enabled = _enabled; } mogltk::widgets::Menu::Menu(shape * sh, mogltk::widget * father) : widget(father, 0, 0, 0, 0, 0, "Menu", sh), cur_x(0), selected(-1) { rect r = father->GetDrawRect(); move(r.x, r.y); resize(r.w, 16); } void mogltk::widgets::Menu::resize_notify() { rect r = Father()->GetDrawRect(); resize(r.w, 16); } void mogltk::widgets::Menu::addnode(const String & caption, mogltk::widgets::action * a) { nodes.push_back(node(caption, 0, a, cur_x)); cur_x += SystemFont->singletextsize(caption) + 6; } void mogltk::widgets::Menu::addsub(const String & caption, mogltk::widgets::ContextMenu * sub) { nodes.push_back(node(caption, sub, 0, cur_x)); cur_x += SystemFont->singletextsize(caption) + 6; } mogltk::widgets::ContextMenu * mogltk::widgets::Menu::createsub(const String & caption) { ContextMenu * r = new ContextMenu(Shaper(), Father(), GetX() + cur_x, GetY() + 16); addsub(caption, r); r->SetVisible(false); return r; } void mogltk::widgets::Menu::SetEnabled(int i, bool e) { nodes[i].SetEnabled(e); } void mogltk::widgets::Menu::SetCaption(int i, const String & s) { nodes[i].SetCaption(s); } void mogltk::widgets::Menu::draw(void) { std::vector::iterator i; int n; Shaper()->box(GetAX(), GetAY(), GetAX2(), GetAY2(), DOS_WHITE); for (i = nodes.begin(), n = 0; i != nodes.end(); i++, n++) { if (selected == n) { if ((i + 1) == nodes.end()) { Shaper()->box(GetAX() + i->GetX(), GetAY(), cur_x, GetAY2(), DOS_MAGENTA); } else { Shaper()->box(GetAX() + i->GetX(), GetAY(), GetAX() + i[1].GetX(), GetAY2(), DOS_MAGENTA); } } Shaper()->text(GetAX() + i->GetX() + 3, GetAY(), i->GetCaption(), BLACK); } } bool mogltk::widgets::Menu::process_event(int mx, int my, mogltk::event_t event) { std::vector::iterator i; action * a; ContextMenu * sub; int n; switch (event) { case E_MOUSE_MOVE: selected = -1; for (i = nodes.begin(), n = 0; i != nodes.end(); i++, n++) { int ax, ax2, ay, ay2; ax = GetAX() + i->GetX(); ay = GetAY(); if ((i + 1) != nodes.end()) { ax2 = GetAX() + i[1].GetX(); } else { ax2 = GetAX() + cur_x; } ay2 = GetAY2(); if (!((mx < ax) || (mx > ax2) || (my < ay) || (my > ay2))) { selected = n; } } add_out_move(); return true; case E_MOUSE_CLICK: a = 0; if (selected != -1) { if ((a = nodes[selected].GetAction()) && nodes[selected].GetEnabled()) { a->do_action(this); return true; } else if ((sub = nodes[selected].GetSub()) && nodes[selected].GetEnabled()) { sub->StickyDisplay(); return true; } } break; case E_MOUSE_OUT: selected = -1; remove_out_move(); return true; } return false; } /* * The mainloop widget thing. */ void mogltk::widget::mainloop() { bool end_event_loop = false; widget_mouse_event * mouse = new widget_mouse_event(this); widget * w; int mx, my; while (!end_event_loop && !engine::quitrequested()) { root->fulldraw(); mx = mogltk::engine::mouseX(); my = mogltk::engine::mouseY(); mogltk::ColorP::Max.A = 50; Sprite::Cursor->draw(mx - 6, my - 3, BLACK); mogltk::ColorP::Max.A = 255; Sprite::Cursor->draw(mx - 8, my - 6); if (w = root->find_widget(mx, my)) { sh->box(w->GetAX(), w->GetAY(), w->GetAX2(), w->GetAY2(), Color(100, 150, 60, 50)); } engine::base_o->Flip(); widget::check_timed_events(); } delete mouse; }