diff options
Diffstat (limited to 'src/ui')
-rw-r--r-- | src/ui/Makefile.am | 6 | ||||
-rw-r--r-- | src/ui/bitmap.cc | 11 | ||||
-rw-r--r-- | src/ui/bitmap.h | 33 | ||||
-rw-r--r-- | src/ui/button.cc | 32 | ||||
-rw-r--r-- | src/ui/button.h | 45 | ||||
-rw-r--r-- | src/ui/container.h | 36 | ||||
-rw-r--r-- | src/ui/definitions.h | 7 | ||||
-rw-r--r-- | src/ui/font.cc | 13 | ||||
-rw-r--r-- | src/ui/font.h | 51 | ||||
-rw-r--r-- | src/ui/input.cc | 174 | ||||
-rw-r--r-- | src/ui/input.h | 55 | ||||
-rw-r--r-- | src/ui/label.cc | 13 | ||||
-rw-r--r-- | src/ui/label.h | 38 | ||||
-rw-r--r-- | src/ui/menu.cc | 47 | ||||
-rw-r--r-- | src/ui/menu.h | 22 | ||||
-rw-r--r-- | src/ui/paint.cc | 66 | ||||
-rw-r--r-- | src/ui/paint.h | 12 | ||||
-rw-r--r-- | src/ui/palette.cc | 16 | ||||
-rw-r--r-- | src/ui/palette.h | 51 | ||||
-rw-r--r-- | src/ui/ui.cc | 191 | ||||
-rw-r--r-- | src/ui/ui.h | 99 | ||||
-rw-r--r-- | src/ui/widget.cc | 253 | ||||
-rw-r--r-- | src/ui/widget.h | 330 | ||||
-rw-r--r-- | src/ui/window.cc | 9 | ||||
-rw-r--r-- | src/ui/window.h | 24 |
25 files changed, 1122 insertions, 512 deletions
diff --git a/src/ui/Makefile.am b/src/ui/Makefile.am index 5c7815b..b0f1625 100644 --- a/src/ui/Makefile.am +++ b/src/ui/Makefile.am @@ -7,9 +7,9 @@ else noinst_LTLIBRARIES = libui.la endif -noinst_HEADERS = bitmap.h button.h definitions.h font.h label.h \ +noinst_HEADERS = bitmap.h button.h container.h definitions.h font.h input.h label.h \ menu.h paint.h palette.h ui.h widget.h window.h -libui_la_SOURCES = bitmap.cc button.cc font.cc label.cc menu.cc paint.cc \ - palette.cc ui.cc widget.cc window.cc +libui_la_SOURCES = bitmap.cc button.cc font.cc input.cc label.cc menu.cc \ + paint.cc palette.cc ui.cc widget.cc window.cc libui_la_LDFLAGS = -avoid-version -no-undefined diff --git a/src/ui/bitmap.cc b/src/ui/bitmap.cc index c14ccff..fcf141c 100644 --- a/src/ui/bitmap.cc +++ b/src/ui/bitmap.cc @@ -24,13 +24,13 @@ Bitmap::Bitmap(Widget *parent, const char *texture) : Widget(parent) Bitmap::~Bitmap() {} -void Bitmap::print(size_t indent) +void Bitmap::print(const size_t indent) const { std::string marker(""); con_print << aux::pad_left(marker, indent*2) << label() << " \"" << texture() << "\"" << std::endl; } -void Bitmap::set_texture(std::string const & texture) +void Bitmap::set_texture(const std::string & texture) { bitmap_texture.assign(texture); } @@ -43,10 +43,15 @@ void Bitmap::set_texture(const char *texture) bitmap_texture.clear(); } +void Bitmap::set_color(const math::Color & color) +{ + bitmap_color.assign(color); +} + void Bitmap::draw_background() { if (bitmap_texture.size()) { - paint::color(1.0f, 1.0f, 1.0f, 1.0f); + paint::color(bitmap_color); paint::bitmap(global_location(), size(), bitmap_texture); } } diff --git a/src/ui/bitmap.h b/src/ui/bitmap.h index 1f60ef9..9bc1776 100644 --- a/src/ui/bitmap.h +++ b/src/ui/bitmap.h @@ -9,25 +9,38 @@ #include "ui/widget.h" -namespace ui { +namespace ui +{ -class Bitmap : public Widget { +class Bitmap : public Widget +{ public: - Bitmap (Widget *parent, const char *texture=0); + Bitmap(Widget *parent, const char *texture=0); ~Bitmap(); - - inline std::string const &texture() const { return bitmap_texture; } - void set_texture(std::string const & texture); + + inline std::string const &texture() const { + return bitmap_texture; + } + + inline math::Color const &color() const { + return bitmap_color; + } + + void set_texture(const std::string & texture); void set_texture(const char *texture); - + + void set_color(const math::Color &color); + /// print bitmap description - virtual void print(size_t indent); - + virtual void print(const size_t indent) const; + protected: + /// draw the bitmap as background virtual void draw_background(); - + private: std::string bitmap_texture; + math::Color bitmap_color; }; } diff --git a/src/ui/button.cc b/src/ui/button.cc index 1ac5fd8..08fd0e9 100644 --- a/src/ui/button.cc +++ b/src/ui/button.cc @@ -11,9 +11,10 @@ #include "ui/button.h" #include "core/commandbuffer.h" -namespace ui { +namespace ui +{ -Button::Button (Widget *parent, const char *text, const char *command) : Label(parent, text) +Button::Button(Widget *parent, const char *text, const char *command) : Label(parent, text) { set_label("button"); set_command(command); @@ -24,7 +25,7 @@ Button::~Button() { } -void Button::print(size_t indent) +void Button::print(const size_t indent) const { std::string marker(""); con_print << aux::pad_left(marker, indent*2) << label() << " \"" << text() << "\" \"" << command() << "\"" << std::endl; @@ -38,7 +39,7 @@ void Button::set_command(const char *command) button_command.clear(); } -void Button::set_command(std::string const &command) +void Button::set_command(const std::string &command) { button_command.assign(command); } @@ -47,12 +48,12 @@ void Button::draw_border() { if (!border()) return; - - if (has_focus()) + + if (has_mouse_focus()) paint::color(palette()->foreground()); else paint::color(palette()->border()); - + paint::border(global_location(), size()); } @@ -60,29 +61,34 @@ void Button::draw_text() { if (!text().size()) return; - - if (has_focus()) + + if (has_mouse_focus()) paint::color(palette()->highlight()); else paint::color(palette()->foreground()); - + paint::text(global_location(), size(), font(), text(), alignment()); } -bool Button::keypress(unsigned int key, unsigned int modifier) +bool Button::on_keypress(const int key, const unsigned int modifier) { return false; } -bool Button::keyrelease(unsigned int key, unsigned int modifier) +bool Button::on_keyrelease(const int key, const unsigned int modifier) { if (key == 512 + SDL_BUTTON_LEFT) { core::cmd() << button_command << std::endl; audio::play("ui/button"); return true; } - + return false; } +void Button::on_mouseover(const math::Vector2f &cursor) +{ + audio::play("ui/select"); +} + } diff --git a/src/ui/button.h b/src/ui/button.h index c074467..b1bb522 100644 --- a/src/ui/button.h +++ b/src/ui/button.h @@ -10,32 +10,45 @@ #include <string> #include "ui/label.h" -namespace ui { +namespace ui +{ -class Button : public Label { +class Button : public Label +{ public: - Button (Widget *parent, const char *text=0, const char *command=0); + Button(Widget *parent, const char *text=0, const char *command=0); ~Button(); - - void set_command(std::string const &command); + + /// set the command this button will execute + void set_command(const std::string &command); + + /// set the command this button will execute void set_command(const char *command); - - inline std::string const & command() const { return button_command; } - + + /// the command this button executes + inline const std::string & command() const { + return button_command; + } + /// print button description - virtual void print(size_t indent); - - /// handle keyboard events - virtual bool keypress(unsigned int key, unsigned int modifier); - virtual bool keyrelease(unsigned int key, unsigned int modifier); - + virtual void print(const size_t indent) const; + + /// called when the mouse enters the widget + virtual void on_mouseover(const math::Vector2f &cursor); + + /// called when the widget receives a key press + virtual bool on_keypress(const int key, const unsigned int modifier); + + /// called when the widget receives a key release + virtual bool on_keyrelease(const int key, const unsigned int modifier); + protected: /// draw the button border virtual void draw_border(); - + /// draw the button text virtual void draw_text(); - + private: std::string button_command; }; diff --git a/src/ui/container.h b/src/ui/container.h new file mode 100644 index 0000000..77e987e --- /dev/null +++ b/src/ui/container.h @@ -0,0 +1,36 @@ +/* + ui/container.h + This file is part of the Osirion project and is distributed under + the terms of the GNU General Public License version 2 +*/ + +/* +#ifndef __INCLUDED_UI_CONTAINER_H__ +#define __INCLUDED_UI_CONTAINER_H__ + +#include <string> +#include "ui/widget.h" + +namespace ui { + +/// a widget containing childs of equal size +class Container : public Widget { +public: + Container(Widget *parent); + ~Container(); + + void set_margin(const float h, const float v); + void set_child_size(const float width, const float height); + +protected: + virtual void resize(); + +private: + math::Vector2f container_child_size; +}; + +} + +#endif // __INCLUDED_UI_CONTAINER_H__ +*/ + diff --git a/src/ui/definitions.h b/src/ui/definitions.h index d5d7fe9..b9b4e3c 100644 --- a/src/ui/definitions.h +++ b/src/ui/definitions.h @@ -7,18 +7,19 @@ #ifndef __INCLUDED_UI_DEFINITIONS_H__ #define __INCLUDED_UI_DEFINITIONS_H__ -namespace ui { +namespace ui +{ enum Alignment { AlignAuto = 0x0000, AlignLeft = 0x0001, AlignHCenter = 0x0002, AlignRight = 0x0004, - + AlignTop = 0x0010, AlignVCenter = 0x0020, AlignBottom = 0x0040, - + AlignCenter = AlignHCenter | AlignVCenter }; diff --git a/src/ui/font.cc b/src/ui/font.cc index 26d4155..9d721fd 100644 --- a/src/ui/font.cc +++ b/src/ui/font.cc @@ -6,7 +6,8 @@ #include "ui/font.h" -namespace ui { +namespace ui +{ Font::Font(const char *name, const float width, const float height) { @@ -23,17 +24,17 @@ void Font::set_size(const float width, const float height) font_size.assign(width, height); } -void Font::set_size(math::Vector2f const &size) +void Font::set_size(const math::Vector2f &size) { font_size.assign(size); } -void Font::set_width(float width) +void Font::set_width(const float width) { font_size.x = width; } -void Font::set_height(float height) +void Font::set_height(const float height) { font_size.y = height; } @@ -46,12 +47,10 @@ void Font::set_name(const char *name) font_name.clear(); } -void Font::set_name(std::string const & name) +void Font::set_name(const std::string & name) { font_name.assign(name); } } - - diff --git a/src/ui/font.h b/src/ui/font.h index a68dec8..1261427 100644 --- a/src/ui/font.h +++ b/src/ui/font.h @@ -10,38 +10,47 @@ #include <string> #include "math/vector2f.h" -namespace ui { +namespace ui +{ class Font { public: Font(const char *name, const float width, const float height); ~Font(); - - inline std::string const & name() const { return font_name; } - - inline math::Vector2f const & size() const { return font_size; } - - inline float const width() const { return font_size.x; } - - inline float const height() const { return font_size.y; } - + + inline const std::string & name() const { + return font_name; + } + + inline const math::Vector2f & size() const { + return font_size; + } + + inline float width() const { + return font_size.x; + } + + inline float height() const { + return font_size.y; + } + void set_size(const float width, const float height); - - void set_size(math::Vector2f const &size); - - void set_width(float width); - - void set_height(float height); - + + void set_size(const math::Vector2f &size); + + void set_width(const float width); + + void set_height(const float height); + void set_name(const char *name); - - void set_name(std::string const & name); - + + void set_name(const std::string & name); + private: std::string font_name; - + math::Vector2f font_size; }; diff --git a/src/ui/input.cc b/src/ui/input.cc new file mode 100644 index 0000000..0c4ea32 --- /dev/null +++ b/src/ui/input.cc @@ -0,0 +1,174 @@ +/* + ui/input.cc + This file is part of the Osirion project and is distributed under + the terms of the GNU General Public License version 2 +*/ + +#include "ui/input.h" +#include "ui/paint.h" +#include "auxiliary/functions.h" +#include "core/core.h" +#include "render/render.h" + +namespace ui +{ + +Input::Input(Widget *parent) : Widget(parent) +{ + input_text.clear(); + input_pos = 0; + + set_label("input"); + set_background(false); + set_border(false); +} + +Input::~Input() +{ +} + +void Input::clear() +{ + input_text.clear(); + input_pos = 0; +} +void Input::set_text(std::string const &text) +{ + input_text.assign(text); + input_pos = input_text.size(); +} + +void Input::set_text(const char *text) +{ + if (text) + input_text.assign(text); + else + input_text.clear(); + input_pos = input_text.size(); +} + +void Input::draw() +{ + draw_background(); + draw_border(); + + using namespace render; + size_t text_width = (size_t) width() / font()->width(); + math::Vector2f v(global_location()); + paint::color(palette()->foreground()); + + std::string firstpart(input_text.substr(0, input_pos)); + size_t draw_width = 0; + const char *c = firstpart.c_str(); + + while (*c) { + if (aux::is_color_code(c)) { + c++; + } else { + draw_width++; + } + c++; + } + + c = firstpart.c_str(); + while (*c && draw_width > text_width - 2) { + if (aux::is_color_code(c)) { + c++; + Text::setcolor(*c); + } else { + draw_width--; + } + c++; + } + + // draw the part before the cursor + if (*c) { + paint::text(v, size(), font(), std::string(c), AlignLeft | AlignVCenter); + } + + // draw the part behind the cursor + v.x += draw_width * font()->width(); + if (input_pos < input_text.size()) { + // FIXME limit to width + if (input_pos > 1 && aux::is_color_code(input_text.c_str() + input_pos -1)) { + Text::setcolor(input_text[input_pos]); + } + c = input_text.c_str() + input_pos; + paint::text(v, size(), font(), std::string(c), AlignLeft | AlignVCenter); + } + + // draw cursor + if (has_input_focus() && (core::application()->time() - ::floorf(core::application()->time())) < 0.5f) { + std::string cursor("^B"); + cursor += (char) 11; + paint::text(v, size(), font(), cursor, AlignLeft | AlignVCenter); + } +} + +bool Input::on_keypress(const int key, const unsigned int modifier) +{ + switch (key) { + case SDLK_TAB: + core::CommandBuffer::complete(input_text, input_pos); + return true; + break; + + case SDLK_HOME: + input_pos = 0; + return true; + break; + + case SDLK_END: + input_pos = input_text.size(); + return true; + break; + + case SDLK_LEFT: + if (input_pos > 0) + input_pos--; + return true; + break; + + case SDLK_RIGHT: + if (input_pos < input_text.size()) + input_pos++; + return true; + break; + + case SDLK_DELETE: + if (input_text.size() && input_pos < input_text.size()) { + input_text.erase(input_pos, 1); + } + return true; + break; + + case SDLK_BACKSPACE: + if (input_text.size() && input_pos) { + input_text.erase(input_pos-1, 1); + input_pos--; + } + return true; + break; + + default: + if ((key >= 32) && (key <175)) { + if (input_pos == input_text.size()) + input_text += (char)key; + else + input_text.insert(input_pos, 1, (char)key); + input_pos++; + return true; + } + break; + } + + return false; +} +bool Input::on_keyrelease(const int key, const unsigned int modifier) +{ + return false; +} + +} + + diff --git a/src/ui/input.h b/src/ui/input.h new file mode 100644 index 0000000..214f63e --- /dev/null +++ b/src/ui/input.h @@ -0,0 +1,55 @@ +/* + ui/input.h + This file is part of the Osirion project and is distributed under + the terms of the GNU General Public License version 2 +*/ + +#ifndef __INCLUDED_UI_INPUT_H__ +#define __INCLUDED_UI_INPUT_H__ + +#include "ui/widget.h" + +namespace ui +{ + +/// text input widget +class Input : public Widget +{ +public: + Input(Widget *parent); + ~Input(); + + /// set the text displayed by the label + void set_text(std::string const &text); + + /// set the text displayed by the label + void set_text(const char *text); + + /// return the text displayed by the label + inline std::string const &text() const { + return input_text; + } + + /// clear the text + void clear(); + +protected: + /// draw the widget + virtual void draw(); + + /// called when the widget receives a key press + virtual bool on_keypress(const int key, const unsigned int modifier); + + /// called when the widget receives a key release + virtual bool on_keyrelease(const int key, const unsigned int modifier); + +private: + + std::string input_text; + size_t input_pos; +}; + +} + +#endif // __INCLUDED_UI_INPUT_H__ + diff --git a/src/ui/label.cc b/src/ui/label.cc index 6f496fc..80e493e 100644 --- a/src/ui/label.cc +++ b/src/ui/label.cc @@ -10,7 +10,8 @@ using math::Vector2f; -namespace ui { +namespace ui +{ Label::Label(Widget *parent, const char *text) : Widget(parent) { @@ -23,7 +24,7 @@ Label::~Label() { } -void Label::print(size_t indent) +void Label::print(const size_t indent) const { std::string marker(""); con_print << aux::pad_left(marker, indent*2) << label() << " \"" << text() << "\"" << std::endl; @@ -37,12 +38,12 @@ void Label::set_text(const char *text) label_text.clear(); } -void Label::set_text(std::string const &text) +void Label::set_text(const std::string &text) { label_text.assign(text); } -void Label::set_alignment(unsigned int alignment) +void Label::set_alignment(const unsigned int alignment) { label_alignment = alignment; } @@ -50,7 +51,7 @@ void Label::set_alignment(unsigned int alignment) void Label::draw() { Widget::draw(); - + draw_text(); } @@ -58,7 +59,7 @@ void Label::draw_text() { if (!label_text.size()) return; - + paint::color(palette()->foreground()); paint::text(global_location(), size(), font(), text(), alignment()); } diff --git a/src/ui/label.h b/src/ui/label.h index 45171b2..b7925c7 100644 --- a/src/ui/label.h +++ b/src/ui/label.h @@ -10,39 +10,45 @@ #include <string> #include "ui/widget.h" -namespace ui { +namespace ui +{ /// a widget displaying centered text -class Label : public Widget { +class Label : public Widget +{ public: Label(Widget *parent, const char *text=0); ~Label(); - + /// set the text displayed by the label - void set_text(std::string const &text); - + void set_text(const std::string &text); + /// set the text displayed by the label void set_text(const char *text); - + /// set the text alignment - void set_alignment(unsigned int alignment); - + void set_alignment(const unsigned int alignment); + /// return the text displayed by the label - inline std::string const &text() const { return label_text; } - + inline const std::string &text() const { + return label_text; + } + /// text alignment - inline unsigned int alignment() const { return label_alignment; } - + inline unsigned int alignment() const { + return label_alignment; + } + /// print label description - virtual void print(size_t indent); - + virtual void print(const size_t indent) const; + protected: /// draw the label virtual void draw(); - + /// draw the label text virtual void draw_text(); - + private: std::string label_text; unsigned int label_alignment; diff --git a/src/ui/menu.cc b/src/ui/menu.cc index af9929c..2a1829f 100644 --- a/src/ui/menu.cc +++ b/src/ui/menu.cc @@ -10,22 +10,23 @@ #include "ui/menu.h" #include "ui/ui.h" -namespace ui { +namespace ui +{ Menu::Menu(Window *parent, const char *label) : Window(parent) { set_label(label); set_border(false); - + menu_element_width = 256.0f; menu_element_height = 48.0f; menu_element_margin = 24.0f; - + menu_background = new Bitmap(this); menu_container = new Window(this); menu_container->set_border(true); menu_container->set_background(true); - + menu_container->set_label("container"); } @@ -38,41 +39,41 @@ void Menu::load() { std::string filename("menus/"); filename.append(label()); - + filesystem::IniFile ini; - + ini.open(filename); - + if (!ini.is_open()) { con_error << "Could not open " << ini.name() << std::endl; return; } - + std::string strval; Button *button = 0; Label *label = 0; while (ini.getline()) { if (ini.got_section()) { - + //con_debug << " " << ini.name() << " [" << ini.section() << "]" << std::endl; - + if (ini.got_section("menu")) { } else if (ini.got_section("button")) { button = add_button(); - + } else if (ini.got_section("label")) { label = add_label(); - + } else if (ini.got_section()) { ini.unknown_section(); } - + } else if (ini.got_key()) { - + //con_debug << " " << ini.name() << " " << ini.key() << "=" << ini.value() << std::endl; - + if (ini.in_section("menu")) { if (ini.got_key_string("background", strval)) { set_background(strval.c_str()); @@ -88,10 +89,10 @@ void Menu::load() } else if (ini.in_section("button")) { if (ini.got_key_string("text", strval)) { button->set_text(strval); - + } else if (ini.got_key_string("command", strval)) { button->set_command(strval); - + } else if (ini.got_key_string("align", strval)) { aux::to_label(strval); if (strval.compare("left") == 0) { @@ -99,7 +100,7 @@ void Menu::load() } else if (strval.compare("center") == 0) { button->set_alignment(AlignCenter); } else if (strval.compare("right") == 0) { - button->set_alignment(AlignRight | AlignVCenter); + button->set_alignment(AlignRight | AlignVCenter); } else { ini.unknown_value(); } @@ -124,10 +125,10 @@ void Menu::load() ini.unkown_key(); } } - + } } - + con_debug << " " << ini.name() << " " << children().size() << " widgets" << std::endl; ini.close(); } @@ -153,9 +154,9 @@ Button *Menu::add_button(char const *text, char const *command) void Menu::resize() { - size().assign(parent()->size()); - menu_background->size().assign(size()); - + set_size(parent()->size()); + menu_background->set_size(size()); + float n = (float) menu_container->children().size(); menu_container->set_size(1.5f * menu_element_width, n * (menu_element_height + menu_element_margin) + menu_element_height); menu_container->set_location(menu_element_width * 0.25, (height() - menu_container->height()) / 2.0f); diff --git a/src/ui/menu.h b/src/ui/menu.h index 376e069..1b4f17e 100644 --- a/src/ui/menu.h +++ b/src/ui/menu.h @@ -12,36 +12,38 @@ #include "ui/label.h" #include "ui/window.h" -namespace ui { +namespace ui +{ /// a menu container -class Menu : public Window { +class Menu : public Window +{ public: /// create a new menu Menu(Window *parent, const char * label); ~Menu(); - + /// load a menu from ini/menus/label.ini void load(); - + void set_background(const char *texture); - + Label *add_label(char const * text=0); - + Button *add_button(char const *text=0, char const *command=0); - + protected: virtual void resize(); - + private: float menu_element_width; float menu_element_height; float menu_element_margin; - + Bitmap *menu_background; Window *menu_container; - + }; } diff --git a/src/ui/paint.cc b/src/ui/paint.cc index ce5a5c2..33ee54f 100644 --- a/src/ui/paint.cc +++ b/src/ui/paint.cc @@ -11,7 +11,8 @@ #include "render/textures.h" #include "ui/paint.h" -namespace ui { +namespace ui +{ // contains the interface between the user interface and the render library namespace paint { @@ -26,10 +27,15 @@ void color(math::Color const & color) render::gl::color(color); } +void color_code(const char *c) +{ + render::Text::setcolor(*c); +} + void border(math::Vector2f const &location, math::Vector2f const &size) { using namespace render::gl; - + begin(LineLoop); vertex(location.x +1 , location.y); vertex(location.x + size.x, location.y); @@ -41,7 +47,7 @@ void border(math::Vector2f const &location, math::Vector2f const &size) void rectangle(math::Vector2f const &location, math::Vector2f const &size) { using namespace render::gl; - + begin(Quads); vertex(location.x +1 , location.y); vertex(location.x + size.x, location.y); @@ -57,39 +63,39 @@ void bitmap(math::Vector2f const &location, math::Vector2f const &size, std::str render::Textures::bind("bitmaps/" + texture); enable(GL_TEXTURE_2D); - + begin(Quads); - + glTexCoord2f(0.0f, 0.0f); vertex(location.x +1 , location.y); - + glTexCoord2f(1.0f, 0.0f); vertex(location.x + size.x, location.y); - + glTexCoord2f(1.0f, 1.0f); vertex(location.x + size.x, location.y + size.y -1); - + glTexCoord2f(0.0f, 1.0f); vertex(location.x +1, location.y + size.y - 1); end(); - + disable(GL_TEXTURE_2D); } void text_centered(math::Vector2f const &location, math::Vector2f const &size, std::string const &text, Font const *font) { using namespace render::gl; - + render::Text::setfont(font->name().c_str(), font->width(), font->height()); enable(GL_TEXTURE_2D); math::Vector2f v(location); - + v.x += (size.x - aux::text_strip(text).size() * font->width()) /2.0f; v.y += (size.y - font->height()) / 2.0f; - + render::Text::draw(v.x, v.y, text); - + disable(GL_TEXTURE_2D); } @@ -97,45 +103,45 @@ void text(math::Vector2f const &location, Font const *font, std::stringstream & { using namespace render::gl; render::Text::setfont(font->name().c_str(), font->width(), font->height()); - + // enable OpenGL textures enable(GL_TEXTURE_2D); - + render::Text::draw(location.x, location.y, textstream); - + // disable texturing disable(GL_TEXTURE_2D); } void text(math::Vector2f const &location, math::Vector2f const &size, - Font const *font, - std::string const &text, - unsigned int align) + Font const *font, + std::string const &text, + unsigned int align) { unsigned int align_horizontal = (align & 0x000F); if (!align_horizontal) align_horizontal = AlignLeft; - + unsigned int align_vertical = (align & 0x00F0); if (!align_vertical) align_vertical = AlignTop; - + // apply text font using namespace render::gl; render::Text::setfont(font->name().c_str(), font->width(), font->height()); - + // enable OpenGL textures enable(GL_TEXTURE_2D); - + // determine the width and height of the text // FIXME support multiline text float text_height = 1.0f * font->height(); float text_width = (float) aux::text_strip(text).size() * font->width(); - + // calculate drawing position math::Vector2f v(location); - - switch(align_horizontal) { + + switch (align_horizontal) { case AlignLeft: v.x += font->width(); break; @@ -147,7 +153,7 @@ void text(math::Vector2f const &location, math::Vector2f const &size, break; } - switch(align_vertical) { + switch (align_vertical) { case AlignTop: v.y += font->height()*0.5f; break; @@ -158,12 +164,12 @@ void text(math::Vector2f const &location, math::Vector2f const &size, v.y += size.y - text_height - font->height()*0.5f; break; } - + render::Text::draw(v.x, v.y, text); - + // disable texturing disable(GL_TEXTURE_2D); - + } } diff --git a/src/ui/paint.h b/src/ui/paint.h index 3128481..367b001 100644 --- a/src/ui/paint.h +++ b/src/ui/paint.h @@ -9,7 +9,8 @@ #include "ui/widget.h" -namespace ui { +namespace ui +{ /// low-level widget paint functions namespace paint { @@ -20,6 +21,9 @@ void color(float r=0.0f, float g=0.0f, float b=0.0f, float a=1.0f); /// set paint color void color(math::Color const & color); +/// set paint color +void color_code(const char *c); + /// draw a border void border(math::Vector2f const &location, math::Vector2f const &size); @@ -30,9 +34,9 @@ void rectangle(math::Vector2f const &location, math::Vector2f const &size); void bitmap(math::Vector2f const &location, math::Vector2f const &size, std::string const &texture); /// draw text -void text(math::Vector2f const &location, math::Vector2f const &size, Font const *font, std::string const &text, - unsigned int align = AlignCenter); - +void text(math::Vector2f const &location, math::Vector2f const &size, Font const *font, + std::string const &text, unsigned int align = AlignCenter); + /// draw textstream void text(math::Vector2f const &location, Font const *font, std::stringstream & textstream); diff --git a/src/ui/palette.cc b/src/ui/palette.cc index cb6ee91..20d1e93 100644 --- a/src/ui/palette.cc +++ b/src/ui/palette.cc @@ -7,14 +7,17 @@ #include "ui/palette.h" #include "sys/sys.h" -namespace ui { +namespace ui +{ Palette::Palette() { palette_foreground.assign(0.8f, 1.0f); palette_highlight.assign(1.0f, 1.0f); palette_background.assign(0.5f, 0.5f); - palette_border.assign(0.0f, 8.0f, 0.0f); + palette_border.assign(0.0f, 0.8f, 0.0f); + palette_pointer.assign(0.0f, 0.5f, 0.0f); + palette_active.assign(0.0f, 1.0f, 0.0f); } Palette::~Palette() @@ -41,6 +44,15 @@ void Palette::set_border(math::Color const &color) palette_border.assign(color); } +void Palette::set_pointer(math::Color const &color) +{ + palette_pointer.assign(color); +} + +void Palette::set_active(math::Color const &color) +{ + palette_active.assign(color); } +} diff --git a/src/ui/palette.h b/src/ui/palette.h index edd738f..9d27f95 100644 --- a/src/ui/palette.h +++ b/src/ui/palette.h @@ -9,7 +9,8 @@ #include "math/color.h" -namespace ui { +namespace ui +{ class Palette { @@ -17,28 +18,50 @@ class Palette public: Palette(); ~Palette(); - + void set_foreground(math::Color const &color); - + void set_highlight(math::Color const &color); - + void set_background(math::Color const &color); - + void set_border(math::Color const &color); - - inline math::Color const &foreground() const { return palette_foreground; } - - inline math::Color const &highlight() const { return palette_highlight; } - - inline math::Color const &background() const { return palette_background; } - - inline math::Color const &border() const { return palette_border; } - + + void set_pointer(math::Color const &color); + + void set_active(math::Color const &color); + + inline math::Color const &foreground() const { + return palette_foreground; + } + + inline math::Color const &highlight() const { + return palette_highlight; + } + + inline math::Color const &background() const { + return palette_background; + } + + inline math::Color const &border() const { + return palette_border; + } + + inline math::Color const &pointer() const { + return palette_pointer; + } + + inline math::Color const &active() const { + return palette_active; + } + private: math::Color palette_foreground; math::Color palette_highlight; math::Color palette_background; + math::Color palette_pointer; + math::Color palette_active; math::Color palette_border; }; diff --git a/src/ui/ui.cc b/src/ui/ui.cc index 8242381..8d60543 100644 --- a/src/ui/ui.cc +++ b/src/ui/ui.cc @@ -18,7 +18,10 @@ #include "ui/widget.h" #include "ui/window.h" -namespace ui { +namespace ui +{ + +/* -- static functions --------------------------------------------- */ UI *global_ui = 0; @@ -59,7 +62,7 @@ void func_ui(std::string const &args) con_warn << "User Interface not available!" << std::endl; return; } - + if (!args.size()) { help(); return; @@ -68,7 +71,7 @@ void func_ui(std::string const &args) std::string command; argstr >> command; aux::to_label(command); - + if (command.compare("help") == 0) { help(); } else if (command.compare("list") == 0) { @@ -103,28 +106,28 @@ void func_menu(std::string const &args) con_warn << "User Interface not available!" << std::endl; return; } - + if (!args.size()) { return; } std::stringstream argstr(args); std::string command; argstr >> command; - + aux::to_label(command); - + if (command.compare("hide") == 0) { root()->hide_window(); - + } else if (command.compare("close") == 0) { root()->hide_window(); - + } else if (command.compare("back") == 0) { root()->previous_window(); - + } else if (command.compare("previous") == 0) { root()->previous_window(); - + } else if (command.compare("list") == 0) { root()->list_menus(); } else { @@ -132,6 +135,8 @@ void func_menu(std::string const &args) } } +/* -- class UI ----------------------------------------------------- */ + UI *root() { return global_ui; @@ -140,28 +145,28 @@ UI *root() void init() { con_print << "^BInitializing user interface..." << std::endl; - + if (!global_ui) { global_ui = new UI(); } else { con_warn << "User interface already initialized!" << std::endl; return; } - + global_ui->load(); - + core::Func *func = core::Func::add("list_ui", func_list_ui); func->set_info("list user interface widgets"); - + func = core::Func::add("list_menu", func_list_menu); func->set_info("list available menus"); - + func = core::Func::add("ui", func_ui); func->set_info("[command] user interface functions"); - + func = core::Func::add("ui_restart", func_ui_restart); func->set_info("[command] [options] reload user interface files"); - + func = core::Func::add("menu", func_menu); func->set_info("[command] menu functions"); } @@ -169,42 +174,51 @@ void init() void shutdown() { con_print << "^BShutting down user interface..." << std::endl; - + core::Func::remove("list_ui"); core::Func::remove("list_menu"); core::Func::remove("menu"); core::Func::remove("ui"); - + if (global_ui) { delete global_ui; global_ui = 0; } } +/* -- class UI ----------------------------------------------------- */ + UI::UI() : Window(0) { set_label("root"); set_size(1024, 768); set_border(false); - + // default palette ui_palette = new Palette(); set_palette(ui_palette); - + // default fonts ui_font_small = new Font("gui", 12, 18); ui_font_large = new Font("gui", 14, 24); set_font(ui_font_small); + + ui_mouse_focus = this; + ui_input_focus = this; + set_focus(); } UI::~UI() { delete ui_palette; - + delete ui_font_small; delete ui_font_large; } +/* + remove all existing child windows and load ini/ui.ini +*/ void UI::load() { Windows::iterator it; @@ -213,47 +227,47 @@ void UI::load() remove_child(window); } window_children.clear(); - ui_focus = this; + ui_mouse_focus = this; ui_active_window = 0; - + std::string filename("ui"); - + filesystem::IniFile ini; - + ini.open(filename); - + if (!ini.is_open()) { con_error << "Could not open " << ini.name() << std::endl; return; } - + std::string strval; math::Color color; Menu *menu = 0; while (ini.getline()) { - + if (ini.got_section()) { - + //con_debug << " " << ini.name() << " [" << ini.section() << "]" << std::endl; - + if (ini.got_section("ui")) { continue; - + } else if (ini.got_section("colors")) { continue; - - } else { + + } else { ini.unknown_section(); continue; } - + } else if (ini.got_key()) { - + //con_debug << " " << ini.name() << " " << ini.key() << "=" << ini.value() << std::endl; - + if (ini.in_section("ui")) { - + if (ini.got_key_string("menu", strval)) { aux::to_label(strval); menu = new Menu(this, strval.c_str()); @@ -262,9 +276,9 @@ void UI::load() } else { ini.unkown_key(); } - + } else if (ini.in_section("colors")) { - + if (ini.got_key_color("foreground", color)) { ui_palette->set_foreground(color); continue; @@ -277,6 +291,10 @@ void UI::load() } else if (ini.got_key_color("border", color)) { ui_palette->set_border(color); continue; + } else if (ini.got_key_color("pointer", color)) { + ui_palette->set_pointer(color); + } else if (ini.got_key_color("active", color)) { + ui_palette->set_active(color); } else { ini.unkown_key(); } @@ -286,7 +304,7 @@ void UI::load() con_debug << " " << ini.name() << " " << window_children.size() << " menus" << std::endl; ini.close(); - + // fallback main menu if (!find_window("main")) { con_warn << "menu 'main' not found, using default" << std::endl; @@ -295,7 +313,7 @@ void UI::load() menu->add_button("Connect", "connect"); menu->add_button("Quit", "quit"); } - + // fallback game menu if (!find_window("game")) { con_warn << "menu 'game' not found, using default" << std::endl; @@ -306,17 +324,16 @@ void UI::load() } } -void UI::list() +void UI::list() const { size_t n = Widget::list(0); con_print << n << " user interface widgets" << std::endl; } -void UI::list_menus() +void UI::list_menus() const { - Windows::iterator it; - for (it = window_children.begin(); it != window_children.end(); it++) { - Window *window = (*it); + for (Windows::const_iterator it = window_children.begin(); it != window_children.end(); it++) { + const Window *window = (*it); con_print << " " << window->label() << std::endl; } con_print << window_children.size() << " menus" << std::endl; @@ -332,15 +349,16 @@ void UI::remove_window(Window *window) { if (ui_active_window == window) { ui_active_window = 0; - ui_focus = this; + ui_mouse_focus = this; + ui_input_focus = this; } - + Window::remove_window(window); } -Window *UI::find_window(const char *label) +Window *UI::find_window(const char *label) const { - for (Windows::iterator it = window_children.begin(); it != window_children.end(); it++) { + for (Windows::const_iterator it = window_children.begin(); it != window_children.end(); it++) { if ((*it)->label().compare(label) == 0) { return (*it); } @@ -351,19 +369,21 @@ Window *UI::find_window(const char *label) void UI::show_window(const char *label) { Window *window = find_window(label); - + if (window) { - if (ui_active_window) { - ui_active_window->hide(); - window->set_previous(ui_active_window); - } else { - window->clear_previous(); - } - ui_active_window = window; - ui_active_window->event_resize(); - ui_active_window->raise(); - ui_active_window->show(); - ui_focus = window; + if (ui_active_window) { + ui_active_window->hide(); + window->set_previous(ui_active_window); + } else { + window->clear_previous(); + } + ui_active_window = window; + ui_active_window->event_resize(); + ui_active_window->raise(); + ui_active_window->show(); + ui_active_window->set_focus(); + ui_mouse_focus = this; + ui_input_focus = this; } else { con_warn << "Unknown window '" << label << "'" << std::endl; } @@ -390,28 +410,57 @@ void UI::previous_window() void UI::frame() { - ui_focus = event_focus(mouse_cursor); + if (ui_active_window && !ui_active_window->visible()) { + ui_active_window = 0; + } + event_draw(); } -void UI::input_mouse(float x, float y) +/* -- global event handlers ---------------------------------------- */ +/* + These functions receive input events from the client input + subsystem and distributes them to the widget hierarchy +*/ +void UI::input_mouse(const float x, const float y) { mouse_cursor.assign(x, y); + Widget *f = find_mouse_focus(mouse_cursor); + if (f) { + f->event_mouse(mouse_cursor); + } + ui_mouse_focus = f; } -void UI::input_key(bool pressed, unsigned int key, unsigned int modifier) +void UI::input_key(const bool pressed, const int key, const unsigned int modifier) { - ui_focus->event_key(pressed, key, modifier); + if (key < 512) { + // keyboard keys + Widget *f = find_input_focus(); + if (f) { + f->event_key(pressed, key, modifier); + } + ui_input_focus = f; + } else { + // mosue buttons + if (ui_mouse_focus) + ui_mouse_focus->event_key(pressed, key, modifier); + } } -bool UI::keypress(unsigned int key, unsigned int modifier) +/* -- event handlers ----------------------------------------------- */ +/* + These functions handle events for this widget only. They are + the fallback input handlers +*/ +bool UI::on_keypress(const int key, const unsigned int modifier) { - return true; + return true; } -bool UI::keyrelease(unsigned int key, unsigned int modifier) +bool UI::on_keyrelease(const int key, const unsigned int modifier) { - return true; + return true; } } diff --git a/src/ui/ui.h b/src/ui/ui.h index a555e97..eb2d4e0 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -12,73 +12,96 @@ #include "ui/widget.h" #include "ui/window.h" -namespace ui { +namespace ui +{ -class UI : public Window { +class UI : public Window +{ public: /// constructor UI(); - + /// destructor ~UI(); - + /// list widgets - void list(); - + void list() const; + /// list meus - void list_menus(); - + void list_menus() const; + /// reload menu files void load(); - + /// make a window the active window void show_window(const char *label); - + /// hide the active window void hide_window(); - + /// show previous window void previous_window(); - + /// return the active window - Window *active() { return ui_active_window; } - - /// mouse cursor input - void input_mouse(float x, float y); - - /// keyboard input - void input_key(bool pressed, unsigned int key, unsigned int modifier); - + Window *active() { + return ui_active_window; + } + + /// return the widget with global mouse focus + inline Widget *mouse_focus() const { + return ui_mouse_focus; + } + + /// return the widget with global input focus + inline Widget *input_focus() const { + return ui_input_focus; + } + + /// receive global mouse movement + void input_mouse(const float x, const float y); + + /// receive global key input + void input_key(const bool pressed, const int key, const unsigned int modifier); + /// run a user interface frame void frame(); - - /// return the widget which has the focus - inline Widget *focus() { return ui_focus; } - - /* -- Fonts ------------------------------------------------ */ + + /* -- fonts ------------------------------------------------ */ + /// default small font - inline Font *font_small() { return ui_font_small; } - + inline const Font *font_small() const { + return ui_font_small; + } + /// default medium font - inline Font *font_large() { return ui_font_large; } - + inline const Font *font_large() const { + return ui_font_large; + } + protected: - Window *find_window(const char *label); - + Window *find_window(const char *label) const; + virtual void add_window(Window *window); virtual void remove_window(Window *window); - - /// handle keyboard input - virtual bool keypress(unsigned int key, unsigned int modifier); - virtual bool keyrelease(unsigned int key, unsigned int modifier); - + + /* -- event handlers --------------------------------------- */ + + /// handle keypress events + virtual bool on_keypress(const int key, const unsigned int modifier); + + /// handle key release events + virtual bool on_keyrelease(const int key, const unsigned int modifier); + private: Palette *ui_palette; Font *ui_font_small; Font *ui_font_large; - + Window *ui_active_window; - Widget *ui_focus; + Widget *ui_mouse_focus; + Widget *ui_input_focus; + + /// TODO move to separate object to handle mouse cursor drawing math::Vector2f mouse_cursor; }; diff --git a/src/ui/widget.cc b/src/ui/widget.cc index b2c436d..e17e5ab 100644 --- a/src/ui/widget.cc +++ b/src/ui/widget.cc @@ -10,22 +10,25 @@ #include "ui/ui.h" #include "ui/widget.h" -namespace ui { +namespace ui +{ -Widget::Widget(Widget *parent) { +Widget::Widget(Widget *parent) +{ + widget_focus = false; widget_visible = true; widget_border = true; widget_background = false; widget_palette = 0; widget_font = 0; widget_label.assign("widget"); - + if (!parent) { widget_parent = root(); } else { widget_parent = parent; } - + if (widget_parent) widget_parent->add_child(this); } @@ -33,39 +36,47 @@ Widget::Widget(Widget *parent) { Widget::~Widget() { for (Children::iterator it = widget_children.begin(); it != widget_children.end(); it++) { - delete (*it); + delete(*it); (*it) = 0; } widget_children.clear(); } -size_t Widget::list(size_t indent) +size_t Widget::list(const size_t indent) const { print(indent); size_t n = 1; - for (Children::iterator it = widget_children.begin(); it != widget_children.end(); it++) { + for (Children::const_iterator it = widget_children.begin(); it != widget_children.end(); it++) { n += (*it)->list(indent+1); } return n; } -void Widget::print(size_t indent) +void Widget::print(const size_t indent) const { - std::string marker(""); - con_print << aux::pad_left(marker, indent*2) << label() << std::endl; + if (indent) { + std::string marker; + if (widget_focus) + marker.assign("^B* ^N"); + else + marker.assign(" "); + con_print << aux::pad_left(marker, indent*2) << label() << std::endl; + } } -Palette const *Widget::palette() const { +const Palette *Widget::palette() const +{ if (widget_palette) { - return widget_palette; + return widget_palette; } else { return parent()->palette(); } } -Font const *Widget::font() const { +const Font *Widget::font() const +{ if (widget_font) { - return widget_font; + return widget_font; } else { return parent()->font(); } @@ -75,7 +86,7 @@ void Widget::lower() { if (!parent()) return; - + Children::iterator it = parent()->find_child(this); if (it != parent()->children().end()) { parent()->children().erase(it); @@ -87,7 +98,7 @@ void Widget::raise() { if (!parent()) return; - + Children::iterator it = parent()->find_child(this); if (it != parent()->children().end()) { parent()->children().erase(it); @@ -95,6 +106,20 @@ void Widget::raise() } } +void Widget::set_focus() +{ + if (!parent()) { + widget_focus = true; + return; + } + + for (Children::iterator it = parent()->children().begin(); it != parent()->children().end(); it++) { + (*it)->widget_focus = false; + } + + widget_focus = true; +} + void Widget::show() { widget_visible = true; @@ -108,7 +133,10 @@ void Widget::hide() void Widget::set_visible(bool visible) { - widget_visible = visible; + if (visible) + show(); + else + hide(); } void Widget::set_border(bool border) @@ -133,20 +161,26 @@ void Widget::set_label(char const *label) aux::to_label(widget_label); } -void Widget::set_palette(Palette *palette) +void Widget::set_palette(const Palette *palette) { widget_palette = palette; } -void Widget::set_font(Font *font) +void Widget::set_font(const Font *font) { widget_font = font; } -void Widget::set_location(float const x, float const y) { +void Widget::set_location(float const x, float const y) +{ widget_location.assign(x, y); } +void Widget::set_location(const math::Vector2f &location) +{ + widget_location.assign(location); +} + void Widget::set_size(float const w, float const h) { widget_size.assign(w, h); @@ -173,7 +207,7 @@ Widget::Children::iterator Widget::find_child(Widget *child) if ((*it) == child) return it; } - + return it; } @@ -184,118 +218,167 @@ void Widget::add_child(Widget *child) widget_children.push_back(child); } } - + void Widget::remove_child(Widget *child) { Children::iterator it = find_child(child); if (it != widget_children.end()) { - delete (*it); + delete(*it); widget_children.erase(it); } } -void Widget::event_resize() +Widget *Widget::find_input_focus() { - resize(); - for (Children::iterator it = widget_children.begin(); it != widget_children.end(); it++) { - (*it)->event_resize(); + if (!visible() || !widget_focus) + return 0; + + for (Children::const_reverse_iterator rit = widget_children.rbegin(); rit != widget_children.rend(); ++rit) { + Widget *w = (*rit); + if (w->visible() && w->widget_focus) { + Widget *f = w->find_input_focus(); + if (f) + return f; + } } + + // no child with input focus + return this; } -void Widget::resize() +Widget *Widget::find_mouse_focus(const math::Vector2f & pos) { + // this widget is not visible + if (!visible() || !size().contains(pos)) + return 0; + + // reverse-iterate children + for (Children::const_reverse_iterator rit = widget_children.rbegin(); rit != widget_children.rend(); ++rit) { + Widget *w = (*rit); + if (w->visible()) { + Widget *f = w->find_mouse_focus(pos - w->location()); + if (f) + return f; + } + + } + + // no child with mouse focus + return this; } -void Widget::event_draw() +bool Widget::has_mouse_focus() const { - if (!widget_visible) - return; - - draw(); - for (Children::iterator it = widget_children.begin(); it != widget_children.end(); it++) { - if ((*it)->visible()) - (*it)->event_draw(); - } + return (root()->mouse_focus() == this); } -void Widget::draw() +bool Widget::has_input_focus() const { - draw_background(); - draw_border(); + return (root()->input_focus() == this); } -void Widget::draw_background() +/* -- event distributors ------------------------------------------- */ + +bool Widget::event_key(const bool pressed, const int key, const unsigned int modifier) { - if (!widget_background) - return; + bool handled = false; + + if (pressed) { + handled = on_keypress(key, modifier); + } else { + handled = on_keyrelease(key, modifier); + } + + if (!handled && parent()) + handled = parent()->event_key(pressed, key, modifier); + + return handled; +} - paint::color(palette()->background()); - paint::rectangle(global_location(), size()); +bool Widget::event_mouse(const math::Vector2f &cursor) +{ + math::Vector2f local_cursor = to_local_coords(cursor); + bool handled = false; + + if (root()->mouse_focus() != this) { + on_mouseover(local_cursor); + } + + on_mousemove(local_cursor); + return handled; } -void Widget::draw_border() +void Widget::event_draw() { - if (!widget_border) + if (!visible()) return; - - paint::color(palette()->border()); - paint::border(global_location(), size()); + + draw(); + + for (Children::iterator it = widget_children.begin(); it != widget_children.end(); it++) { + if ((*it)->visible()) + (*it)->event_draw(); + } } -Widget *Widget::event_focus(math::Vector2f const & pos) +void Widget::event_resize() { - // this widget is not visible - if (!visible()) - return 0; + resize(); + for (Children::iterator it = widget_children.begin(); it != widget_children.end(); it++) { + (*it)->event_resize(); + } +} - // pos is outside this - if ((pos.x < 0) || (pos.y < 0) || (pos.x > size().x) || (pos.y > size().y)) - return 0; +/* -- event handlers ----------------------------------------------- */ - // reverse-iterate children - for (Children::reverse_iterator rit = widget_children.rbegin(); rit != widget_children.rend(); ++rit) { - Widget *w = (*rit); - if (w->visible()) { - Widget *f = w->event_focus(pos - w->location()); - if (f) - return f; - } +void Widget::on_mouseover(const math::Vector2f &cursor) +{ + return; +} - } - - // no child has focus - return this; +void Widget::on_mousemove(const math::Vector2f &cursor) +{ + return; } -bool Widget::has_focus() const +bool Widget::on_keypress(const int key, const unsigned int modifier) { - return (root()->focus() == this); + return false; } -bool Widget::event_key(bool pressed, unsigned int key, unsigned int modifier) +bool Widget::on_keyrelease(const int key, const unsigned int modifier) { - bool handled; + return false; +} - if (pressed) { - handled = keypress(key, modifier); - } else { - handled = keyrelease(key, modifier); - } +/* -- draw functions ----------------------------------------------- */ - if (!handled && parent()) - handled = parent()->event_key(pressed, key, modifier); +void Widget::resize() +{ +} - return handled; +void Widget::draw() +{ + draw_background(); + draw_border(); } -bool Widget::keypress(unsigned int key, unsigned int modifier) +void Widget::draw_background() { - return false; + if (!widget_background) + return; + + paint::color(palette()->background()); + paint::rectangle(global_location(), size()); } -bool Widget::keyrelease(unsigned int key, unsigned int modifier) +void Widget::draw_border() { - return false; + if (!widget_border) + return; + + paint::color(palette()->border()); + paint::border(global_location(), size()); } } diff --git a/src/ui/widget.h b/src/ui/widget.h index 2078134..e069220 100644 --- a/src/ui/widget.h +++ b/src/ui/widget.h @@ -20,199 +20,283 @@ #include "ui/definitions.h" #include "sys/sys.h" -namespace ui { +namespace ui +{ -class Widget { +class Widget +{ public: /// type definition for child widgets typedef std::list<Widget *> Children; - + /// create a new widget Widget(Widget *parent=0); - + /// destroy a widget virtual ~Widget(); - + + /// parent widget this widget belongs to + inline Widget *parent() const { + return widget_parent; + } + /* -- inspectors -------------------------------------------- */ - inline math::Vector2f &location() { return widget_location; } - - inline math::Vector2f &size() { return widget_size; } - - inline float const left() const { return widget_location.x; } - - inline float const top() const { return widget_location.y; } - inline float const width() const { return widget_size.x; } - - inline float const height() const { return widget_size.y; } - - - inline std::string const &label() const { return widget_label; } - - inline bool border() const { return widget_border; } - - inline bool background() const { return widget_background; } - - inline Widget *parent() const { return widget_parent; } - - inline bool visible() const { return widget_visible; } - - Palette const *palette() const; - - Font const *font() const; - - bool has_focus() const; - - + /// pixel coordinates of the top-left corner of this widget within its parent + inline const math::Vector2f &location() const { + return widget_location; + } + + /// size of this widget in pixels + inline const math::Vector2f &size() const { + return widget_size; + } + + /// left coordinate of location() + /** + * @see location + */ + inline float left() const { + return widget_location.x; + } + + /// top coordinate of location() + /** + * @see location + */ + inline float top() const { + return widget_location.y; + } + + /// width of the widget in pixels + /** + * @see size() + */ + inline float width() const { + return widget_size.x; + } + + /// height of the widget in pixels + /** + * @see size() + */ + inline float height() const { + return widget_size.y; + } + + /// widget label + inline const std::string &label() const { + return widget_label; + } + + /// true if this widget will draw a background + inline bool background() const { + return widget_background; + } + + /// true if this widget will draw a border + inline bool border() const { + return widget_border; + } + + /// true if this widget is visible + inline bool visible() const { + return widget_visible; + } + + /// true if this widget is not visible + inline bool hidden() const { + return !widget_visible; + } + + /// the palette used to draw this widget + const Palette *palette() const; + + /// the font used to draw this widget + const Font *font() const; + + /// return true if the widget has input focus + bool has_input_focus() const; + + /// returns true if the widget has mouse focus + bool has_mouse_focus() const; + /* -- mutators --------------------------------------------- */ - + /// raise the widget to the top of the widget stack void raise(); - + /// lower the widget to the bottom of the widget stack void lower(); - + /// show the widget - void show(); - + virtual void show(); + /// hide the widget - void hide(); - + virtual void hide(); + /// set visibility void set_visible(bool visible = true); - - /// set location of the top-left corner + + /// set input focus + void set_focus(); + + /// set location of the top-left corner, relative to the parent void set_location(float const x, float const y); - + + /// set location of the top-left corner, relative to the parent + void set_location(const math::Vector2f &location); + /// set the widgets width and height void set_size(float const w, float const h); - + /// set the widgets width and height void set_size(math::Vector2f const &size); - + /// set the widgets width void set_width(float const w); - + /// set the widgets height void set_height(float const h); - + /// set the widgets palette - void set_palette(Palette *palette); - + void set_palette(const Palette *palette); + /// set the widgets font - void set_font(Font *font); - + void set_font(const Font *font); + /// set the widgets label void set_label(std::string const &label); /// set the widgets label - void set_label(char const *label); - - void set_border(bool border); - - void set_background(bool background); - - /// resize event + void set_label(const char *label); + + /// enable or disable widget border + void set_border(bool border = true); + + ///enable or disable widget background + void set_background(bool background = true); + + /// child widgets + inline Children &children() { + return widget_children; + } + + + /* -- event distributors ----------------------------------- */ + + /// distribute resize event virtual void event_resize(); - - /// draw event + + /// distribute draw event virtual void event_draw(); - - /// keyboard event - virtual bool event_key(bool pressed, unsigned int key, unsigned int modifier); - - /// find the child widget with focus - /** @param pos local position within the widget - */ - Widget *event_focus(math::Vector2f const & pos); - - /// child widgets - inline Children &children() { return widget_children; } - + + /// distribute keyboard events + virtual bool event_key(const bool pressed, const int key, const unsigned int modifier); + + /// distribute mouse movement events + virtual bool event_mouse(const math::Vector2f &cursor); + protected: - /// handle keyboard events - /** returns true if the event was handled by this widget - */ - virtual bool keypress(unsigned int key, unsigned int modifier); - - /// handle keyboard events - /** returns true if the event was handled by this widget - */ - virtual bool keyrelease(unsigned int key, unsigned int modifier); - - /// draw the widget - virtual void draw(); - - /// resize the widget - virtual void resize(); - - /// draw the widget background - virtual void draw_background(); - - /// draw the widget border - virtual void draw_border(); - + /// find the widget that has input focus + virtual Widget *find_input_focus(); + + /// find widget that has mosue focus + /** @param cursor mouse cursor position relative to this widget's location + */ + Widget *find_mouse_focus(const math::Vector2f & cursor); + /// list widget content - size_t list(size_t indent); - + size_t list(const size_t indent) const; + /// print widget description - virtual void print(size_t indent); - + virtual void print(const size_t indent) const; + + /* -- coordinate mapping ----------------------------------- */ + /// map local coordinates to global coordinates - inline math::Vector2f to_global_coords(math::Vector2f const &local) - { + inline math::Vector2f to_global_coords(const math::Vector2f &local) { math::Vector2f v(local); Widget *parent = widget_parent; do { v -= parent->location(); - parent = parent->widget_parent; - } while(parent); + parent = parent->parent(); + } while (parent); return v; } - + /// map global coordinates to local coordinates - inline math::Vector2f to_local_coords(math::Vector2f const &global) { + inline math::Vector2f to_local_coords(const math::Vector2f &global) { math::Vector2f v(global); Widget *parent = this; while (parent) { v += parent->location(); - parent = parent->widget_parent; + parent = parent->parent(); } return v; } - + /// map local widget location to global location - inline math::Vector2f global_location() const { + inline math::Vector2f global_location() { math::Vector2f v(widget_location); Widget *parent = widget_parent; while (parent) { v += parent->location(); - parent = parent->widget_parent; + parent = parent->parent(); } return v; } - - /// remove a child widget + + /* -- event handlers --------------------------------------- */ + + /// called when the mouse receives mouse movement + virtual void on_mousemove(const math::Vector2f &cursor); + + /// called when the mouse enters the widget + virtual void on_mouseover(const math::Vector2f &cursor); + + /// called when the widget receives a key press + virtual bool on_keypress(const int key, const unsigned int modifier); + + /// called when the widget receives a key release + virtual bool on_keyrelease(const int key, const unsigned int modifier); + + /* -- draw functions --------------------------------------- */ + + /// resize event + virtual void resize(); + + /// draw the widget + virtual void draw(); + + /// draw the widget background + virtual void draw_background(); + + /// draw the widget border + virtual void draw_border(); + + void add_child(Widget *child); void remove_child(Widget *child); - + private: - bool widget_visible; - bool widget_background; - bool widget_border; - math::Vector2f widget_location; - math::Vector2f widget_size; - std::string widget_label; + bool widget_visible; + bool widget_background; + bool widget_border; + bool widget_focus; + + math::Vector2f widget_location; + math::Vector2f widget_size; + std::string widget_label; Children widget_children; - - Palette *widget_palette; - Font *widget_font; + + const Palette *widget_palette; + const Font *widget_font; Widget *widget_parent; Children::iterator find_child(Widget *child); - - void add_child(Widget *child); + }; } diff --git a/src/ui/window.cc b/src/ui/window.cc index cc9f3b5..4a60056 100644 --- a/src/ui/window.cc +++ b/src/ui/window.cc @@ -7,7 +7,8 @@ #include "ui/paint.h" #include "ui/window.h" -namespace ui { +namespace ui +{ Window::Window(Window *parent) : Widget(static_cast<Widget *>(parent)) { @@ -38,7 +39,7 @@ void Window::draw_border() { if (!border()) return; - + paint::color(palette()->foreground()); paint::border(global_location(), size()); } @@ -50,7 +51,7 @@ Window::Windows::iterator Window::find_window(Window *window) if ((*it) == window) return it; } - + return it; } @@ -61,7 +62,7 @@ void Window::add_window(Window *window) window_children.push_back(window); } } - + void Window::remove_window(Window *window) { Windows::iterator it = find_window(window); diff --git a/src/ui/window.h b/src/ui/window.h index a134f04..919559f 100644 --- a/src/ui/window.h +++ b/src/ui/window.h @@ -9,32 +9,36 @@ #include "ui/widget.h" -namespace ui { +namespace ui +{ -class Window : public Widget { +class Window : public Widget +{ public: Window(Window *parent=0); ~Window(); - + virtual void draw_border(); - + /// set the label of the previous window void set_previous(Window *previous); /// clear the label of the previous window void clear_previous(); - - inline std::string const &previous() const { return window_previous; } - + + inline const std::string &previous() const { + return window_previous; + } + protected: typedef std::list<Window *> Windows; Windows window_children; - + Windows::iterator find_window(Window *window); - + virtual void add_window(Window *window); virtual void remove_window(Window *window); - + /// label of the previous window that got activated /** This label is used to implement the 'menu previous' * command |