From fecd2866f52560699920667a3f167f386fb1459b Mon Sep 17 00:00:00 2001 From: Rtch90 Date: Sat, 14 Apr 2018 19:30:27 +0100 Subject: [PATCH] [Add] Gui Tooltips. [Clean] Cleaned up GUI::Screen. --- src/Makefile.am | 4 +- src/glfreetype.cpp | 16 ++++++ src/glfreetype.h | 1 + src/gui.cpp | 44 ++++++++++++++++ src/gui.h | 3 ++ src/gui_button.cpp | 2 +- src/gui_container.cpp | 32 +++++++++++ src/gui_container.h | 1 + src/gui_events.h | 6 ++- src/gui_fixed.cpp | 2 +- src/gui_label.cpp | 13 +++-- src/gui_label.h | 1 + src/gui_multi_state_image_button.cpp | 11 ++++ src/gui_multi_state_image_button.h | 4 ++ src/gui_screen.cpp | 79 +++++++++++----------------- src/gui_screen.h | 6 ++- src/gui_tooltip.cpp | 71 +++++++++++++++++++++++++ src/gui_tooltip.h | 21 ++++++++ src/gui_widget.cpp | 74 +++++++++++++++++++++++++- src/gui_widget.h | 43 ++++++++++----- src/sector_view.cpp | 3 ++ src/ship_cpanel.cpp | 14 ++--- src/system_view.cpp | 2 + src/world_view.cpp | 10 ++-- 24 files changed, 381 insertions(+), 82 deletions(-) create mode 100644 src/gui_tooltip.cpp create mode 100644 src/gui_tooltip.h diff --git a/src/Makefile.am b/src/Makefile.am index bb1f974..93f222d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,13 +6,13 @@ noinst_LIBRARIES = libgui.a include_HEADERS = body.h frame.h generic_system_view.h glfreetype.h gui_button.h gui_container.h gui_events.h gui_fixed.h \ gui.h gui_image_button.h gui_image.h gui_image_radio_button.h gui_label.h gui_multi_state_image_button.h gui_radio_button.h \ - gui_radio_group.h gui_screen.h gui_toggle_button.h gui_widget.h libs.h matrix4x4.h mtrand.h l3d.h \ + gui_radio_group.h gui_screen.h gui_toggle_button.h gui_widget.h gui_tooltip.h libs.h matrix4x4.h mtrand.h l3d.h \ planet.h player.h dynamic_body.h sector.h sector_view.h ship_cpanel.h ship.h space.h star.h star_system.h system_info_view.h \ system_view.h vector3.h view.h world_view.h date.h space_station.h space_station_view.h model_body.h gui_iselectable.h \ ship_type.h object.h info_view.h model_coll_mesh_data.h object_viewer_view.h fixed.h custom_starsystems.h gameconsts.h \ aabb.h serializer.h sfx.h -libgui_a_SOURCES = gui_button.cpp gui.cpp gui_fixed.cpp gui_screen.cpp gui_label.cpp gui_toggle_button.cpp gui_radio_button.cpp \ +libgui_a_SOURCES = gui_button.cpp gui.cpp gui_fixed.cpp gui_screen.cpp gui_label.cpp gui_tooltip.cpp gui_toggle_button.cpp gui_radio_button.cpp \ gui_radio_group.cpp gui_image_button.cpp gui_image.cpp gui_image_radio_button.cpp gui_multi_state_image_button.cpp gui_widget.cpp \ gui_container.cpp diff --git a/src/glfreetype.cpp b/src/glfreetype.cpp index 63e8b03..09aacdb 100644 --- a/src/glfreetype.cpp +++ b/src/glfreetype.cpp @@ -283,6 +283,22 @@ void FontFace::RenderGlyph(int chr) { glDrawElements(GL_TRIANGLES, glyph->numidx, GL_UNSIGNED_SHORT, glyph->iarray); } +void FontFace::MeasureString(const char* str, float& w, float& h) { + w = 0; + h = GetHeight(); + float line_width = 0; + for(unsigned int i = 0; i < strlen(str); i++) { + if(str[i] == '\n') { + if(line_width > w) w = line_width; + line_width = 0; + h += GetHeight(); + } else { + line_width += m_glyphs[str[i]].advx; + } + } + if(line_width > w) w = line_width; +} + void FontFace::RenderString(const char* str) { glPushMatrix(); for(unsigned int i = 0; i < strlen(str); i++) { diff --git a/src/glfreetype.h b/src/glfreetype.h index 52fb433..3da23f1 100644 --- a/src/glfreetype.h +++ b/src/glfreetype.h @@ -8,6 +8,7 @@ public: void RenderGlyph(int chr); void RenderString(const char* str); void RenderMarkup(const char* str); + void MeasureString(const char* str, float& w, float& h); /* Of Ms. */ float GetHeight(void) { return m_height; } diff --git a/src/gui.cpp b/src/gui.cpp index 51217ad..8631e6d 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -3,6 +3,7 @@ namespace Gui { namespace RawEvents { + sigc::signal onMouseMotion; sigc::signal onMouseDown; sigc::signal onMouseUp; sigc::signal onKeyDown; @@ -31,10 +32,53 @@ void HandleSDLEvent(SDL_Event* event) { case SDL_KEYUP: RawEvents::onKeyUp.emit(&event->key); break; + case SDL_MOUSEMOTION: + Screen::OnMouseMotion(&event->motion); + RawEvents::onMouseMotion.emit(&event->motion); + break; + } +} + +struct TimerSignal { + Uint32 goTime; + sigc::signal* sig; +}; + +static std::list g_timeSignals; + +void AddTimer(Uint32 ms, sigc::signal* s) { + TimerSignal _s; + _s.goTime = SDL_GetTicks() + ms; + _s.sig = s; + g_timeSignals.push_back(_s); +} + +void RemoveTimer(sigc::signal* s) { + for(std::list::iterator i = g_timeSignals.begin(); + i!= g_timeSignals.end();) { + if((*i).sig == s) + i = g_timeSignals.erase(i); + else ++i; + } +} + +static void ExpireTimers(Uint32 t) { + for(std::list::iterator i = g_timeSignals.begin(); + i != g_timeSignals.end();) { + if(t >= (*i).goTime) + i = g_timeSignals.erase(i); + else ++i; } } void Draw(void) { + Uint32 t = SDL_GetTicks(); + /* Let's abuse it like an update() function also.. */ + for(std::list::iterator i = g_timeSignals.begin(); i != g_timeSignals.end(); ++i) { + if(t >= (*i).goTime)(*i).sig->emit(); + } + ExpireTimers(t); + Screen::Draw(); } diff --git a/src/gui.h b/src/gui.h index f943285..c7e3e27 100644 --- a/src/gui.h +++ b/src/gui.h @@ -9,6 +9,8 @@ void HandleSDLEvent(SDL_Event* event); void Draw(void); + void AddTimer(Uint32 ms, sigc::signal* s); + void RemoveTimer(sigc::signal* s); void Init(int screen_width, int screen_height, int ui_width, int ui_height); } @@ -35,5 +37,6 @@ namespace Gui { #include "gui_radio_group.h" #include "gui_fixed.h" #include "gui_label.h" +#include "gui_tooltip.h" #include "gui_screen.h" diff --git a/src/gui_button.cpp b/src/gui_button.cpp index 278fc6a..6cc64a6 100644 --- a/src/gui_button.cpp +++ b/src/gui_button.cpp @@ -7,7 +7,7 @@ namespace Gui { Button::Button(void) { m_isPressed = false; - m_eventMask = EVENT_MOUSEDOWN | EVENT_MOUSEUP; + m_eventMask = EVENT_MOUSEDOWN | EVENT_MOUSEUP | EVENT_MOUSEMOTION; SetSize(BUTTON_SIZE, BUTTON_SIZE); } diff --git a/src/gui_container.cpp b/src/gui_container.cpp index 977671d..939c4a8 100644 --- a/src/gui_container.cpp +++ b/src/gui_container.cpp @@ -3,6 +3,38 @@ namespace Gui { +bool Container::OnMouseMotion(MouseMotionEvent* e) { + float x = e->x; + float y = e->y; + for(std::list::iterator i = m_children.begin(); i != m_children.end(); ++i) { + float pos[2],size[2]; + if(!(*i).w->IsVisible()) { + if((*i).w->IsMouseOver() == true) + (*i).w->OnMouseLeave(); + continue; + } + int evmask = (*i).w->GetEventMask(); + if(!(evmask & Widget::EVENT_MOUSEMOTION)) continue; + + (*i).w->GetPosition(pos); + (*i).w->GetSize(size); + + if((x >= pos[0]) && (x < pos[0]+size[0]) && + (y >= pos[1]) && (y < pos[1]+size[1])) { + e->x = x-pos[0]; + e->y = y-pos[1]; + if((*i).w->IsMouseOver() == false) { + (*i).w->OnMouseEnter(); + } + bool alive = (*i).w->OnMouseMotion(e); + if(!alive) return false; + } else { + if((*i).w->IsMouseOver() == true) + (*i).w->OnMouseLeave(); + } + } + return true; +} bool Container::HandleMouseEvent(MouseButtonEvent* e) { float x = e->x; diff --git a/src/gui_container.h b/src/gui_container.h index 982c15f..0bcacdc 100644 --- a/src/gui_container.h +++ b/src/gui_container.h @@ -9,6 +9,7 @@ namespace Gui { public: bool OnMouseDown(MouseButtonEvent* e); bool OnMouseUp(MouseButtonEvent* e); + bool OnMouseMotion(MouseMotionEvent* e); void DeleteAllChildren(void); virtual void Draw(void); virtual void ShowAll(void); diff --git a/src/gui_events.h b/src/gui_events.h index 5da523e..387517f 100644 --- a/src/gui_events.h +++ b/src/gui_events.h @@ -3,7 +3,11 @@ namespace Gui { struct MouseButtonEvent { Uint8 isdown; Uint8 button; - float x, y; /* Widget coords. */ + float x, y; /* Widget coords. */ + float screenX, screenY; /* Screen coords. */ + }; + struct MouseMotionEvent { + float x, y; /* Widget coords. */ float screenX, screenY; /* Screen coords. */ }; } diff --git a/src/gui_fixed.cpp b/src/gui_fixed.cpp index 58e0cc0..f868329 100644 --- a/src/gui_fixed.cpp +++ b/src/gui_fixed.cpp @@ -7,7 +7,7 @@ Fixed::Fixed(float w, float h) { SetSize(w, h); memcpy(m_bgcol, Color::bg, 3*sizeof(float)); m_w = w; m_h = h; - m_transparent = false; + m_transparent = true; m_eventMask = EVENT_ALL; } diff --git a/src/gui_label.cpp b/src/gui_label.cpp index 9587776..afa97e6 100644 --- a/src/gui_label.cpp +++ b/src/gui_label.cpp @@ -12,12 +12,20 @@ Label::Label(std::string& text) { m_color[0] = m_color[1] = m_color[2] = 1.0f; } +void Label::RecalcSize(void) { + float w, h; + Screen::MeasureString(m_text, w, h); + SetSize(w,h); +} + void Label::SetText(const char* text) { m_text = text; + RecalcSize(); } void Label::SetText(std::string& text) { m_text = text; + RecalcSize(); } void Label::Draw(void) { @@ -26,9 +34,8 @@ void Label::Draw(void) { } void Label::GetSizeRequested(float size[2]) { -#pragma message("Not setting size correctly.") - size[0] = 70; - size[1] = 10; + RecalcSize(); + GetSize(size); } void Label::SetColor(float r, float g, float b) { diff --git a/src/gui_label.h b/src/gui_label.h index 5717e37..452668f 100644 --- a/src/gui_label.h +++ b/src/gui_label.h @@ -14,6 +14,7 @@ namespace Gui { void SetText(std::string& text); void SetColor(float r, float g, float b); private: + void RecalcSize(void); std::string m_text; float m_color[3]; }; diff --git a/src/gui_multi_state_image_button.cpp b/src/gui_multi_state_image_button.cpp index 8416cb3..a8e10e5 100644 --- a/src/gui_multi_state_image_button.cpp +++ b/src/gui_multi_state_image_button.cpp @@ -18,11 +18,13 @@ MultiStateImageButton::~MultiStateImageButton(void) { void MultiStateImageButton::StateNext(void) { m_curState++; if(m_curState >= (signed)m_states.size()) m_curState = 0; + UpdateOverriddenTooltip(); } void MultiStateImageButton::StatePrev(void) { m_curState--; if(m_curState < 0) m_curState = (signed)m_states.size()-1; + UpdateOverriddenTooltip(); } void MultiStateImageButton::OnActivate(void) { @@ -49,14 +51,23 @@ void MultiStateImageButton::Draw(void) { } void MultiStateImageButton::AddState(int state, const char* filename) { + AddState(state, filename, ""); +} + +void MultiStateImageButton::AddState(int state, const char* filename, std::string tooltip) { State s; s.state = state; s.image = new Image(filename); + s.tooltip = tooltip; m_states.push_back(s); float size[2]; s.image->GetSizeRequested(size); SetSize(size[0], size[1]); } +std::string MultiStateImageButton::GetOverrideTooltip(void) { + return m_states[m_curState].tooltip; +} + } diff --git a/src/gui_multi_state_image_button.h b/src/gui_multi_state_image_button.h index 4f69a88..b85c973 100644 --- a/src/gui_multi_state_image_button.h +++ b/src/gui_multi_state_image_button.h @@ -12,16 +12,20 @@ namespace Gui { virtual ~MultiStateImageButton(void); virtual void GetSizeRequested(float size[2]); void AddState(int state, const char* filename); + void AddState(int state, const char* filename, std::string tooltip); int GetState(void) { return m_states[m_curState].state; } void StateNext(void); void StatePrev(void); virtual void OnActivate(void); sigc::signal onClick; virtual void SetSelected(bool state); + protected: + virtual std::string GetOverrideTooltip(void); private: struct State { int state; Image* image; + std::string tooltip; }; std::vector m_states; int m_curState; diff --git a/src/gui_screen.cpp b/src/gui_screen.cpp index af14297..34f5b92 100644 --- a/src/gui_screen.cpp +++ b/src/gui_screen.cpp @@ -11,11 +11,11 @@ int Screen::realWidth; int Screen::realHeight; float Screen::invRealWidth; float Screen::invRealHeight; -std::list Screen::widgets; std::list Screen::kbshortcut_widgets; float Screen::font_xsize; float Screen::font_ysize; std::vector Screen::labelPositions; +Gui::Fixed* Screen::baseContainer; void Screen::Init(int real_width, int real_height, int ui_width, int ui_height) { Screen::width = ui_width; @@ -28,6 +28,8 @@ void Screen::Init(int real_width, int real_height, int ui_width, int ui_height) Screen::font = new FontFace("font.ttf"); Screen::font_xsize = 16*0.8; Screen::font_ysize = 16; + Screen::baseContainer = new Gui::Fixed(Screen::width, Screen::height); + Screen::baseContainer->SetPosition(0,0); } GLint Screen::Project(GLdouble objX, GLdouble objY, GLdouble objZ, const GLdouble* model, @@ -46,7 +48,6 @@ void Screen::EnterOrtho(void) { glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); - //glOrtho(9, 320, 0, 200, -1, 1); glOrtho(0, width, 0, height, -1, 1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); @@ -67,65 +68,43 @@ void Screen::Draw(void) { labelPositions.clear(); EnterOrtho(); - for(std::list::iterator i = Screen::widgets.begin(); i != Screen::widgets.end(); ++i) { - if(!(*i)->IsVisible()) continue; - glPushMatrix(); - float pos[2]; - (*i)->GetPosition(pos); - glTranslatef(pos[0], pos[1], 0); - (*i)->Draw(); - glPopMatrix(); - } + baseContainer->Draw(); LeaveOrtho(); } void Screen::AddBaseWidget(Widget* w, int x, int y) { - w->SetPosition(x, y); - Screen::widgets.push_back(w); + baseContainer->Add(w, x, y); } void Screen::RemoveBaseWidget(Widget* w) { - Screen::widgets.remove(w); + baseContainer->Remove(w); +} + +void Screen::SDLEventCoordToScreenCoord(int sdlev_x, int sdlev_y, float* x, float* y) { + *y = height-(sdlev_y*height*invRealHeight); + *x = sdlev_x*width*invRealWidth; +} + +void Screen::OnMouseMotion(SDL_MouseMotionEvent* e) { + MouseMotionEvent ev; + float x, y; + Screen::SDLEventCoordToScreenCoord(e->x, e->y, &x, &y); + ev.screenX = ev.x = x; + ev.screenY = ev.y = y; + baseContainer->OnMouseMotion(&ev); } void Screen::OnClick(SDL_MouseButtonEvent* e) { MouseButtonEvent ev; - float x = e->x; - float y = e->y; - y = height-(y*height*invRealHeight); - x = x*width*invRealWidth; + float x, y; + Screen::SDLEventCoordToScreenCoord(e->x, e->y, &x, &y); ev.button = e->button; ev.isdown = (e->type == SDL_MOUSEBUTTONDOWN); - ev.x = x; - ev.y = y; - ev.screenX = x; - ev.screenY = y; + ev.screenX = ev.x = x; + ev.screenY = ev.y = y; OnClickTestLabels(ev); - for(std::list::iterator i = Screen::widgets.begin(); i != Screen::widgets.end(); ++i) { - float size[2], pos[2]; - if(!(*i)->IsVisible()) continue; - int evmask = (*i)->GetEventMask(); - if(ev.isdown) { - if(!(evmask & Widget::EVENT_MOUSEDOWN)) continue; - } else { - if(!(evmask & Widget::EVENT_MOUSEUP)) continue; - } - (*i)->GetPosition(pos); - (*i)->GetSize(size); - - if((x >= pos[0]) && (x < pos[0]+size[0]) && - (y >= pos[1]) && (y < pos[1]+size[1])) { - - ev.x = x-pos[0]; - ev.y = y-pos[1]; - - if(ev.isdown) { - (*i)->OnMouseDown(&ev); - } else { - (*i)->OnMouseUp(&ev); - } - } - } + if(ev.isdown) baseContainer->OnMouseDown(&ev); + else baseContainer->OnMouseUp(&ev); } void Screen::OnClickTestLabels(const Gui::MouseButtonEvent& ev) { @@ -147,6 +126,12 @@ void Screen::OnKeyDown(const SDL_keysym* sym) { } } +void Screen::MeasureString(const std::string& s, float& w, float& h) { + font->MeasureString(s.c_str(), w, h); + w *= Screen::font_xsize; + h *= Screen::font_ysize; +} + void Screen::RenderString(const std::string& s) { glPushMatrix(); glScalef(Screen::font_xsize, Screen::font_ysize, 1); diff --git a/src/gui_screen.h b/src/gui_screen.h index dad9894..cba4444 100644 --- a/src/gui_screen.h +++ b/src/gui_screen.h @@ -11,9 +11,11 @@ namespace Gui { static void Draw(void); static void AddBaseWidget(Widget* w, int x, int y); static void RemoveBaseWidget(Widget* w); + static void OnMouseMotion(SDL_MouseMotionEvent* e); static void OnClick(SDL_MouseButtonEvent* e); static void OnKeyDown(const SDL_keysym* sym); static void RenderString(const std::string& s); + static void MeasureString(const std::string& s, float& w, float& h); static void RenderMarkup(const std::string& s); static void PutClickableLabel(const std::string& s, float x, float y, sigc::slot slot); @@ -37,16 +39,18 @@ namespace Gui { static void OnClickTestLabels(const Gui::MouseButtonEvent& ev); static bool CanPutLabel(float x, float y); static void AddShortcutWidget(Widget* w); + static void SDLEventCoordToScreenCoord(int sdlev_x, int sdlev_y, float* x, float* y); static bool init; static int width, height; static int realWidth, realHeight; static float invRealWidth, invRealHeight; - static std::list widgets; static std::list kbshortcut_widgets; + static std::list mouseHoveredWidgets; static FontFace* font; static float font_xsize; static float font_ysize; + static Gui::Fixed* baseContainer; }; } diff --git a/src/gui_tooltip.cpp b/src/gui_tooltip.cpp new file mode 100644 index 0000000..cca3b01 --- /dev/null +++ b/src/gui_tooltip.cpp @@ -0,0 +1,71 @@ +#include "gui.h" + +namespace Gui { + +#define TOOLTIP_PADDING 5 +#define FADE_TIME_MS 500 + +ToolTip::ToolTip(const char* text) { + SetText(text); + m_createdTime = SDL_GetTicks(); +} + +void ToolTip::CalcSize(void) { + float w, h; + Screen::MeasureString(m_text, w, h); + w += 2*TOOLTIP_PADDING; + h += 2*TOOLTIP_PADDING; + SetSize(w, h); +} + +ToolTip::ToolTip(std::string& text) { + SetText(text); + m_createdTime = SDL_GetTicks(); +} + +void ToolTip::SetText(const char* text) { + m_text = text; + CalcSize(); +} + +void ToolTip::SetText(std::string& text) { + m_text = text; + CalcSize(); +} + +void ToolTip::Draw(void) { + float size[2]; + int age = SDL_GetTicks() - m_createdTime; + float alpha = age/(float)FADE_TIME_MS; alpha = MIN(alpha, 0.75); + glEnable(GL_BLEND); + GetSize(size); + glColor4f(.2, .2, .6, alpha); + glBegin(GL_QUADS); + glVertex2f(size[0], 0); + glVertex2f(size[0], size[1]); + glVertex2f(0, size[1]); + glVertex2f(0, 0); + glEnd(); + glColor4f(.0, .0, .8, alpha); + glBegin(GL_LINE_LOOP); + glVertex2f(size[0], 0); + glVertex2f(size[0], size[1]); + glVertex2f(0, size[1]); + glVertex2f(0, 0); + glEnd(); + glPushMatrix(); + glTranslatef(TOOLTIP_PADDING, TOOLTIP_PADDING, 0); + glColor4f(1, 1, 1, alpha); + Screen::RenderMarkup(m_text); + glPopMatrix(); + glDisable(GL_BLEND); +} + +void ToolTip::GetSizeRequested(float size[2]) { +#pragma message("Not setting size correctly.") + size[0] = 70; + size[1] = 10; +} + +} + diff --git a/src/gui_tooltip.h b/src/gui_tooltip.h new file mode 100644 index 0000000..75ec2ad --- /dev/null +++ b/src/gui_tooltip.h @@ -0,0 +1,21 @@ +#pragma once +#include +#include "gui_widget.h" + +namespace Gui { + class ToolTip : public Widget { + public: + ToolTip(const char* text); + ToolTip(std::string& text); + virtual void Draw(void); + virtual ~ToolTip(void) {} + virtual void GetSizeRequested(float size[2]); + void SetText(const char* text); + void SetText(std::string& text); + private: + void CalcSize(void); + std::string m_text; + Uint32 m_createdTime; + }; +} + diff --git a/src/gui_widget.cpp b/src/gui_widget.cpp index 7699acc..3022e88 100644 --- a/src/gui_widget.cpp +++ b/src/gui_widget.cpp @@ -3,8 +3,12 @@ namespace Gui { Widget::Widget(void) { - m_visible = false; - m_eventMask = EVENT_NONE; + m_parent = 0; + m_visible = false; + m_mouseOver = false; + m_eventMask = EVENT_NONE; + m_tooltipWidget = 0; + m_tooltipTimerSignal.connect(sigc::mem_fun(this, &Widget::OnToolTip)); } void Widget::SetShortcut(SDLKey key, SDLMod mod) { @@ -20,5 +24,71 @@ void Widget::OnPreShortcut(const SDL_keysym* sym) { } } +void Widget::GetAbsolutePosition(float pos[2]) { + GetPosition(pos); + const Container* parent = GetParent(); + while(parent) { + pos[0] += parent->m_size.x; + pos[1] += parent->m_size.y; + parent = parent->GetParent(); + } +} + +void Widget::OnMouseEnter(void) { + m_mouseOver = true; + Gui::AddTimer(1000, &m_tooltipTimerSignal); +} + +void Widget::OnMouseLeave(void) { + m_mouseOver = false; + if(m_tooltipWidget) { + Screen::RemoveBaseWidget(m_tooltipWidget); + m_tooltipWidget = 0; + } + Gui::RemoveTimer(&m_tooltipTimerSignal); +} + +void Widget::UpdateOverriddenTooltip(void) { + if(m_tooltipWidget) { + std::string text = GetOverrideTooltip(); + m_tooltipWidget->SetText(text); + } +} + +void Widget::OnToolTip(void) { + if(!m_tooltipWidget) { + std::string text = GetOverrideTooltip(); + if(text == "") text = m_tooltip; + if(text == "") return; + + float pos[2]; + GetAbsolutePosition(pos); + m_tooltipWidget = new ToolTip(text); + if(m_tooltipWidget->m_size.w + pos[0] > Screen::GetWidth()) + pos[0] = Screen::GetWidth() - m_tooltipWidget->m_size.w; + if(m_tooltipWidget->m_size.h + pos[1] > Screen::GetHeight()) + pos[1] = Screen::GetHeight() - m_tooltipWidget->m_size.h; + + Screen::AddBaseWidget(m_tooltipWidget, pos[0], pos[1]); + m_tooltipWidget->Show(); + } +} + +void Widget::Hide(void) { + m_visible = false; + if(m_tooltipWidget) { + Screen::RemoveBaseWidget(m_tooltipWidget); + delete m_tooltipWidget; + m_tooltipWidget = 0; + } +} + +Widget::~Widget(void) { + if(m_tooltipWidget) { + Screen::RemoveBaseWidget(m_tooltipWidget); + delete m_tooltipWidget; + } +} + } diff --git a/src/gui_widget.h b/src/gui_widget.h index 7be0b0d..c04187f 100644 --- a/src/gui_widget.h +++ b/src/gui_widget.h @@ -3,36 +3,45 @@ namespace Gui { class Container; + class ToolTip; class Widget { public: Widget(void); virtual void Draw(void) = 0; - virtual ~Widget(void) {} + virtual ~Widget(void); virtual void GetSizeRequested(float size[2]) = 0; - void GetPosition(float pos[2]) { pos[0] = m_size.x; pos[1] = m_size.y; } + void GetPosition(float pos[2]) const { pos[0] = m_size.x; pos[1] = m_size.y; } + void GetAbsolutePosition(float pos[2]); void SetPosition(float x, float y) { m_size.x = x; m_size.y = y; } void GetSize(float size[2]) { size[0] = m_size.w; size[1] = m_size.h; } void SetSize(float w, float h) { m_size.w = w; m_size.h = h; }; void SetShortcut(SDLKey key, SDLMod mod); virtual void Show(void) { m_visible = true; } - virtual void Hide(void) { m_visible = false; } + virtual void Hide(void); bool IsVisible(void) { return m_visible; } - Container* GetParent(void) { return m_parent; } + Container* GetParent(void) const { return m_parent; } void SetParent(Container* p) { m_parent = p; } + void SetToolTip(std::string s) { m_tooltip = s; } + const std::string& GetToolTip(void) const { return m_tooltip; } /* Event handlers should return false to stop propagating event. */ - virtual bool OnMouseDown(MouseButtonEvent* e) { return false; } - virtual bool OnMouseUp(MouseButtonEvent* e) { return false; } - virtual void OnActivate(void) {} + virtual bool OnMouseDown(MouseButtonEvent* e) { return false; } + virtual bool OnMouseUp(MouseButtonEvent* e) { return false; } + virtual bool OnMouseMotion(MouseMotionEvent* e) { return true; } + virtual void OnActivate(void) { } + virtual void OnMouseEnter(void); + virtual void OnMouseLeave(void); + bool IsMouseOver(void) { return m_mouseOver; } /* Only to be called by Screen::OnKeyDown. */ void OnPreShortcut(const SDL_keysym* sym); enum EventMask { - EVENT_NONE = 0, - EVENT_KEYDOWN = 1<<0, - EVENT_KEYUP = 1<<1, - EVENT_MOUSEDOWN = 1<<2, - EVENT_MOUSEUP = 1<<3, - EVENT_ALL = 0xffffffff + EVENT_NONE = 0, + EVENT_KEYDOWN = 1<<0, + EVENT_KEYUP = 1<<1, + EVENT_MOUSEDOWN = 1<<2, + EVENT_MOUSEUP = 1<<3, + EVENT_MOUSEMOTION = 1<<4, /* Needed for OnMouseEnter, Leave, IsMOuseOver. */ + EVENT_ALL = 0xffffffff }; unsigned int GetEventMask(void) { return m_eventMask; } protected: @@ -41,12 +50,20 @@ namespace Gui { SDLKey sym; SDLMod mod; } m_shortcut; + + virtual std::string GetOverrideTooltip(void) { return ""; } + void UpdateOverriddenTooltip(void); private: struct { float x,y,w,h; } m_size; bool m_visible; + bool m_mouseOver; Container* m_parent; + std::string m_tooltip; + sigc::signal m_tooltipTimerSignal; + ToolTip* m_tooltipWidget; + void OnToolTip(); }; } diff --git a/src/sector_view.cpp b/src/sector_view.cpp index 38d368c..f8ff820 100644 --- a/src/sector_view.cpp +++ b/src/sector_view.cpp @@ -21,14 +21,17 @@ SectorView::SectorView(void) : GenericSystemView() { Gui::ImageButton* ib = new Gui::ImageButton("icons/sectorview_f6_systeminfo.png"); ib->onClick.connect(sigc::mem_fun(this, &SectorView::OnClickSystemInfo)); ib->SetShortcut(SDLK_F5, KMOD_NONE); + ib->SetToolTip("Star system information."); m_rightButtonBar->Add(ib, 2, 2); m_zoomInButton = new Gui::ImageButton("icons/zoom_in_f7.png"); m_zoomInButton->SetShortcut(SDLK_F6, KMOD_NONE); + m_zoomInButton->SetToolTip("Zoom in."); m_rightButtonBar->Add(m_zoomInButton, 34, 2); m_zoomOutButton = new Gui::ImageButton("icons/zoom_out_f8.png"); m_zoomOutButton->SetShortcut(SDLK_F7, KMOD_NONE); + m_zoomOutButton->SetToolTip("Zoom out."); m_rightButtonBar->Add(m_zoomOutButton, 66, 2); m_gluDiskDlist = glGenLists(1); diff --git a/src/ship_cpanel.cpp b/src/ship_cpanel.cpp index d8dbed0..85d1cfe 100644 --- a/src/ship_cpanel.cpp +++ b/src/ship_cpanel.cpp @@ -50,9 +50,9 @@ ShipCpanel::ShipCpanel(void) : Gui::Fixed(640, 64) { Gui::MultiStateImageButton* cam_button = new Gui::MultiStateImageButton(); g->Add(cam_button); cam_button->SetSelected(true); - cam_button->AddState(WorldView::CAM_FRONT, "icons/cam_front.png"); - cam_button->AddState(WorldView::CAM_REAR, "icons/cam_rear.png"); - cam_button->AddState(WorldView::CAM_EXTERNAL, "icons/cam_external.png"); + cam_button->AddState(WorldView::CAM_FRONT, "icons/cam_front.png", "Front view"); + cam_button->AddState(WorldView::CAM_REAR, "icons/cam_rear.png", "Read view"); + cam_button->AddState(WorldView::CAM_EXTERNAL, "icons/cam_external.png", "External view"); cam_button->SetShortcut(SDLK_F1, KMOD_NONE); cam_button->onClick.connect(sigc::mem_fun(this, &ShipCpanel::OnChangeCamView)); Add(cam_button, 2, 2); @@ -61,8 +61,8 @@ ShipCpanel::ShipCpanel(void) : Gui::Fixed(640, 64) { g->Add(map_button); map_button->SetSelected(false); map_button->SetShortcut(SDLK_F2, KMOD_NONE); - map_button->AddState(L3D::MAP_SECTOR, "icons/cpan_f2_map.png"); - map_button->AddState(L3D::MAP_SYSTEM, "icons/cpan_f2_normal.png"); + map_button->AddState(L3D::MAP_SECTOR, "icons/cpan_f2_map.png", "Galaxy sector map"); + map_button->AddState(L3D::MAP_SYSTEM, "icons/cpan_f2_normal.png", "Star system view"); map_button->onClick.connect(sigc::mem_fun(this, &ShipCpanel::OnChangeMapView)); Add(map_button, 34, 2); @@ -70,7 +70,7 @@ ShipCpanel::ShipCpanel(void) : Gui::Fixed(640, 64) { g->Add(info_button); info_button->SetSelected(false); info_button->SetShortcut(SDLK_F3, KMOD_NONE); - info_button->AddState(0, "icons/cpan_f3_shipinfo.png"); + info_button->AddState(0, "icons/cpan_f3_shipinfo.png", "Ship information."); info_button->onClick.connect(sigc::mem_fun(this, &ShipCpanel::OnChangeInfoView)); Add(info_button, 66, 2); @@ -78,7 +78,7 @@ ShipCpanel::ShipCpanel(void) : Gui::Fixed(640, 64) { g->Add(comms_button); comms_button->SetSelected(false); comms_button->SetShortcut(SDLK_F4, KMOD_NONE); - comms_button->AddState(0, "icons/comms_f4.png"); + comms_button->AddState(0, "icons/comms_f4.png", "Comms."); comms_button->onClick.connect(sigc::mem_fun(this, &ShipCpanel::OnClickComms)); Add(comms_button, 98, 2); diff --git a/src/system_view.cpp b/src/system_view.cpp index 7c7ed7a..d172a90 100644 --- a/src/system_view.cpp +++ b/src/system_view.cpp @@ -13,10 +13,12 @@ SystemView::SystemView(void): View() { m_zoomInButton = new Gui::ImageButton("icons/zoom_in_f7.png"); m_zoomInButton->SetShortcut(SDLK_F6, KMOD_NONE); + m_zoomInButton->SetToolTip("Zoom in."); m_rightButtonBar->Add(m_zoomInButton, 34, 2); m_zoomOutButton = new Gui::ImageButton("icons/zoom_out_f8.png"); m_zoomOutButton->SetShortcut(SDLK_F7, KMOD_NONE); + m_zoomOutButton->SetToolTip("Zoom out."); m_rightButtonBar->Add(m_zoomOutButton, 66, 2); Gui::ImageButton* b = new Gui::ImageButton("icons/sysview_accel_r3.png", diff --git a/src/world_view.cpp b/src/world_view.cpp index 125fb0d..57b182a 100644 --- a/src/world_view.cpp +++ b/src/world_view.cpp @@ -27,25 +27,27 @@ WorldView::WorldView(void): View() { Gui::MultiStateImageButton* wheels_button = new Gui::MultiStateImageButton(); wheels_button->SetShortcut(SDLK_F6, KMOD_NONE); - wheels_button->AddState(0, "icons/wheels_up.png"); - wheels_button->AddState(1, "icons/wheels_down.png"); + wheels_button->AddState(0, "icons/wheels_up.png", "Wheels up."); + wheels_button->AddState(1, "icons/wheels_down.png", "Wheels down."); wheels_button->onClick.connect(sigc::mem_fun(this, &WorldView::OnChangeWheelsState)); m_rightButtonBar->Add(wheels_button, 34, 2); Gui::MultiStateImageButton* labels_button = new Gui::MultiStateImageButton(); labels_button->SetShortcut(SDLK_8, KMOD_NONE); - labels_button->AddState(1, "icons/labels_on.png"); - labels_button->AddState(0, "icons/labels_off.png"); + labels_button->AddState(1, "icons/labels_on.png", "Object labels on."); + labels_button->AddState(0, "icons/labels_off.png", "Object labels off."); labels_button->onClick.connect(sigc::mem_fun(this, &WorldView::OnChangeLabelsState)); m_rightButtonBar->Add(labels_button, 98, 2); m_hyperspaceButton = new Gui::ImageButton("icons/hyperspace_f8.png"); m_hyperspaceButton->SetShortcut(SDLK_F7, KMOD_NONE); + m_hyperspaceButton->SetToolTip("Hyperspace Jump."); m_hyperspaceButton->onClick.connect(sigc::mem_fun(this, &WorldView::OnClickHyperspace)); m_rightButtonBar->Add(m_hyperspaceButton, 66, 2); launchButton = new Gui::ImageButton("icons/blastoff.png"); launchButton->SetShortcut(SDLK_F5, KMOD_NONE); + launchButton->SetToolTip("Takeoff"); launchButton->onClick.connect(sigc::mem_fun(this, &WorldView::OnClickBlastoff)); m_rightButtonBar->Add(launchButton, 2, 2);