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)
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;
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
#include <sigc++/sigc++.h>
#include <msp/gl/texture2d.h>
+#include "text.h"
#include "widget.h"
namespace Msp {
{
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;
#include "panel.h"
#include "part.h"
#include "style.h"
+#include "text.h"
using namespace std;
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();
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)
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))
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();
#ifndef MSP_GLTK_ENTRY_H_
#define MSP_GLTK_ENTRY_H_
+#include "text.h"
#include "widget.h"
namespace Msp {
};
private:
- std::string text;
+ Text text;
unsigned edit_pos;
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:
#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;
}
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
#ifndef MSP_GLTK_LABEL_H_
#define MSP_GLTK_LABEL_H_
+#include "text.h"
#include "widget.h"
namespace Msp {
{
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:
void panel(const std::string &);
};
-private:
+protected:
struct Child: public Container::Child
{
Child(Panel &, Widget *);
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 *);
*/
#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 {
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()));
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)
{
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;
+ }
}
}
#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
{
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);
--- /dev/null
+#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
--- /dev/null
+#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
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)
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()
Widget::Loader(t)
{
add("exclusive", &Toggle::exclusive);
- add("text", &Toggle::text);
+ add("text", &Loader::text);
add("value", &Toggle::value);
}
tgl.state&=~ACTIVE;
}
+void Toggle::Loader::text(const string &t)
+{
+ static_cast<Toggle &>(wdg).text=t;
+}
+
} // namespace GLtk
} // namespace Msp
#define MSP_GLTK_TOGGLE_H_
#include <sigc++/signal.h>
+#include "text.h"
#include "widget.h"
namespace Msp {
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;
update_style();
}
+void Widget::set_tooltip(const string &t)
+{
+ tooltip = t;
+}
+
void Widget::set_visible(bool v)
{
if(v==visible)
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);
font->draw_string(text, imm);
GL::pop_matrix();
-}
+}*/
void Widget::pointer_enter()
{
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
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: