/* * mogltk * Copyright (C) 1999-2005 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: contextmenu.cc,v 1.3 2006-10-28 16:50:46 pixel Exp $ */ #include #include #include #include "Font.h" #include "engine.h" #include "Widgets.h" #include "sprite.h" /*********************************** * 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() throw (GeneralException) { 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), subselected(0) { 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; }