Browse Source

Tooltip implementation

rsredsq 10 years ago
parent
commit
b1795fb82f

+ 1 - 0
Resources/EditorData/AtomicEditor/editor/ui/maintoolbar.tb.txt

@@ -7,6 +7,7 @@ TBLayout: distribution: gravity, spacing: 4
 		@include definitions>menubutton
 		TBSkinImage: skin: PlayButton, id: skin_image
 		id maintoolbar_play
+		tooltip Play project
 	TBButton: toggle-mode: 1
 		@include definitions>menubutton
 		TBSkinImage: skin: 3DTranslateBitmap

+ 45 - 1
Source/Atomic/UI/UI.cpp

@@ -36,6 +36,8 @@
 #include <TurboBadger/tb_tab_container.h>
 #include <TurboBadger/tb_toggle_container.h>
 #include <TurboBadger/tb_scroll_container.h>
+#include <TurboBadger/tb_menu_window.h>
+#include <TurboBadger/tb_popup_window.h>
 #include <TurboBadger/image/tb_image_widget.h>
 
 void register_tbbf_font_renderer();
@@ -79,6 +81,8 @@ using namespace tb;
 #include "UISeparator.h"
 #include "UIDimmer.h"
 #include "UISelectDropdown.h"
+#include "UIMenuWindow.h"
+#include "UIPopupWindow.h"
 
 #include "SystemUI/SystemUI.h"
 #include "SystemUI/SystemUIEvents.h"
@@ -535,11 +539,52 @@ void UI::HandleUpdate(StringHash eventType, VariantMap& eventData)
         exitRequested_ = false;
         return;
     }
+    
+    mouseStayedTime += eventData[Update::P_TIMESTEP].GetFloat();
+
+    if (mouseStayedTime >= 0.5f)
+    {
+        UIWidget* hoveredWidget = GetHoveredWidget();
+        if (hoveredWidget && !tooltip_ && (hoveredWidget->GetShorten() || hoveredWidget->GetTooltip().Length() > 0))
+        {
+            tooltip_ = new UIPopupWindow(context_, hoveredWidget, "tooltip");
+            UILayout* tooltipLayout = new UILayout(context_, UI_AXIS_Y, true);
+            if (hoveredWidget->GetShorten())
+            {
+                UIEditField* fullTextField = new UIEditField(context_, true);
+                fullTextField->SetAdaptToContentSize(true);
+                fullTextField->SetText(hoveredWidget->GetText());
+                fullTextField->SetReadOnly(true);
+                tooltipLayout->AddChild(fullTextField);
+            }
+            if (hoveredWidget->GetTooltip().Length() > 0)
+            {
+                UIEditField* tooltipTextField = new UIEditField(context_, true);
+                tooltipTextField->SetAdaptToContentSize(true);
+                tooltipTextField->SetText(hoveredWidget->GetTooltip());
+                tooltipTextField->SetReadOnly(true);
+                tooltipLayout->AddChild(tooltipTextField);
+            }
+            Input* input = GetSubsystem<Input>();
+            IntVector2 mousePosition = input->GetMousePosition();
+            tooltip_->AddChild(tooltipLayout);
+            tooltip_->Show(mousePosition.x_ + 1, mousePosition.y_ + 1);
+        }
+    }
+    else 
+    {
+        if (tooltip_) tooltip_->Close();
+    }
 
     SendEvent(E_UIUPDATE);
     TBMessageHandler::ProcessMessages();
 }
 
+UIWidget* UI::GetHoveredWidget()
+{
+    return WrapWidget(TBWidget::hovered_widget);
+}
+
 bool UI::IsWidgetWrapped(tb::TBWidget* widget)
 {
     return widgetWrap_.Contains(widget);
@@ -640,7 +685,6 @@ UIWidget* UI::WrapWidget(tb::TBWidget* widget)
         return sep;
     }
 
-
     if (widget->IsOfType<TBContainer>())
     {
         UIContainer* container = new UIContainer(context_, false);

+ 7 - 0
Source/Atomic/UI/UI.h

@@ -33,6 +33,7 @@ namespace Atomic
 class VertexBuffer;
 class UIRenderer;
 class UIWidget;
+class UIPopupWindow;
 
 namespace SystemUI
 {
@@ -111,6 +112,8 @@ public:
 
     void SetBlockChangedEvents(bool blocked = true);
 
+    UIWidget* GetHoveredWidget();
+
 private:
 
     static WeakPtr<Context> uiContext_;
@@ -144,6 +147,8 @@ private:
     HashMap<tb::TBWidget*, SharedPtr<UIWidget> > widgetWrap_;
     HashMap<unsigned, String> tbidToString_;
 
+    WeakPtr<UIPopupWindow> tooltip_;
+
     int changedEventsBlocked_;
 
     bool inputDisabled_;
@@ -152,6 +157,8 @@ private:
     bool skinLoaded_;
     bool consoleVisible_;
     bool exitRequested_;
+    
+    float mouseStayedTime;
 
     // Events
     void HandleScreenMode(StringHash eventType, VariantMap& eventData);

+ 1 - 0
Source/Atomic/UI/UIInput.cpp

@@ -139,6 +139,7 @@ void UI::HandleMouseMove(StringHash eventType, VariantMap& eventData)
 
     rootWidget_->InvokePointerMove(px, py, tb::TB_MODIFIER_NONE, false);
 
+    mouseStayedTime = 0;
 }
 
 

+ 0 - 7
Source/Atomic/UI/UILayout.h

@@ -29,13 +29,6 @@
 namespace Atomic
 {
 
-enum UI_AXIS {
-    ///< Horizontal layout
-    UI_AXIS_X = tb::AXIS_X,
-    ///< Vertical layout
-    UI_AXIS_Y = tb::AXIS_Y,
-};
-
 /// Specifies which height widgets in a AXIS_X layout should have,
 ///	or which width widgets in a AXIS_Y layout should have.
 ///	No matter what, it will still prioritize minimum and maximum for each widget.

+ 1 - 1
Source/Atomic/UI/UIMenuWindow.h

@@ -36,7 +36,7 @@ class UIMenuWindow : public UIWidget
 
 public:
 
-    UIMenuWindow(Context* context, UIWidget* target, const String& id);
+    UIMenuWindow(Context* context, UIWidget* target, const String& id = String::EMPTY);
     virtual ~UIMenuWindow();
 
     void Show(UISelectItemSource* source, int x = -1, int y = -1);

+ 73 - 0
Source/Atomic/UI/UIPopupWindow.cpp

@@ -0,0 +1,73 @@
+//
+// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include <TurboBadger/tb_widgets.h>
+#include <TurboBadger/tb_popup_window.h>
+
+#include "UI.h"
+#include "UIEvents.h"
+#include "UIWidget.h"
+#include "UIPopupWindow.h"
+
+using namespace tb;
+
+namespace Atomic
+{
+
+    UIPopupWindow::UIPopupWindow(Context* context, UIWidget* target, const String& id) : UIWidget(context, false)
+    {
+        widget_ = new TBPopupWindow(target->GetInternalWidget());
+        widget_->SetID(TBIDC(id.CString()));
+        widget_->SetDelegate(this);
+        GetSubsystem<UI>()->WrapWidget(this, widget_);
+    }
+
+    UIPopupWindow::~UIPopupWindow()
+    {
+    }
+
+    void UIPopupWindow::Show(int x, int y)
+    {
+        if (x != -1 && y != -1)
+        {
+            ((TBPopupWindow*)widget_)->Show(TBPopupAlignment(TBPoint(x, y)));
+        }
+        else
+        {
+            ((TBPopupWindow*)widget_)->Show(TBPopupAlignment());
+        }
+    }
+
+    bool UIPopupWindow::OnEvent(const tb::TBWidgetEvent &ev)
+    {
+        return false;
+    }
+
+    void UIPopupWindow::Close()
+    {
+        if (!widget_)
+            return;
+
+        ((TBPopupWindow*)widget_)->Close();
+    }
+
+}

+ 51 - 0
Source/Atomic/UI/UIPopupWindow.h

@@ -0,0 +1,51 @@
+//
+// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include "UIWidget.h"
+
+namespace Atomic
+{
+
+class UIPopupWindow: public UIWidget
+{
+    OBJECT(UIPopupWindow)
+
+    public:
+
+    UIPopupWindow(Context* context, UIWidget* target, const String& id = String::EMPTY);
+    virtual ~UIPopupWindow();
+
+    void Show(int x = -1, int y = -1);
+
+    void Close();
+
+protected:
+
+    virtual bool OnEvent(const tb::TBWidgetEvent &ev);
+
+private:
+
+};
+
+}

+ 47 - 0
Source/Atomic/UI/UIWidget.cpp

@@ -273,6 +273,14 @@ void UIWidget::SetGravity(UI_GRAVITY gravity)
 
 }
 
+void UIWidget::SetAxis(UI_AXIS axis)
+{
+    if (!widget_)
+        return;
+
+    widget_->SetAxis((AXIS) axis);
+}
+
 bool UIWidget::IsAncestorOf(UIWidget* widget)
 {
     if (!widget_ || !widget || !widget->widget_)
@@ -793,6 +801,13 @@ void UIWidget::SetCapturing(bool capturing)
     widget_->SetCapturing(capturing);
 }
 
+bool UIWidget::GetCapturing()
+{
+    if (!widget_)
+        return false;
+
+    widget_->GetCapturing();
+}
 
 void UIWidget::InvalidateLayout()
 {
@@ -810,5 +825,37 @@ void UIWidget::InvokeShortcut(const String& shortcut)
     widget_->OnEvent(ev);
 }
 
+bool UIWidget::GetShorten()
+{
+    if (!widget_)
+        return false;
+
+    return widget_->GetShorten();
+}
+
+void UIWidget::SetShorten(bool shorten)
+{
+    if (!widget_)
+        return;
+
+    widget_->SetShorten(shorten);
+}
+
+String UIWidget::GetTooltip()
+{
+    if (!widget_)
+        return "";
+
+    return widget_->GetTooltip().CStr();
+}
+
+void UIWidget::SetTooltip(const String& tooltip)
+{
+    if (!widget_)
+        return;
+
+    widget_->SetTooltip(tooltip.CString());
+}
+
 
 }

+ 18 - 2
Source/Atomic/UI/UIWidget.h

@@ -143,6 +143,13 @@ enum UI_WIDGET_STATE {
 
 };
 
+enum UI_AXIS {
+    ///< Horizontal layout
+    UI_AXIS_X = tb::AXIS_X,
+    ///< Vertical layout
+    UI_AXIS_Y = tb::AXIS_Y,
+};
+
 
 class UIView;
 class UILayoutParams;
@@ -189,6 +196,7 @@ class UIWidget : public Object, public tb::TBWidgetDelegate
 
     void Center();
     void SetGravity(UI_GRAVITY gravity);
+    void SetAxis(UI_AXIS axis);
 
     void SetValue(double value);
     virtual double GetValue();
@@ -208,7 +216,7 @@ class UIWidget : public Object, public tb::TBWidgetDelegate
     UI_WIDGET_VISIBILITY GetVisibility();
 
     void SetStateRaw(UI_WIDGET_STATE state);
-   UI_WIDGET_STATE GetStateRaw();
+    UI_WIDGET_STATE GetStateRaw();
 
     void Invalidate();
     void Die();
@@ -250,10 +258,18 @@ class UIWidget : public Object, public tb::TBWidgetDelegate
     bool GetCaptured();
 
     void SetCapturing(bool capturing);
-    bool GetCapturing() { return widget_->GetCapturing(); }
+    bool GetCapturing();
 
     void InvokeShortcut(const String& shortcut);
 
+    bool GetShorten();
+
+    void SetShorten(bool shorten);
+
+    String GetTooltip();
+
+    void SetTooltip(const String& text);
+
 protected:
 
     void ConvertEvent(UIWidget* handler, UIWidget* target, const tb::TBWidgetEvent &ev, VariantMap& data);

+ 1 - 0
Source/ThirdParty/TurboBadger/tb_widgets.cpp

@@ -75,6 +75,7 @@ TBWidget::TBWidget()
 	, m_packed_init(0)
     , needCapturing_(true)
     , captured_(false)
+    , shorten_(false)
 {
 #ifdef TB_RUNTIME_DEBUG_INFO
 	last_measure_time = 0;

+ 10 - 0
Source/ThirdParty/TurboBadger/tb_widgets.h

@@ -999,6 +999,14 @@ public:
 
     TBWidget *GetWidgetByTouchId(unsigned touchId);
 
+    bool GetShorten() { return shorten_; }
+
+    void SetShorten(bool shorten) { shorten_ = shorten; }
+
+    TBStr GetTooltip() { TBStr str; str.Set(tooltip_); return str; }
+
+    bool SetTooltip(const char *tooltip) { return tooltip_.Set(tooltip); }
+
 private:
 	friend class TBWidgetListener;	///< It does iteration of m_listeners for us.
 	TBWidget *m_parent;				///< The parent of this widget
@@ -1024,6 +1032,8 @@ private:
     bool needCapturing_; //if ours widget need capturing
     bool captured_; //if ours widget is currently captured
     unsigned touchId_;
+    bool shorten_;
+    TBStr tooltip_;
 	union {
 		struct {
 			uint16 is_group_root : 1;

+ 7 - 1
Source/ThirdParty/TurboBadger/tb_widgets_common.cpp

@@ -30,6 +30,7 @@ int TBWidgetString::GetHeight(TBWidget *widget)
 
 void TBWidgetString::Paint(TBWidget *widget, const TBRect &rect, const TBColor &color)
 {
+    // TODO: store calculated string width to avoid recalculation each frame
 	TBFontFace *font = widget->GetFont();
 	int string_w = GetWidth(widget);
 
@@ -40,8 +41,11 @@ void TBWidgetString::Paint(TBWidget *widget, const TBRect &rect, const TBColor &
 		x += MAX(0, (rect.w - string_w) / 2);
 	int y = rect.y + (rect.h - GetHeight(widget)) / 2;
 
-	if (string_w <= rect.w)
+    if (string_w <= rect.w)
+    {
+        widget->SetShorten(false);
 		font->DrawString(x, y, color, m_text);
+    }
 	else
 	{
 		// There's not enough room for the entire string
@@ -51,6 +55,8 @@ void TBWidgetString::Paint(TBWidget *widget, const TBRect &rect, const TBColor &
 		// Some fonts seem to render ellipsis a lot uglier than three dots.
 		const char *end = "...";
 
+        widget->SetShorten(true);
+
 		int endw = font->GetStringWidth(end);
 		int startw = 0;
 		int startlen = 0;

+ 3 - 0
Source/ThirdParty/TurboBadger/tb_widgets_reader.cpp

@@ -146,6 +146,9 @@ void TBWidget::OnInflate(const INFLATE_INFO &info)
 				dc->GetPxFromValue(val.GetArray()->GetValue(3), 0)));
 		}
 	}
+
+    if (const char *tooltip = info.node->GetValueString("tooltip", nullptr))
+        SetTooltip(tooltip);
 }
 
 TB_WIDGET_FACTORY(TBButton, TBValue::TYPE_NULL, WIDGET_Z_BOTTOM) {}