]> git.tdb.fi Git - libs/gltk.git/commitdiff
Add Text class with multiline support
authorMikko Rasa <tdb@tdb.fi>
Sun, 20 Sep 2009 16:27:08 +0000 (16:27 +0000)
committerMikko Rasa <tdb@tdb.fi>
Sun, 20 Sep 2009 16:27:08 +0000 (16:27 +0000)
Use said class in widgets containing text
Support for displaying tooltips in the Root widget

16 files changed:
source/button.cpp
source/button.h
source/dropdown.cpp
source/entry.cpp
source/entry.h
source/label.cpp
source/label.h
source/panel.h
source/root.cpp
source/root.h
source/text.cpp [new file with mode: 0644]
source/text.h [new file with mode: 0644]
source/toggle.cpp
source/toggle.h
source/widget.cpp
source/widget.h

index aecfd32fe0d004a56c8201d0da5f33f32599c636..c9bca9adcdeebb25f0478f1faee0804e8fa77d46 100644 (file)
@@ -14,11 +14,12 @@ namespace GLtk {
 
 Button::Button(const Resources &r, const std::string &t):
        Widget(r),
+       text(style),
        icon(0),
        pressed(false)
 {
-       set_text(t);
        update_style();
+       set_text(t);
 }
 
 void Button::set_text(const std::string &t)
@@ -66,7 +67,8 @@ void Button::pointer_motion(int x, int y)
 void Button::render_special(const Part &part) const
 {
        if(part.get_name()=="text")
-               render_text(part, text);
+               //render_text(part, text);
+               text.render(part, geom);
        if(part.get_name()=="icon" && icon)
        {
                Geometry rgeom;
@@ -95,12 +97,12 @@ void Button::render_special(const Part &part) const
 Button::Loader::Loader(Button &btn):
        Widget::Loader(btn)
 {
-       add("text", &Button::text);
+       add("text", &Loader::text);
 }
 
-Button &Button::Loader::get_object() const
+void Button::Loader::text(const std::string &t)
 {
-       return static_cast<Button &>(wdg);
+       static_cast<Button &>(wdg).text=t;
 }
 
 } // namespace GLtk
index d13a4c094c22deade08f6fcbe9e0fcf4b656857a..31d87e1f0ba806f5dfc100c1c6bde41b20cb3a6c 100644 (file)
@@ -10,6 +10,7 @@ Distributed under the LGPL
 
 #include <sigc++/sigc++.h>
 #include <msp/gl/texture2d.h>
+#include "text.h"
 #include "widget.h"
 
 namespace Msp {
@@ -26,11 +27,12 @@ public:
        {
        public:
                Loader(Button &);
-               Button &get_object() const;
+       private:
+               void text(const std::string &);
        };
 
 private:
-       std::string text;
+       Text text;
        const GL::Texture2D *icon;
        bool pressed;
 
index cbd7ee437111bc3726b1c0ba988471638142140b..5e19ed9ca8534a1aeb27bf8aa8b72a63e16ab4a3 100644 (file)
@@ -11,6 +11,7 @@ Distributed under the LGPL
 #include "panel.h"
 #include "part.h"
 #include "style.h"
+#include "text.h"
 
 using namespace std;
 
@@ -98,7 +99,8 @@ void Dropdown::render_special(const Part &part) const
        if(part.get_name()=="text")
        {
                if(list.get_selected_index()>=0)
-                       render_text(part, list.get_selected());
+                       Text(style, list.get_selected()).render(part, geom);
+                       //render_text(part, list.get_selected());
        }
        else if(part.get_name()=="list" && dropped)
                list.render();
index 523fea5cc945f8a6bf6b321990c74ff449ee63d1..f5037215592e1a45143ab8b305cf563007c7dbe0 100644 (file)
@@ -16,17 +16,16 @@ Distributed under the LGPL
 
 using namespace std;
 
-#include <iostream>
-
 namespace Msp {
 namespace GLtk {
 
 Entry::Entry(const Resources &r, const string &t):
        Widget(r),
-       text(t),
-       edit_pos(text.size())
+       text(style),
+       edit_pos(0)
 {
        update_style();
+       set_text(t);
 }
 
 void Entry::set_text(const string &t)
@@ -64,7 +63,7 @@ void Entry::key_press(unsigned key, unsigned, wchar_t ch)
 void Entry::render_special(const Part &part) const
 {
        if(part.get_name()=="text")
-               render_text(part, text);
+               text.render(part, geom);
        else if(part.get_name()=="cursor")
        {
                if(!part.get_graphic(state))
@@ -74,8 +73,8 @@ void Entry::render_special(const Part &part) const
                const float font_size=font->get_default_size();
 
                Geometry rgeom=part.get_geometry();
-               rgeom.x=static_cast<unsigned>(font->get_string_width(text.substr(0, edit_pos))*font_size);
-               rgeom.w=static_cast<unsigned>(font->get_string_width(text)*font_size);
+               rgeom.x=static_cast<unsigned>(font->get_string_width(text.get().substr(0, edit_pos))*font_size);
+               rgeom.w=static_cast<unsigned>(font->get_string_width(text.get())*font_size);
                part.get_alignment().apply(rgeom, geom, part.get_margin());
 
                GL::push_matrix();
index 29fec417ec966bb0931fbc53ea5627877954c409..b8bae562c7fd2b53b7322cc6c09f6baaa3b2f3d9 100644 (file)
@@ -8,6 +8,7 @@ Distributed under the LGPL
 #ifndef MSP_GLTK_ENTRY_H_
 #define MSP_GLTK_ENTRY_H_
 
+#include "text.h"
 #include "widget.h"
 
 namespace Msp {
@@ -31,7 +32,7 @@ public:
        };
 
 private:
-       std::string text;
+       Text text;
        unsigned edit_pos;
 
 public:
@@ -40,7 +41,7 @@ public:
        Entry(const Resources &, const std::string & =std::string());
 
        void set_text(const std::string &);
-       const std::string &get_text() const { return text; }
+       const std::string &get_text() const { return text.get(); }
 
        virtual void key_press(unsigned, unsigned, wchar_t);
 private:
index 0e0134d73766a4cb5f05830386d772790d6dca7d..ae821a81f0f6330dc42ac6c3f15ce18ac85d21d9 100644 (file)
@@ -7,18 +7,40 @@ Distributed under the LGPL
 
 #include "label.h"
 #include "part.h"
+#include "style.h"
+
+using namespace std;
 
 namespace Msp {
 namespace GLtk {
 
-Label::Label(const Resources &r, const std::string &t):
-       Widget(r)
+Label::Label(const Resources &r, const string &t):
+       Widget(r),
+       text(style)
 {
-       set_text(t);
        update_style();
+       set_text(t);
+}
+
+void Label::autosize()
+{
+       const list<Part> &parts=style->get_parts();
+       const Part *text_part=0;
+       for(list<Part>::const_iterator i=parts.begin(); (!text_part && i!=parts.end()); ++i)
+               if(i->get_name()=="text")
+                       text_part=&*i;
+
+       geom.h=text.get_height();
+       geom.w=text.get_width();
+       if(text_part)
+       {
+               const Sides &margin=text_part->get_margin();
+               geom.w+=margin.left+margin.right;
+               geom.h+=margin.top+margin.bottom;
+       }
 }
 
-void Label::set_text(const std::string &t)
+void Label::set_text(const string &t)
 {
        text=t;
 }
@@ -26,19 +48,19 @@ void Label::set_text(const std::string &t)
 void Label::render_special(const Part &part) const
 {
        if(part.get_name()=="text")
-               render_text(part, text);
+               text.render(part, geom);
 }
 
 
 Label::Loader::Loader(Label &l):
        Widget::Loader(l)
 {
-       add("text", &Label::text);
+       add("text", &Loader::text);
 }
 
-Label &Label::Loader::get_object()
+void Label::Loader::text(const string &t)
 {
-       return static_cast<Label &>(wdg);
+       static_cast<Label &>(wdg).text=t;
 }
 
 } // namespace GLtk
index baa0ddc7123f5381e0208976b38b2d09b0375838..f492006037939cae1631c9fec21798421a750555 100644 (file)
@@ -8,6 +8,7 @@ Distributed under the LGPL
 #ifndef MSP_GLTK_LABEL_H_
 #define MSP_GLTK_LABEL_H_
 
+#include "text.h"
 #include "widget.h"
 
 namespace Msp {
@@ -23,14 +24,17 @@ public:
        {
        public:
                Loader(Label &);
-               Label &get_object();
+       private:
+               void text(const std::string &);
        };
 
 private:
-       std::string text;
+       Text text;
 
 public:
        Label(const Resources &, const std::string & =std::string());
+
+       virtual void autosize();
        void set_text(const std::string &);
 
 private:
index b431a854cdcc284ad751fa45e926ea082e274962..8a5d1286ab97024a3abf102643a2b344fd2eb655 100644 (file)
@@ -35,7 +35,7 @@ public:
                void panel(const std::string &);
        };
 
-private:
+protected:
        struct Child: public Container::Child
        {
                Child(Panel &, Widget *);
@@ -66,7 +66,7 @@ public:
        virtual void key_press(unsigned, unsigned, wchar_t);
        virtual void key_release(unsigned, unsigned);
        virtual void focus_out();
-private:
+protected:
        virtual const char *get_class() const { return "panel"; }
        virtual void render_special(const Part &) const;
        virtual Child *create_child(Widget *);
index 6bc5793df6e0c4b5140660a9f96f8d3095e58c5f..0cd7e0f35d20ddb40a713e3d87beee7253bf0433 100644 (file)
@@ -6,6 +6,10 @@ Distributed under the LGPL
 */
 
 #include <msp/input/keys.h>
+#include <msp/time/units.h>
+#include <msp/time/utils.h>
+#include "label.h"
+#include "style.h"
 #include "root.h"
 
 namespace Msp {
@@ -14,7 +18,9 @@ namespace GLtk {
 Root::Root(const Resources &r, Graphics::Window &w):
        Widget(r),
        Panel(r),
-       window(w)
+       window(w),
+       lbl_tooltip(0),
+       tooltip_target(0)
 {
        set_geometry(Geometry(0, 0, window.get_width(), window.get_height()));
 
@@ -27,6 +33,44 @@ Root::Root(const Resources &r, Graphics::Window &w):
        window.signal_key_release.connect(sigc::mem_fun(this, &Root::key_release_event));
 }
 
+void Root::tick()
+{
+       if(tooltip_timeout && Time::now()>tooltip_timeout)
+       {
+               if(Widget *wdg=get_descendant_at(pointer_x, pointer_y))
+               {
+                       const std::string &tip=wdg->get_tooltip();
+                       if(!tip.empty())
+                       {
+                               if(!lbl_tooltip)
+                               {
+                                       lbl_tooltip=new Label(res);
+                                       add(*lbl_tooltip);
+                                       lbl_tooltip->set_style("tooltip");
+                               }
+
+                               lbl_tooltip->set_text(tip);
+                               lbl_tooltip->autosize();
+                               const Geometry &tip_geom=lbl_tooltip->get_geometry();
+                               unsigned x=pointer_x+10;
+                               unsigned y=pointer_y-10-lbl_tooltip->get_geometry().h;
+                               if(x+tip_geom.w>geom.w)
+                               {
+                                       if(pointer_x>static_cast<int>(tip_geom.w+2))
+                                               x=pointer_x-2-tip_geom.w;
+                                       else
+                                               x=geom.w-tip_geom.w;
+                               }
+                               lbl_tooltip->set_position(x, y);
+                               raise(*lbl_tooltip);
+                               lbl_tooltip->set_visible(true);
+                               tooltip_timeout=Time::TimeStamp();
+                               tooltip_target=wdg;
+                       }
+               }
+       }
+}
+
 void Root::button_press_event(int x, int y, unsigned btn, unsigned)
 {
        if(visible)
@@ -51,6 +95,23 @@ void Root::pointer_motion_event(int x, int y)
        {
                translate_coords(x, y);
                pointer_motion(x, y);
+
+               if(!tooltip_target)
+               {
+                       if(pointer_focus)
+                       {
+                               pointer_x=x;
+                               pointer_y=y;
+                               tooltip_timeout=Time::now()+700*Time::msec;
+                       }
+                       else
+                               tooltip_timeout=Time::TimeStamp();
+               }
+               else if(get_descendant_at(x, y)!=tooltip_target)
+               {
+                       lbl_tooltip->set_visible(false);
+                       tooltip_target=0;
+               }
        }
 }
 
index 36efba794c064c4fd854b31fc21654716e196eb4..7cbd82744bb0d0426e6ff07108dfdbaded67896d 100644 (file)
@@ -10,11 +10,14 @@ Distributed under the LGPL
 
 #include <sigc++/trackable.h>
 #include <msp/gbase/window.h>
+#include <msp/time/timestamp.h>
 #include "panel.h"
 
 namespace Msp {
 namespace GLtk {
 
+class Label;
+
 /**
 A Root is a special type of Panel that covers and entire Window and accepts
 input from it.  When created, a Root widget will take its size from the window
@@ -25,9 +28,15 @@ class Root: public Panel, public sigc::trackable
 {
 private:
        Graphics::Window &window;
+       Label *lbl_tooltip;
+       int pointer_x;
+       int pointer_y;
+       Msp::Time::TimeStamp tooltip_timeout;
+       Widget *tooltip_target;
 
 public:
        Root(const Resources &, Graphics::Window &);
+       void tick();
 private:
        virtual const char *get_class() const { return "root"; }
        void button_press_event(int, int, unsigned, unsigned);
diff --git a/source/text.cpp b/source/text.cpp
new file mode 100644 (file)
index 0000000..5f4095e
--- /dev/null
@@ -0,0 +1,112 @@
+#include <msp/gl/immediate.h>
+#include <msp/gl/matrix.h>
+#include "style.h"
+#include "text.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GLtk {
+
+Text::Text(const Style *const &s):
+       style(s)
+{ }
+
+Text::Text(const Style *const &s, const string &t):
+       style(s)
+{
+       set(t);
+}
+
+unsigned Text::get_width() const
+{
+       unsigned width=0;
+       for(vector<Line>::const_iterator i=lines.begin(); i!=lines.end(); ++i)
+               width=max(width, i->width);
+       return width;
+}
+
+unsigned Text::get_height() const
+{
+       const GL::Font *font=style->get_font();
+       float font_size=font->get_default_size();
+       unsigned line_height=static_cast<unsigned>((font->get_ascent()-font->get_descent())*font_size);
+       unsigned line_spacing=line_height*6/5;
+       return line_height+(lines.size()-1)*line_spacing;
+}
+
+void Text::set(const string &t)
+{
+       text=t;
+       lines.clear();
+       float font_size=style->get_font()->get_default_size();
+       unsigned start=0;
+       while(1)
+       {
+               unsigned newline=text.find('\n', start);
+
+               Line line;
+               line.start=start;
+               line.length=(newline==string::npos ? text.size() : newline)-start;
+               line.width=static_cast<unsigned>(style->get_font()->get_string_width(text.substr(line.start, line.length))*font_size);
+               lines.push_back(line);
+
+               if(newline==string::npos)
+                       break;
+               start=newline+1;
+       }
+}
+
+void Text::erase(unsigned pos, unsigned len)
+{
+       text.erase(pos, len);
+}
+
+void Text::insert(unsigned pos, const string &s)
+{
+       text.insert(pos, s);
+}
+
+void Text::render(const Part &part, const Geometry &geom) const
+{
+       if(lines.empty())
+               return;
+
+       const GL::Font *font=style->get_font();
+       float font_size=font->get_default_size();
+       unsigned line_height=static_cast<unsigned>((font->get_ascent()-font->get_descent())*font_size);
+       unsigned line_spacing=font_size*6/5;
+       unsigned height=line_height+(lines.size()-1)*line_spacing;
+       int y_offset=static_cast<int>(-font->get_descent()*font_size);
+
+       const GL::Color &color=style->get_font_color();
+       GL::Immediate imm((GL::COLOR4_UBYTE, GL::TEXCOORD2, GL::VERTEX2));
+       imm.color(color.r, color.g, color.b);
+       for(unsigned i=0; i<lines.size(); ++i)
+       {
+               const Line &line=lines[i];
+
+               Geometry rgeom;
+               rgeom.w=line.width;
+               rgeom.h=height;
+               rgeom.y=(lines.size()-1-i)*line_spacing+y_offset;
+               part.get_alignment().apply(rgeom, geom, part.get_margin());
+
+               GL::push_matrix();
+               GL::translate(rgeom.x, rgeom.y, 0);
+               GL::scale_uniform(font_size);
+
+               font->draw_string(text.substr(line.start, line.length), imm);
+
+               GL::pop_matrix();
+       }
+}
+
+Text &Text::operator=(const string &t)
+{
+       set(t);
+       return *this;
+}
+
+} // namespace GLtk
+} // namespace Msp
diff --git a/source/text.h b/source/text.h
new file mode 100644 (file)
index 0000000..46bd18f
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef MSP_GLTK_TEXT_H_
+#define MSP_GLTK_TEXT_H_
+
+#include <string>
+#include <vector>
+
+namespace Msp {
+namespace GLtk {
+
+class Geometry;
+class Part;
+class Style;
+
+/**
+Stores and renders text.  Supports multiline text.
+*/
+class Text
+{
+private:
+       struct Line
+       {
+               unsigned start;
+               unsigned length;
+               unsigned width;
+       };
+
+       const Style *const &style;
+       std::string text;
+       std::vector<Line> lines;
+
+public:
+       Text(const Style *const &);
+       Text(const Style *const &, const std::string &);
+
+       unsigned get_width() const;
+       unsigned get_height() const;
+
+       void set(const std::string &);
+       void erase(unsigned, unsigned);
+       void insert(unsigned, const std::string &);
+       const std::string &get() const { return text; }
+       unsigned size() const { return text.size(); }
+
+       void render(const Part &, const Geometry &) const;
+
+       Text &operator=(const std::string &);
+       //operator const std::string &() const { return text; }
+};
+
+} // namespace GLtk
+} // namespace Msp
+
+#endif
index 9fbd098ae0783aab8a4e724e1975b85864bc8b48..550d97a27584fbcba9a1e6699d4e4a23d2fffb6f 100644 (file)
@@ -16,12 +16,13 @@ namespace GLtk {
 
 Toggle::Toggle(const Resources &r, const string &t):
        Widget(r),
-       text(t),
+       text(style),
        pressed(false),
        value(false),
        exclusive(false)
 {
        update_style();
+       set_text(t);
 }
 
 void Toggle::set_text(const string &t)
@@ -72,7 +73,7 @@ void Toggle::button_release(int x, int y, unsigned btn)
 void Toggle::render_special(const Part &part) const
 {
        if(part.get_name()=="text")
-               render_text(part, text);
+               text.render(part, geom);
 }
 
 void Toggle::exclude_siblings()
@@ -89,7 +90,7 @@ Toggle::Loader::Loader(Toggle &t):
        Widget::Loader(t)
 {
        add("exclusive", &Toggle::exclusive);
-       add("text",      &Toggle::text);
+       add("text",      &Loader::text);
        add("value",     &Toggle::value);
 }
 
@@ -107,5 +108,10 @@ void Toggle::Loader::finish()
                tgl.state&=~ACTIVE;
 }
 
+void Toggle::Loader::text(const string &t)
+{
+       static_cast<Toggle &>(wdg).text=t;
+}
+
 } // namespace GLtk
 } // namespace Msp
index 794636ec1e4617b8a0064adb46c8bdb902bdbe11..f9a32fe192971c50fae7590f16e1186b6ebbad74 100644 (file)
@@ -9,6 +9,7 @@ Distributed under the LGPL
 #define MSP_GLTK_TOGGLE_H_
 
 #include <sigc++/signal.h>
+#include "text.h"
 #include "widget.h"
 
 namespace Msp {
@@ -27,10 +28,11 @@ public:
                Toggle &get_object() const;
        private:
                virtual void finish();
+               void text(const std::string &);
        };
 
 private:
-       std::string text;
+       Text text;
        bool pressed;
        bool value;
        bool exclusive;
index 84d042573ec18aff63230eca34cada3e150dbab3..7137260a297165442e0554011b0334ef0149a6d1 100644 (file)
@@ -58,6 +58,11 @@ void Widget::set_style(const string &s)
        update_style();
 }
 
+void Widget::set_tooltip(const string &t)
+{
+       tooltip = t;
+}
+
 void Widget::set_visible(bool v)
 {
        if(v==visible)
@@ -88,14 +93,18 @@ void Widget::render() const
        for(PartSeq::const_iterator i=style->get_parts().begin(); i!=style->get_parts().end(); ++i)
        {
                if(i->get_name().empty())
-                       render_graphic(*i);
+               {
+                       GL::PushMatrix push_;
+                       i->render(geom, state);
+               }
+                       //render_graphic(*i);
                else
                        render_special(*i);
        }
        GL::pop_matrix();
 }
 
-void Widget::render_graphic(const Part &part) const
+/*void Widget::render_graphic(const Part &part) const
 {
        GL::push_matrix();
        part.render(geom, state);
@@ -123,7 +132,7 @@ void Widget::render_text(const Part &part, const string &text) const
        font->draw_string(text, imm);
 
        GL::pop_matrix();
-}
+}*/
 
 void Widget::pointer_enter()
 {
index 6774cbec10e66991a438836e38bebd692c8f77ff..ce88c97d4e65921b6c044bdea79f79a12dd3c11c 100644 (file)
@@ -55,13 +55,17 @@ protected:
        State state;
        bool visible;
        Container *parent;
+       std::string tooltip;
 
        Widget(const Resources &);
 public:
        virtual ~Widget();
+
        void set_position(int, int);
        void set_size(unsigned, unsigned);
+       virtual void autosize() { }
        void set_geometry(const Geometry &);
+       const Geometry &get_geometry() const { return geom; }
 
        /**
        Sets the widget style.  The final style name is constructed by concatenating
@@ -70,16 +74,17 @@ public:
        void set_style(const std::string &);
        const Style &get_style() const { return *style; }
 
-       void set_visible(bool);
-       void set_focus();
+       void set_tooltip(const std::string &);
+       const std::string &get_tooltip() const { return tooltip; }
 
-       const Geometry &get_geometry() const { return geom; }
+       void set_visible(bool);
        bool is_visible() const { return visible; }
+       void set_focus();
 
        void render() const;
 protected:
-       void render_graphic(const Part &) const;
-       void render_text(const Part &, const std::string &) const;
+       /*void render_graphic(const Part &) const;
+       void render_text(const Part &, const std::string &) const;*/
        virtual void render_special(const Part &) const { }
 
 public: