Project::OSiRiON - Git repositories
Project::OSiRiON
News . About . Screenshots . Downloads . Forum . Wiki . Tracker . Git
summaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/Makefile.am2
-rw-r--r--src/ui/font.h6
-rw-r--r--src/ui/iconbutton.cc7
-rw-r--r--src/ui/iconbutton.h4
-rw-r--r--src/ui/label.h3
-rw-r--r--src/ui/toolbar.h2
-rw-r--r--src/ui/tooltip.cc90
-rw-r--r--src/ui/tooltip.h80
-rw-r--r--src/ui/ui.cc69
-rw-r--r--src/ui/ui.h17
-rw-r--r--src/ui/widget.cc40
-rw-r--r--src/ui/widget.h100
12 files changed, 344 insertions, 76 deletions
diff --git a/src/ui/Makefile.am b/src/ui/Makefile.am
index 1485565..875ffcd 100644
--- a/src/ui/Makefile.am
+++ b/src/ui/Makefile.am
@@ -29,6 +29,7 @@ noinst_HEADERS = \
scrollpane.h \
slider.h \
toolbar.h \
+ tooltip.h \
ui.h \
widget.h \
window.h
@@ -53,6 +54,7 @@ libui_la_SOURCES = \
scrollpane.cc \
slider.cc \
toolbar.cc \
+ tooltip.cc \
ui.cc \
widget.cc \
window.cc
diff --git a/src/ui/font.h b/src/ui/font.h
index b91120e..be08cfd 100644
--- a/src/ui/font.h
+++ b/src/ui/font.h
@@ -27,10 +27,16 @@ public:
return font_size;
}
+ /**
+ * @brief width of a single character
+ * */
inline float width() const {
return font_size.width();
}
+ /**
+ * @height width of a single character
+ * */
inline float height() const {
return font_size.height();
}
diff --git a/src/ui/iconbutton.cc b/src/ui/iconbutton.cc
index 18bfb5a..c23ed66 100644
--- a/src/ui/iconbutton.cc
+++ b/src/ui/iconbutton.cc
@@ -18,14 +18,15 @@
namespace ui
{
-IconButton::IconButton(Widget *parent, const char *icon, const char *command) : Widget(parent)
+IconButton::IconButton(Widget *parent, const char *icon, const char *tooltip, const char *command) : Widget(parent)
{
set_label("iconbutton");
set_background(false);
set_border(false);
- set_command(command);
- set_icon(icon);
set_highlight(false);
+ set_icon(icon);
+ set_tooltip(tooltip);
+ set_command(command);
}
IconButton::~IconButton()
diff --git a/src/ui/iconbutton.h b/src/ui/iconbutton.h
index 92e73ee..0382e1a 100644
--- a/src/ui/iconbutton.h
+++ b/src/ui/iconbutton.h
@@ -15,8 +15,8 @@ namespace ui
class IconButton : public Widget
{
public:
- IconButton(Widget *parent, const char *icon = 0, const char *command = 0);
- ~IconButton();
+ IconButton(Widget *parent, const char *icon = 0, const char *tooltip = 0, const char *command = 0);
+ virtual ~IconButton();
/// the command this button executes
inline const std::string & command() const {
diff --git a/src/ui/label.h b/src/ui/label.h
index f187520..f187744 100644
--- a/src/ui/label.h
+++ b/src/ui/label.h
@@ -12,7 +12,6 @@
namespace ui
{
-
/**
* @brief a widget displaying a single line of text
*/
@@ -20,7 +19,7 @@ class Label : public Widget
{
public:
Label(Widget *parent, const char *text = 0);
- ~Label();
+ virtual ~Label();
/// set the text displayed by the label
void set_text(const std::string &text);
diff --git a/src/ui/toolbar.h b/src/ui/toolbar.h
index baff21b..ccb3d30 100644
--- a/src/ui/toolbar.h
+++ b/src/ui/toolbar.h
@@ -27,7 +27,7 @@ public:
protected:
/// re-arrange child widgets
- void resize();
+ virtual void resize();
};
}
diff --git a/src/ui/tooltip.cc b/src/ui/tooltip.cc
new file mode 100644
index 0000000..1777d33
--- /dev/null
+++ b/src/ui/tooltip.cc
@@ -0,0 +1,90 @@
+/*
+ ui/tooltip.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/tooltip.h"
+#include "ui/ui.h"
+#include "ui/paint.h"
+
+#include <cassert>
+
+namespace ui
+{
+
+Tooltip *Tooltip::tooltip_global = nullptr;
+
+Tooltip::Tooltip(Widget *parent) : Label(parent)
+{
+ set_label("tooltip");
+ set_alignment(AlignCenter);
+ set_background(true);
+ set_visible(false);
+}
+
+Tooltip::~Tooltip()
+{
+}
+
+void Tooltip::resize()
+{
+ set_size(font()->width() * text().size() + UI::padding, font()->height() + UI::padding);
+}
+
+void Tooltip::draw_background()
+{
+ Paint::draw_material(global_location(), size(), "ui/window");
+}
+
+void Tooltip::draw()
+{
+ if (tooltip_global != this)
+ {
+ hide();
+ } else {
+ Label::draw();
+ }
+}
+
+void Tooltip::show()
+{
+ if ((tooltip_global != nullptr) && (tooltip_global != this)) {
+ tooltip_global->hide();
+ }
+ tooltip_global = this;
+ event_resize();
+
+ Label::show();
+}
+
+void Tooltip::hide()
+{
+ if (tooltip_global == this) {
+ tooltip_global = nullptr;
+ }
+ Label::hide();
+}
+
+void Tooltip::event_draw()
+{
+}
+
+void Tooltip::event_draw_global()
+{
+ if (tooltip_global && tooltip_global->visible())
+ {
+ if (tooltip_global->background())
+ tooltip_global->draw_background();
+
+ if (tooltip_global->border())
+ tooltip_global->draw_border();
+
+ tooltip_global->draw();
+
+ if (debug())
+ tooltip_global->draw_debug();
+ }
+}
+
+}
diff --git a/src/ui/tooltip.h b/src/ui/tooltip.h
new file mode 100644
index 0000000..629863a
--- /dev/null
+++ b/src/ui/tooltip.h
@@ -0,0 +1,80 @@
+/*
+ ui/tooltip.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_TOOLTIP_H__
+#define __INCLUDED_UI_TOOLTIP_H__
+
+#include "ui/label.h"
+
+namespace ui
+{
+ /**
+ * @brief a widget displaying a tooltip.
+ * This class makes sure only one Tooltip is globally visible.
+ */
+class Tooltip : public Label
+{
+ public:
+ Tooltip(Widget *parent);
+ virtual ~Tooltip();
+
+ /**
+ * @brief resize the tooltip
+ * */
+ virtual void resize();
+
+ /**
+ * @brief show the tooltip
+ * */
+ virtual void show();
+
+ /**
+ * @brief hide the tooltip
+ * */
+ virtual void hide();
+
+ /**
+ * @brief draw event distributor
+ * The default draw event distributor is overwritten to do nothing.
+ * Tooltips are drawn separately because the need to be on top of everything else.
+ * @see event_draw_global
+ * */
+ virtual void event_draw();
+
+ /**
+ * @brief global draw event distributor
+ * This is called by the user interface to draw the tooltip after everything else.
+ * */
+ static void event_draw_global();
+
+ /**
+ * @brief the tooltip that is currently visible, nullptr if no tooltip is currently shown
+ *
+ * */
+ static inline Tooltip *global()
+ {
+ return tooltip_global;
+ }
+
+ protected:
+ /**
+ * @brief draw the tooltip
+ */
+ virtual void draw();
+
+ /**
+ * @brief draw the tooltip background
+ */
+ virtual void draw_background();
+
+ private:
+
+ static Tooltip *tooltip_global;
+};
+
+}
+
+#endif // __INCLUDED_UI_TOOLTIP_H__
diff --git a/src/ui/ui.cc b/src/ui/ui.cc
index 0877519..95b18e2 100644
--- a/src/ui/ui.cc
+++ b/src/ui/ui.cc
@@ -4,13 +4,11 @@
the terms of the GNU General Public License version 2
*/
-#include <string>
-#include <sstream>
-
#include "audio/audio.h"
#include "auxiliary/functions.h"
#include "core/core.h"
#include "core/application.h"
+#include "core/cvar.h"
#include "filesystem/filesystem.h"
#include "render/gl.h"
#include "sys/sys.h"
@@ -20,6 +18,10 @@
#include "ui/ui.h"
#include "ui/widget.h"
+#include <string>
+#include <sstream>
+#include <cassert>
+
namespace ui
{
@@ -32,8 +34,12 @@ math::Vector2f UI::elementsize(256, 32);
float UI::padding = 24.0f;
float UI::margin = 16.0f;
+float UI::icon_small = 24.0f;
+
float UI::pointer_size = 48.0f;
+core::Cvar *ui_tooltiptimeout = nullptr;
+
UI *global_ui = 0;
UI *root()
@@ -44,6 +50,9 @@ UI *root()
void init()
{
con_print << "^BInitializing user interface..." << std::endl;
+
+ ui_tooltiptimeout = core::Cvar::get("ui_tooltiptimeout", "250", core::Cvar::Archive);
+ ui_tooltiptimeout->set_info("[int] time in milliseconds before a tooltip is shown");
if (!global_ui) {
global_ui = new UI();
@@ -94,6 +103,7 @@ UI::UI() : Window(0)
mouse_pointer_bitmap.assign("pointer");
mouse_buttonleft_pressed = false;
+ ui_tooltip_timestamp = core::application()->timestamp();
}
UI::~UI()
@@ -266,7 +276,7 @@ void UI::frame()
Widget *f = 0;
if (!mouse_buttonleft_pressed) {
- f = find_mouse_focus(mouse_cursor);
+ f = find_widget_in_location(mouse_cursor);
} else {
f = find_visible_child(ui_mouse_focus);
}
@@ -275,15 +285,38 @@ void UI::frame()
}
ui_mouse_focus = f;
+ // show tooltip if the timeout has expired
+ if (ui_mouse_focus && ui_mouse_focus->tooltip() && ui_mouse_focus->tooltip()->text().size() && ui_mouse_focus->tooltip()->hidden())
+ {
+ assert(ui_tooltiptimeout != nullptr);
+ unsigned long timeout = (unsigned long) ui_tooltiptimeout->value();
+
+ if (ui_tooltip_timestamp + timeout < core::application()->timestamp()) {
+ // move the tooltip below the mouse cursor
+ math::Vector2f p(
+ ui_mouse_focus->tooltip()->parent() ?
+ ui_mouse_focus->tooltip()->parent()->to_local_coords(mouse_cursor) :
+ mouse_cursor);
+
+ ui_mouse_focus->tooltip()->set_location(p.x() - ui_mouse_focus->tooltip()->width() * 0.5f, p.y() + pointer_size);
+ ui_mouse_focus->tooltip()->resize();
+ ui_mouse_focus->tooltip()->show();
+ }
+ }
+
// reset mouse pointer
ui::root()->set_pointer("pointer");
// draw the widget stack
event_draw();
-
- // draw the mouse pointer
- if (visible())
+
+ if (visible()) {
+ // draw tooltip
+ Tooltip::event_draw_global();
+
+ // draw the mouse pointer
draw_pointer();
+ }
}
/* -- global event handlers ---------------------------------------- */
@@ -293,6 +326,13 @@ void UI::frame()
*/
void UI::input_mouse(const float x, const float y)
{
+ // hide tooltip if the mouse has been moved
+ if (Tooltip::global() && Tooltip::global()->visible())
+ {
+ Tooltip::global()->hide();
+ }
+ ui_tooltip_timestamp = core::application()->timestamp();
+
mouse_cursor.assign(x, y);
}
@@ -300,13 +340,20 @@ bool UI::input_mouse_button(const bool pressed, unsigned int button)
{
bool handled = false;
+ // hide tooltip if a mouse button has been clicked
+ if (Tooltip::global() && Tooltip::global()->visible())
+ {
+ Tooltip::global()->hide();
+ }
+ ui_tooltip_timestamp = core::application()->timestamp();
+
if (button == SDL_BUTTON_LEFT)
{
mouse_buttonleft_pressed = pressed;
}
// set mouse focus
- Widget *f = find_mouse_focus(mouse_cursor);
+ Widget *f = find_widget_in_location(mouse_cursor);
if (f)
{
f->event_mouse(mouse_cursor);
@@ -326,7 +373,7 @@ bool UI::input_mouse_wheel(const math::Vector2f & direction)
bool handled = false;
// set mouse focus
- Widget *f = find_mouse_focus(mouse_cursor);
+ Widget *f = find_widget_in_location(mouse_cursor);
if (f)
{
f->event_mouse(mouse_cursor);
@@ -399,8 +446,8 @@ void UI::draw_pointer()
gl::push();
gl::translate(mouse_cursor.x(), mouse_cursor.y(), 0);
- float angle = core::application()->time() * 0.75f - floorf(core::application()->time() * 0.75f);
- angle *= 360.0f;
+ const float t = core::application()->time() * 0.75f;
+ const float angle = (t - floorf(t)) * 360.0f;
gl::rotate(angle, math::Vector3f(0, 0, 1.0f));
gl::translate(-mouse_cursor.x(), -mouse_cursor.y(), 0);
}
diff --git a/src/ui/ui.h b/src/ui/ui.h
index aaf4acc..009bed6 100644
--- a/src/ui/ui.h
+++ b/src/ui/ui.h
@@ -10,6 +10,7 @@
#include "ui/console.h"
#include "ui/font.h"
#include "ui/palette.h"
+#include "ui/tooltip.h"
#include "ui/widget.h"
#include "ui/window.h"
@@ -64,7 +65,7 @@ public:
/// load settings from ui.ini
void load_settings();
- /* -- fonts ------------------------------------------------ */
+ /* -- font & icon sizes------------------------------------- */
/// default tiny font
inline const Font *font_tiny() const {
@@ -76,17 +77,18 @@ public:
return ui_font_small;
}
- /// default medium font
+ /// default large font
inline const Font *font_large() const {
return ui_font_large;
}
-
+
+ /* -- mouse pointer ---------------------------------------- */
+
+ /// current position of the mouse cursor in global window coordinates
inline const math::Vector2f & global_mouse_coords()
{
return mouse_cursor;
}
-
- /* -- mouse pointer ---------------------------------------- */
/// set mouse pointer bitmap
void set_pointer(const char *pointerbitmap = 0, const Palette::Color color = Palette::Highlight, const bool animated = false);
@@ -109,7 +111,8 @@ public:
static float pointer_size;
-
+ static float icon_small;
+
protected:
/* -- event handlers --------------------------------------- */
@@ -138,6 +141,8 @@ private:
Palette::Color mouse_pointer_color;
bool mouse_pointer_animated;
bool mouse_buttonleft_pressed;
+
+ unsigned long ui_tooltip_timestamp;
};
/// initialize the user interface
diff --git a/src/ui/widget.cc b/src/ui/widget.cc
index 982b792..73c454a 100644
--- a/src/ui/widget.cc
+++ b/src/ui/widget.cc
@@ -9,6 +9,7 @@
#include "ui/paint.h"
#include "ui/ui.h"
#include "ui/widget.h"
+#include "ui/tooltip.h"
#include <cassert>
@@ -22,8 +23,9 @@ Widget::Widget(Widget *parent)
widget_border = true;
widget_background = false;
widget_enabled = true;
- widget_palette = 0;
- widget_font = 0;
+ widget_palette = nullptr;
+ widget_font = nullptr;
+ widget_tooltip = nullptr;
widget_label.assign("widget");
if (!parent) {
@@ -228,17 +230,33 @@ void Widget::set_label(const std::string & label)
widget_label.assign(label);
aux::to_label(widget_label);
}
-
+
void Widget::set_label(const char *label)
{
- if (label) {
+ if (label == nullptr)
+ {
+ widget_label.clear();
+ } else {
widget_label.assign(label);
aux::to_label(widget_label);
- } else {
- widget_label.clear();
}
}
+
+void Widget::set_tooltip(const std::string &tooltip_text)
+{
+ set_tooltip(tooltip_text.c_str());
+}
+
+void Widget::set_tooltip(const char *tooltip_text)
+{
+ if (widget_tooltip == nullptr)
+ {
+ widget_tooltip = new Tooltip(this);
+ }
+ widget_tooltip->set_text(tooltip_text);
+}
+
void Widget::set_palette(const Palette *palette)
{
widget_palette = palette;
@@ -300,7 +318,7 @@ Widget *Widget::next_sibling()
// find this widget in the parent's children
Children::iterator it = parent()->children().begin();
while (it != parent()->children().end() && ((*it) != this)) {
- it++;
+ it++;
}
// assert this widget is a child of its parent
@@ -384,17 +402,17 @@ Widget *Widget::find_visible_child(const Widget *widget)
return 0;
}
-Widget *Widget::find_mouse_focus(const math::Vector2f & pos)
+Widget *Widget::find_widget_in_location(const math::Vector2f & location)
{
// this widget is not visible
- if (!visible() || !size().contains(pos))
- return 0;
+ if (!visible() || !size().contains(location))
+ return nullptr;
// reverse-iterate children
for (Children::reverse_iterator rit = widget_children.rbegin(); rit != widget_children.rend(); ++rit) {
Widget *w = (*rit);
if (w->visible() && w->enabled()) {
- Widget *f = w->find_mouse_focus(pos - w->location());
+ Widget *f = w->find_widget_in_location(location - w->location());
if (f)
return f;
}
diff --git a/src/ui/widget.h b/src/ui/widget.h
index 14bea7b..9c7871f 100644
--- a/src/ui/widget.h
+++ b/src/ui/widget.h
@@ -23,6 +23,8 @@
namespace ui
{
+class Tooltip;
+
class Widget
{
@@ -129,6 +131,11 @@ public:
inline const std::string &label() const {
return widget_label;
}
+
+ /// widget tooltip
+ inline Tooltip *tooltip() {
+ return widget_tooltip;
+ }
/// true if this widget will draw a background
inline const bool background() const {
@@ -220,29 +227,35 @@ public:
/// set location of the top-left corner, relative to the parent
void set_location(const math::Vector2f &location);
- /// set the widgets width and height
+ /// set the widget's width and height
void set_size(const float w, const float h);
- /// set the widgets width and height
+ /// set the widget's width and height
void set_size(const math::Vector2f &size);
- /// set the widgets width
+ /// set the widget's width
void set_width(const float w);
- /// set the widgets height
+ /// set the widget's height
void set_height(const float h);
- /// set the widgets palette
+ /// set the widget's palette
void set_palette(const Palette *palette);
- /// set the widgets font
+ /// set the widget's font
void set_font(const Font *font);
- /// set the widgets label
+ /// set the widget's label
void set_label(const std::string &label);
- /// set the widgets label
- void set_label(const char *label);
+ /// set the widget's label
+ void set_label(const char *label = nullptr);
+
+ /// set the wdiget's tooltip text
+ void set_tooltip(const std::string &tooltip_text);
+
+ /// set the wdiget's tooltip text
+ void set_tooltip(const char *tooltip_text = nullptr);
/// enable or disable widget border
void set_border(const bool border = true);
@@ -262,7 +275,7 @@ public:
* @brief calls the draw event handler and sends the event to all child widgets
* @see draw
**/
- void event_draw();
+ virtual void event_draw();
/**
* @brief calls the key event handlers and sends unhandled keys to the parent widget
@@ -303,37 +316,14 @@ public:
inline void emit(const Event event, void *data=0) {
event_emit(this, event, data);
}
-
-protected:
-
- /// find the widget that has input focus
- virtual Widget *find_input_focus();
-
- /// find widget that has mouse focus
- /** @param cursor mouse cursor position relative to this widget's location
- */
- Widget *find_mouse_focus(const math::Vector2f & cursor);
- /// find a visible widget
- Widget *find_visible_child(const Widget *widget);
-
- /// list widget content
- size_t list(const size_t indent, const bool visible_only = false) const;
-
- /// print widget description
- virtual void print(const size_t indent) const;
-
- /// true of this sibling has local focus
- inline bool focus() const {
- return widget_focus;
- }
-
+
/* -- coordinate mapping ----------------------------------- */
/// map local widget location to global location
- inline math::Vector2f global_location() {
+ inline const math::Vector2f global_location() const {
math::Vector2f v(widget_location);
- Widget *parent = widget_parent;
+ const Widget *parent = widget_parent;
while (parent) {
v += parent->location();
parent = parent->parent();
@@ -342,9 +332,9 @@ protected:
}
/// map local coordinates to global coordinates
- inline math::Vector2f to_global_coords(const math::Vector2f &local) {
+ inline const math::Vector2f to_global_coords(const math::Vector2f &local) const {
math::Vector2f v(local);
- Widget *parent = widget_parent;
+ const Widget *parent = widget_parent;
do {
v += parent->location();
parent = parent->parent();
@@ -353,9 +343,9 @@ protected:
}
/// map global coordinates to local coordinates
- inline math::Vector2f to_local_coords(const math::Vector2f &global) {
+ inline const math::Vector2f to_local_coords(const math::Vector2f &global) const {
math::Vector2f v(global);
- Widget *parent = this;
+ const Widget *parent = this;
while (parent) {
v -= parent->location();
parent = parent->parent();
@@ -363,6 +353,34 @@ protected:
return v;
}
+protected:
+
+ /// find the widget that has input focus
+ virtual Widget *find_input_focus();
+
+ /**
+ * @brief find the widget in a given location
+ * Searches the widget's children tree for the leaf widget visible in a given location.
+ * If no child contains the location, the widget itself is tested. Returns a nullptr ig
+ * the location is not within the widget's boundries.
+ * @param location search position, relative to this widget's location
+ **/
+ Widget *find_widget_in_location(const math::Vector2f &location);
+
+ /// find a visible widget
+ Widget *find_visible_child(const Widget *widget);
+
+ /// list widget content
+ size_t list(const size_t indent, const bool visible_only = false) const;
+
+ /// print widget description
+ virtual void print(const size_t indent) const;
+
+ /// true of this sibling has local focus
+ inline bool focus() const {
+ return widget_focus;
+ }
+
/* -- event handlers --------------------------------------- */
/// called when the mouse receives mouse movement
@@ -437,6 +455,8 @@ private:
const Palette *widget_palette;
const Font *widget_font;
Widget *widget_parent;
+
+ Tooltip *widget_tooltip;
Children::iterator find_child(Widget *child);