123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- #include <ClanLib/Display/display.h>
- #include <ClanLib/Display/sprite.h>
- #include "fonts.hpp"
- #include "box.hpp"
- #include "menu.hpp"
- class MenuItem;
- class MenuImpl
- {
- public:
- Menu* parent;
- std::vector<CL_Slot> slots;
- typedef std::vector<MenuItem*> Items;
- Items items;
- int current_item;
- int width;
- int height;
- MenuImpl() {
- current_item = -1;
- }
- void draw();
- void recalc_size();
- int get_width();
- int get_height();
- void on_mouse_move(const CL_InputEvent& event);
- void on_mouse_down(const CL_InputEvent& event);
- };
- class MenuItem
- {
- protected:
- MenuImpl* parent;
- CL_Signal_v0 on_clicked;
- public:
- MenuItem(MenuImpl* parent_)
- : parent(parent_) {}
- virtual ~MenuItem() {}
- virtual void draw(int x, int y, bool active) =0;
- virtual int get_width() =0;
- virtual int get_height() =0;
- CL_Signal_v0& sig_clicked() { return on_clicked; }
- };
- class SeparatorMenuItem : public MenuItem
- {
- public:
- SeparatorMenuItem(MenuImpl* parent_)
- : MenuItem(parent_)
- {}
- virtual ~SeparatorMenuItem() {}
- void draw(int x, int y, bool active)
- {
- CL_Display::fill_rect(CL_Rect(CL_Point(x, y), CL_Size(parent->get_width()-7, 2)),
- CL_Color(150, 150, 150));
- CL_Display::fill_rect(CL_Rect(CL_Point(x, y+1), CL_Size(parent->get_width()-7, 1)),
- CL_Color(255, 255, 255));
- }
- int get_width() { return 10; }
- int get_height() { return 2; }
- };
- class TextMenuItem : public MenuItem
- {
- private:
- CL_Sprite sprite;
- std::string text;
- public:
- TextMenuItem(const CL_Sprite& sprite_, const std::string& text_, MenuImpl* parent_)
- : MenuItem(parent_),
- sprite(sprite_),
- text(text_)
- {
- if (sprite)
- sprite.set_alignment(origin_center);
- }
- virtual ~TextMenuItem() {}
- void draw(int x, int y, bool active) {
- if (active)
- CL_Display::fill_rect(CL_Rect(CL_Point(x, y-2), CL_Size(parent->get_width() - 7, 18)),
- CL_Color(255, 255, 255));
- if (sprite)
- {
- sprite.draw(x+10, y+7);
- }
- Fonts::verdana11.draw(x+24, y, text);
- }
- int get_width() { return Fonts::verdana11.bounding_rect(0, 0, text).get_width() + 16; }
- int get_height() { return Fonts::verdana11.get_height(); }
- };
- Menu::Menu(const CL_Point& pos, CL_Component* parent)
- : CL_Component(CL_Rect(pos, CL_Size(1,1)), parent),
- impl(new MenuImpl())
- {
- impl->parent = this;
- impl->width = 1;
- impl->height = 1;
- impl->slots.push_back(sig_paint().connect(impl.get(), &MenuImpl::draw));
- impl->slots.push_back(sig_mouse_move().connect(impl.get(), &MenuImpl::on_mouse_move));
- impl->slots.push_back(sig_mouse_down().connect(impl.get(), &MenuImpl::on_mouse_down));
- show(false);
- }
- Menu::~Menu()
- {
- clear();
- }
- void
- Menu::clear()
- {
- for(MenuImpl::Items::iterator i = impl->items.begin(); i != impl->items.end(); ++i)
- delete *i;
- impl->items.clear();
- }
- MenuItemHandle
- Menu::add_separator()
- {
- impl->items.push_back(new SeparatorMenuItem(impl.get()));
- impl->recalc_size();
- return impl->items.size()-1;
- }
- MenuItemHandle
- Menu::add_item(const std::string& name)
- {
- impl->items.push_back(new TextMenuItem(CL_Sprite(), name, impl.get()));
- impl->recalc_size();
- return impl->items.size()-1;
- }
- MenuItemHandle
- Menu::add_item(const CL_Sprite& sprite, const std::string& name)
- {
- impl->items.push_back(new TextMenuItem(sprite, name, impl.get()));
- impl->recalc_size();
- return impl->items.size()-1;
- }
- MenuItemHandle
- Menu::add_submenu(const std::string& name, const Menu& submenu)
- {
- impl->recalc_size();
- return -1;
- }
- void
- MenuImpl::recalc_size()
- {
- height = 0;
- width = 0;
- for(Items::iterator i = items.begin(); i != items.end(); ++i)
- width = std::max(width, (*i)->get_width());
- for(Items::iterator i = items.begin(); i != items.end(); ++i)
- height += (*i)->get_height() + 6;
- width += 12 + 24;
- height += 8;
- parent->set_size(width, height);
- }
- void
- MenuImpl::draw()
- {
- CL_Display::push_translate(parent->get_screen_x(), parent->get_screen_y());
- Box::draw_window(CL_Rect(CL_Point(0, 0),
- CL_Size(parent->get_width(),
- parent->get_height())));
- int x_pos = 3;
- int y_pos = 6;
- for(int i = 0; i < int(items.size()); ++i)
- {
- if (i == current_item)
- items[i]->draw(x_pos, y_pos, true);
- else
- items[i]->draw(x_pos, y_pos, false);
- y_pos += items[i]->get_height() + 6;
- }
- CL_Display::pop_modelview();
- }
- int
- MenuImpl::get_width()
- {
- return width;
- }
- int
- MenuImpl::get_height()
- {
- return height;
- }
- void
- MenuImpl::on_mouse_down(const CL_InputEvent& event)
- {
- if (current_item != -1)
- {
- items[current_item]->sig_clicked()();
- }
- parent->release_mouse();
- parent->show(false);
- }
- void
- MenuImpl::on_mouse_move(const CL_InputEvent& event)
- {
- if (parent->has_mouse_over())
- {
- int y_pos = 6;
- for(int i = 0; i < int(items.size()); ++i)
- {
- y_pos += items[i]->get_height() + 6;
- if (y_pos > event.mouse_pos.y)
- {
- current_item = i;
- return;
- }
- }
- current_item = -1;
- }
- else
- {
- current_item = -1;
- }
- }
- CL_Signal_v0&
- Menu::sig_clicked(MenuItemHandle item)
- {
- return impl->items[item]->sig_clicked();
- }
- void
- Menu::run()
- {
-
- if (impl->items.size() > 0)
- {
- show(true);
- capture_mouse();
- raise();
- }
- }
|