From: Mikko Rasa Date: Tue, 12 Jun 2007 18:54:27 +0000 (+0000) Subject: Initial revision X-Git-Tag: 0.9~37 X-Git-Url: http://git.tdb.fi/?p=libs%2Fgltk.git;a=commitdiff_plain;h=c1f038acb91eb3bfaa34dfd4729d19ed3f871a42 Initial revision --- diff --git a/Build b/Build new file mode 100644 index 0000000..45a22cb --- /dev/null +++ b/Build @@ -0,0 +1,11 @@ +package "mspgltk" +{ + require "mspgl"; + + library "mspgltk" + { + source "source"; + install true; + install_headers "msp/gltk"; + }; +}; diff --git a/source/alignment.cpp b/source/alignment.cpp new file mode 100644 index 0000000..bb5d392 --- /dev/null +++ b/source/alignment.cpp @@ -0,0 +1,14 @@ +#include +#include "alignment.h" +#include "geometry.h" + +namespace Msp { +namespace GLtk { + +void Alignment::apply(const Geometry &geom, unsigned wd, unsigned ht) const +{ + GL::translate((geom.w-wd)*(x+1)/2, (geom.h-ht)*(y+1)/2, 0); +} + +} // namespace GLtk +} // namespace Msp diff --git a/source/alignment.h b/source/alignment.h new file mode 100644 index 0000000..c89148d --- /dev/null +++ b/source/alignment.h @@ -0,0 +1,25 @@ +#ifndef MSP_GLTK_ALIGNMENT_H_ +#define MSP_GLTK_ALIGNMENT_H_ + +namespace Msp { +namespace GLtk { + +class Geometry; + +/** +Handles alignment of widget parts. Both x and y components can have values -1 +(left / bottom), 0 (center) or 1 (right / top). +*/ +struct Alignment +{ + int x, y; + + Alignment(): x(0), y(0) { } + Alignment(int x_, int y_): x(x_), y(y_) { } + void apply(const Geometry &, unsigned, unsigned) const; +}; + +} // namespace GLtk +} // namespace Msp + +#endif diff --git a/source/button.cpp b/source/button.cpp new file mode 100644 index 0000000..2432259 --- /dev/null +++ b/source/button.cpp @@ -0,0 +1,61 @@ +#include "button.h" +#include "part.h" + +namespace Msp { +namespace GLtk { + +Button::Button(const Resources &r, const std::string &t): + Widget(r) +{ + set_text(t); + update_style(); +} + +void Button::set_text(const std::string &t) +{ + text=t; +} + +void Button::render_part(const Part &part) const +{ + if(part.get_name()=="text") + { + render_text(part, text); + /*const GL::Font *const font=style->get_font(); + + const float font_size=font->get_default_size(); + unsigned text_w=static_cast(font->get_string_width(text)*font_size); + + part.get_alignment().apply(geom, text_w, static_cast(font_size)); + + GL::push_matrix(); + GL::scale_uniform(font_size); + + const Color &color=style->get_font_color(); + glColor3f(color.r, color.g, color.b); + font->draw_string(text); + glColor3f(1, 1, 1); + + GL::pop_matrix();*/ + } + else + Widget::render_part(part); +} + +void Button::on_button_press(int, int, unsigned btn) +{ + if(btn==1) + state=ACTIVE; +} + +void Button::on_button_release(int, int, unsigned btn) +{ + if(btn==1/* && x>=0 && y>=0 && x(geom.w) && y(geom.h)*/) + { + state=NORMAL; + signal_clicked.emit(); + } +} + +} // namespace GLtk +} // namespace Msp diff --git a/source/button.h b/source/button.h new file mode 100644 index 0000000..407e2f9 --- /dev/null +++ b/source/button.h @@ -0,0 +1,30 @@ +#ifndef MSP_GLTK_BUTTON_H_ +#define MSP_GLTK_BUTTON_H_ + +#include +#include "widget.h" + +namespace Msp { +namespace GLtk { + +class Button: public Widget +{ +public: + sigc::signal signal_clicked; + + Button(const Resources &, const std::string & =std::string()); + void set_text(const std::string &); +private: + std::string text; + bool pressed; + + const char *get_class() const { return "button"; } + void render_part(const Part &) const; + void on_button_press(int, int, unsigned); + void on_button_release(int, int, unsigned); +}; + +} // namespace GLtk +} // namespace Msp + +#endif diff --git a/source/color.h b/source/color.h new file mode 100644 index 0000000..1d6b456 --- /dev/null +++ b/source/color.h @@ -0,0 +1,18 @@ +#ifndef MSP_GLTK_COLOR_H_ +#define MSP_GLTK_COLOR_H_ + +namespace Msp { +namespace GLtk { + +struct Color +{ + float r, g, b; + + Color(): r(1), g(1), b(1) { } + Color(float r_, float g_, float b_): r(r_), g(g_), b(b_) { } +}; + +} // namespace GLtk +} // namespace Msp + +#endif diff --git a/source/geometry.h b/source/geometry.h new file mode 100644 index 0000000..7e59bd4 --- /dev/null +++ b/source/geometry.h @@ -0,0 +1,22 @@ +#ifndef MSP_GLTK_GEOMETRY_H_ +#define MSP_GLTK_GEOMETRY_H_ + +namespace Msp { +namespace GLtk { + +/** +Specifies the position and size of a widget or graphic. +*/ +struct Geometry +{ + int x, y; + unsigned w, h; + + Geometry(): x(0), y(0), w(1), h(1) { } + Geometry(int x_, int y_, unsigned w_, unsigned h_): x(x_), y(y_), w(w_), h(h_) { } +}; + +} // namespace GLtk +} // namespace Msp + +#endif diff --git a/source/graphic.cpp b/source/graphic.cpp new file mode 100644 index 0000000..99defc7 --- /dev/null +++ b/source/graphic.cpp @@ -0,0 +1,116 @@ +#include "graphic.h" +#include "resources.h" + +using namespace std; + +#include + +namespace Msp { +namespace GLtk { + +Graphic::Graphic(const Resources &r, const string &n): + res(r), + name(n), + texture(0) +{ } + +void Graphic::render(unsigned wd, unsigned ht) const +{ + float x[4]; + float y[4]; + float u[4]; + float v[4]; + + x[0]=0.0f-shadow.left; + x[1]=x[0]+border.left; + x[3]=wd+shadow.right; + x[2]=x[3]-border.right; + + y[0]=0.0f-shadow.bottom; + y[1]=y[0]+border.bottom; + y[3]=ht+shadow.top; + y[2]=y[3]-border.top; + + const unsigned twidth=texture->get_width(); + u[0]=static_cast(slice.x)/twidth; + u[1]=static_cast(slice.x+border.left)/twidth; + u[2]=static_cast(slice.x+slice.w-border.right)/twidth; + u[3]=static_cast(slice.x+slice.w)/twidth; + + const unsigned theight=texture->get_height(); + v[0]=static_cast(slice.y)/theight; + v[1]=static_cast(slice.y+border.bottom)/theight; + v[2]=static_cast(slice.y+slice.h-border.top)/theight; + v[3]=static_cast(slice.y+slice.h)/theight; + + texture->bind(); + unsigned xmin=border.left ? 0 : 1; + unsigned xmax=border.right ? 3 : 2; + unsigned ymin=border.bottom ? 0 : 1; + unsigned ymax=border.top ? 3 : 2; + + for(unsigned i=ymin; iget_width(), graph.texture->get_height()); +} + +void Graphic::Loader::slice(unsigned x, unsigned y, unsigned w, unsigned h) +{ + graph.slice=Geometry(x, y, w, h); +} + +void Graphic::Loader::border() +{ + load_sub(graph.border); +} + +void Graphic::Loader::shadow() +{ + load_sub(graph.shadow); +} + + +Graphic::Sides::Loader::Loader(Sides &s): + sides(s) +{ + add("top", &Sides::top); + add("right", &Sides::right); + add("bottom", &Sides::bottom); + add("left", &Sides::left); +} + +} // namespace GLtk +} // namespace Msp diff --git a/source/graphic.h b/source/graphic.h new file mode 100644 index 0000000..16d8cf4 --- /dev/null +++ b/source/graphic.h @@ -0,0 +1,67 @@ +#ifndef MSP_GLTK_GRAPHIC_H_ +#define MSP_GLTK_GRAPHIC_H_ + +#include +#include +#include "geometry.h" + +namespace Msp { +namespace GLtk { + +class Resources; + +class Graphic +{ +public: + class Loader: public Parser::Loader + { + public: + Loader(Graphic &); + private: + Graphic &graph; + + void texture(const std::string &); + void slice(unsigned, unsigned, unsigned, unsigned); + void border(); + void shadow(); + }; + + struct Sides + { + class Loader: public Parser::Loader + { + public: + Loader(Sides &); + Sides &get_object() { return sides; } + private: + Sides &sides; + }; + + unsigned top; + unsigned right; + unsigned bottom; + unsigned left; + + Sides(); + }; + + Graphic(const Resources &, const std::string &); + const Sides &get_border() const { return border; } + const Sides &get_shadow() const { return shadow; } + const GL::Texture2D *get_texture() const { return texture; } + unsigned get_width() const { return slice.w; } + unsigned get_height() const { return slice.h; } + void render(unsigned, unsigned) const; +private: + const Resources &res; + std::string name; + Sides border; + Sides shadow; + const GL::Texture2D *texture; + Geometry slice; +}; + +} // namespace GLtk +} // namespace Msp + +#endif diff --git a/source/hslider.cpp b/source/hslider.cpp new file mode 100644 index 0000000..c1d334d --- /dev/null +++ b/source/hslider.cpp @@ -0,0 +1,24 @@ +#include "hslider.h" + +namespace Msp { +namespace GLtk { + +HSlider::HSlider(const Resources &r): + Slider(r) +{ +} + +void HSlider::render_part(const Part &part) +{ + if(part.get_name()=="slider") + { + const Graphic *graphic=part.get_graphic(state); + const Graphic::Sides &shadow=graphic->get_shadow(); + unsigned gw=graphic->get_slice().w-shadow.left-shadow.right; + unsigned gh=(part.get_fill_x() ? geom.h, graphic->get_slice().h)-shadow.bottom-shadow.top; + GL::translate((geom.w-gw)*(value-min)/(max-min), part.get_alignment().y + } +} + +} // namespace GLtk +} // namespace Msp diff --git a/source/hslider.h b/source/hslider.h new file mode 100644 index 0000000..84a164e --- /dev/null +++ b/source/hslider.h @@ -0,0 +1,23 @@ +#ifndef MSP_GLTK_HSLIDER_H_ +#define MSP_GLTK_HSLIDER_H_ + +#include "slider.h" + +namespace Msp { +namespace GLtk { + +class HSlider: public Slider +{ +public: + HSlider(const Resources &); +private: + void render_part(const Part &) const; + void on_button_press(int, int, unsigned); + void on_button_release(int, int, unsigned); + void pointer_motion(int, int); +}; + +} // namespace GLtk +} // namespace Msp + +#endif diff --git a/source/indicator.cpp b/source/indicator.cpp new file mode 100644 index 0000000..682837a --- /dev/null +++ b/source/indicator.cpp @@ -0,0 +1,18 @@ +#include "indicator.h" + +namespace Msp { +namespace GLtk { + +Indicator::Indicator(const Resources &r): + Widget(r) +{ + update_style(); +} + +void Indicator::set_active(bool a) +{ + state=(a ? ACTIVE : NORMAL); +} + +} // namespace GLtk +} // namespace Msp diff --git a/source/indicator.h b/source/indicator.h new file mode 100644 index 0000000..c8ecbc5 --- /dev/null +++ b/source/indicator.h @@ -0,0 +1,21 @@ +#ifndef MSP_GLTK_INDICATOR_H_ +#define MSP_GLTK_INDICATOR_H_ + +#include "widget.h" + +namespace Msp { +namespace GLtk { + +class Indicator: public Widget +{ +public: + Indicator(const Resources &); + void set_active(bool); +private: + const char *get_class() const { return "indicator"; } +}; + +} // namespace GLtk +} // namespace Msp + +#endif diff --git a/source/label.cpp b/source/label.cpp new file mode 100644 index 0000000..d0aba35 --- /dev/null +++ b/source/label.cpp @@ -0,0 +1,28 @@ +#include "label.h" +#include "part.h" + +namespace Msp { +namespace GLtk { + +Label::Label(const Resources &r, const std::string &t): + Widget(r) +{ + set_text(t); + update_style(); +} + +void Label::set_text(const std::string &t) +{ + text=t; +} + +void Label::render_part(const Part &part) const +{ + if(part.get_name()=="text") + render_text(part, text); + else + Widget::render_part(part); +} + +} // namespace GLtk +} // namespace Msp diff --git a/source/label.h b/source/label.h new file mode 100644 index 0000000..0ab2029 --- /dev/null +++ b/source/label.h @@ -0,0 +1,24 @@ +#ifndef LABEL_H_ +#define LABEL_H_ + +#include "widget.h" + +namespace Msp { +namespace GLtk { + +class Label: public Widget +{ +public: + Label(const Resources &, const std::string & =std::string()); + void set_text(const std::string &); +private: + std::string text; + + const char *get_class() const { return "label"; } + void render_part(const Part &) const; +}; + +} // namespace GLtk +} // namespace Msp + +#endif diff --git a/source/panel.cpp b/source/panel.cpp new file mode 100644 index 0000000..b029057 --- /dev/null +++ b/source/panel.cpp @@ -0,0 +1,48 @@ +#include "panel.h" +#include "part.h" + +namespace Msp { +namespace GLtk { + +Panel::Panel(const Resources &r): + Widget(r) +{ + update_style(); +} + +Panel::~Panel() +{ + for(ChildSeq::iterator i=children.begin(); i!=children.end(); ++i) + delete *i; +} + +void Panel::add(Widget &wdg) +{ + children.push_back(&wdg); +} + +void Panel::render_part(const Part &part) const +{ + if(part.get_name()=="children") + { + for(ChildSeq::const_iterator i=children.begin(); i!=children.end(); ++i) + (*i)->render(); + } + else + Widget::render_part(part); +} + +void Panel::on_button_press(int x, int y, unsigned btn) +{ + for(ChildSeq::iterator i=children.begin(); i!=children.end(); ++i) + (*i)->button_press(x-geom.x, y-geom.y, btn); +} + +void Panel::on_button_release(int x, int y, unsigned btn) +{ + for(ChildSeq::iterator i=children.begin(); i!=children.end(); ++i) + (*i)->button_release(x-geom.x, y-geom.y, btn); +} + +} // namespace GLtk +} // namespace Msp diff --git a/source/panel.h b/source/panel.h new file mode 100644 index 0000000..7a94dcd --- /dev/null +++ b/source/panel.h @@ -0,0 +1,31 @@ +#ifndef MSP_GLTK_PANEL_H_ +#define MSP_GLTK_PANEL_H_ + +#include "widget.h" + +namespace Msp { +namespace GLtk { + +class Panel: public Widget +{ +public: + Panel(const Resources &); + ~Panel(); + void add(Widget &); +private: + typedef std::list ChildSeq; + + ChildSeq children; + + Panel(const Panel &); + Panel &operator=(const Panel &); + const char *get_class() const { return "panel"; } + void render_part(const Part &) const; + void on_button_press(int, int, unsigned); + void on_button_release(int, int, unsigned); +}; + +} // namespace GLtk +} // namespace Msp + +#endif diff --git a/source/part.cpp b/source/part.cpp new file mode 100644 index 0000000..38e75d7 --- /dev/null +++ b/source/part.cpp @@ -0,0 +1,70 @@ +#include "geometry.h" +#include "part.h" +#include "resources.h" + +using namespace std; + +namespace Msp { +namespace GLtk { + +Part::Part(const Resources &r, const string &n): + res(r), + name(n), + fill_x(true), + fill_y(true) +{ + for(unsigned i=0; iN_STATES_) + throw InvalidParameterValue("Invalid state"); + + return graphic[state]; +} + +void Part::render(const Geometry &geom, State state) const +{ + const Graphic::Sides &shadow=graphic[state]->get_shadow(); + unsigned gw=(fill_x ? geom.w : graphic[state]->get_width())-shadow.left-shadow.right; + unsigned gh=(fill_y ? geom.h : graphic[state]->get_height())-shadow.top-shadow.bottom; + align.apply(geom, gw, gh); + graphic[state]->render(gw, gh); +} + + +Part::Loader::Loader(Part &p): + part(p) +{ + add("graphic", &Loader::graphic); + add("align", &Loader::align); + add("fill", &Loader::fill); +} + +void Part::Loader::graphic(State s, const string &n) +{ + part.graphic[s]=&part.res.get_graphic(n); + if(s==NORMAL) + { + for(unsigned i=0; i +#include +#include +#include "alignment.h" +#include "state.h" + +namespace Msp { +namespace GLtk { + +class Graphic; +class Resources; + +class Part +{ +public: + class Loader: public Parser::Loader + { + public: + Loader(Part &); + private: + Part ∂ + + void graphic(State, const std::string &); + void align(int, int); + void fill(bool, bool); + }; + + Part(const Resources &, const std::string &); + const std::string &get_name() const { return name; } + const Graphic *get_graphic(State) const; + const Alignment &get_alignment() const { return align; } + bool get_fill_x() const { return fill_x; } + bool get_fill_y() const { return fill_y; } + void render(const Geometry &, State) const; +private: + const Resources &res; + std::string name; + const Graphic *graphic[N_STATES_]; + Alignment align; + bool fill_x; + bool fill_y; +}; +typedef std::list PartSeq; + +} // namespace GLtk +} // namespace Msp + +#endif diff --git a/source/resources.cpp b/source/resources.cpp new file mode 100644 index 0000000..a61566a --- /dev/null +++ b/source/resources.cpp @@ -0,0 +1,122 @@ +#include +#include "resources.h" + +using namespace std; + +namespace Msp { +namespace GLtk { + +Resources::Resources(): + default_font(0) +{ } + +Resources::~Resources() +{ + for(FontMap::iterator i=fonts.begin(); i!=fonts.end(); ++i) + delete i->second; + for(TextureMap::iterator i=textures.begin(); i!=textures.end(); ++i) + delete i->second; +} + +const GL::Font &Resources::get_font(const string &name) const +{ + FontMap::const_iterator i=fonts.find(name); + if(i==fonts.end()) + throw KeyError("Unknown font "+name); + + return *i->second; +} + +const GL::Font &Resources::get_default_font() const +{ + if(!default_font) + throw InvalidState("No default font"); + + return *default_font; +} + +const GL::Texture2D &Resources::get_texture(const string &name) const +{ + TextureMap::const_iterator i=textures.find(name); + if(i==textures.end()) + throw KeyError("Unknown texture "+name); + + return *i->second; +} + +const Graphic &Resources::get_graphic(const string &name) const +{ + GraphicMap::const_iterator i=graphics.find(name); + if(i==graphics.end()) + throw KeyError("Unknown graphic "+name); + + return i->second; +} + +const Style &Resources::get_style(const string &wdg, const string &name) const +{ + StyleMap::const_iterator i=styles.find(StyleId(wdg, name)); + if(i==styles.end()) + throw KeyError("Unknown style "+name+" for widget "+wdg); + + return i->second; +} + + +Resources::Loader::Loader(Resources &r): + res(r) +{ + add("font", &Loader::font); + add("texture", &Loader::texture); + add("graphic", &Loader::graphic); + add("style", &Loader::style); +} + +void Resources::Loader::font(const string &fn) +{ + RefPtr fnt=new GL::Font; + Parser::load(*fnt, fn); + + res.fonts.insert(FontMap::value_type(fn.substr(0, fn.rfind('.')), fnt.get())); + if(!res.default_font) + res.default_font=fnt.get(); + fnt.release(); +} + +void Resources::Loader::texture(const string &fn) +{ + RefPtr tex=new GL::Texture2D; + tex->image(fn); + tex->set_min_filter(GL::LINEAR); + + res.textures.insert(TextureMap::value_type(fn.substr(0, fn.rfind('.')), tex.release())); +} + +void Resources::Loader::graphic(const std::string &n) +{ + Graphic graph(res, n); + load_sub(graph); + if(!graph.get_texture()) + throw Exception("Graphic without texture"); + + res.graphics.insert(GraphicMap::value_type(n, graph)); +} + +void Resources::Loader::style(const string &w, const string &n) +{ + Style stl(res, w, n); + load_sub(stl); + + res.styles.insert(StyleMap::value_type(StyleId(w, n), stl)); +} + + +bool Resources::StyleId::operator<(const StyleId &other) const +{ + if(widget +#include +#include +#include "graphic.h" +#include "style.h" + +namespace Msp { +namespace GLtk { + +class Resources +{ +public: + + class Loader: public Msp::Parser::Loader + { + public: + Loader(Resources &); + private: + Resources &res; + + void font(const std::string &); + void texture(const std::string &); + void graphic(const std::string &); + void style(const std::string &, const std::string &); + }; + + Resources(); + ~Resources(); + const GL::Font &get_font(const std::string &) const; + const GL::Font &get_default_font() const; + const GL::Texture2D &get_texture(const std::string &) const; + const Graphic &get_graphic(const std::string &) const; + const Style &get_style(const std::string &, const std::string &) const; +private: + struct StyleId + { + std::string widget; + std::string name; + + StyleId(const std::string &w, const std::string &n): widget(w), name(n) { } + bool operator<(const StyleId &) const; + }; + + typedef std::map FontMap; + typedef std::map TextureMap; + typedef std::map GraphicMap; + typedef std::map StyleMap; + + FontMap fonts; + GL::Font *default_font; + TextureMap textures; + GraphicMap graphics; + StyleMap styles; + + Resources(const Resources &); + Resources &operator=(const Resources &); +}; + +} // namespace GLtk +} // namespace Msp + +#endif diff --git a/source/slider.cpp b/source/slider.cpp new file mode 100644 index 0000000..e7f67c1 --- /dev/null +++ b/source/slider.cpp @@ -0,0 +1,29 @@ +#include "slider.h" + +namespace Msp { +namespace GLtk { + +Slider::Slider(const Resources &r): + Widget(r), + min(0), + max(1), + value(0), + step(0.1) +{ +} + +void Slider::set_value(double v) +{ + if(vmax) + value=max; + else + { + unsigned steps=static_cast((v-min)/step+0.5); + value=min+steps*step; + } +} + +} // namespace GLtk +} // namespace Msp diff --git a/source/slider.h b/source/slider.h new file mode 100644 index 0000000..c88c15b --- /dev/null +++ b/source/slider.h @@ -0,0 +1,27 @@ +#ifndef MSP_GLTK_SLIDER_H_ +#define MSP_GLTK_SLIDER_H_ + +#include "widget.h" + +namespace Msp { +namespace GLtk { + +class Slider: public Widget +{ +public: + void set_value(double); + void set_range(double, double); + void set_step(double); + double get_value() const { return value; } +protected: + double min, max; + double value; + double step; + + Slider(const Resourcres &); +}; + +} // namespace GLtk +} // namespace Msp + +#endif diff --git a/source/state.cpp b/source/state.cpp new file mode 100644 index 0000000..bbff03d --- /dev/null +++ b/source/state.cpp @@ -0,0 +1,27 @@ +#include "state.h" + +using namespace std; + +namespace Msp { +namespace GLtk { + +istream &operator>>(istream &is, State &state) +{ + string str; + is>>str; + if(str=="normal") + state=NORMAL; + else if(str=="hover") + state=HOVER; + else if(str=="active") + state=ACTIVE; + else if(str=="disabled") + state=DISABLED; + else + is.setstate(ios_base::failbit); + + return is; +} + +} // namespace GLtk +} // namespace Msp diff --git a/source/state.h b/source/state.h new file mode 100644 index 0000000..6cbe152 --- /dev/null +++ b/source/state.h @@ -0,0 +1,31 @@ +#ifndef MSP_GLTK_STATE_H_ +#define MSP_GLTK_STATE_H_ + +#include +#include + +namespace Msp { +namespace GLtk { + +enum State +{ + NORMAL, //< Default state + HOVER, //< Pointer over the widget + ACTIVE, //< Widget is active (e.g. pressed button) + DISABLED, //< Widget is unresponsive + N_STATES_ //< Sentry value +}; + +extern std::istream &operator>>(std::istream &, State &); + +} // namespace GLtk + +namespace Parser { + +template<> +struct TypeResolver { static const Value::Type type=Value::ENUM; }; + +} // namespace Parser +} // namespace Msp + +#endif diff --git a/source/style.cpp b/source/style.cpp new file mode 100644 index 0000000..3f276ed --- /dev/null +++ b/source/style.cpp @@ -0,0 +1,43 @@ +#include "resources.h" +#include "style.h" + +using namespace std; + +namespace Msp { +namespace GLtk { + +Style::Style(const Resources &r, const string &w, const string &n): + res(r), + widget(w), + name(n), + font(&res.get_default_font()) +{ } + + +Style::Loader::Loader(Style &s): + style(s) +{ + add("font", &Loader::font); + add("font_color", &Loader::font_color); + add("part", &Loader::part); +} + +void Style::Loader::font(const string &f) +{ + style.font=&style.res.get_font(f); +} + +void Style::Loader::font_color(float r, float g, float b) +{ + style.font_color=Color(r, g, b); +} + +void Style::Loader::part(const string &n) +{ + Part p(style.res, n); + load_sub(p); + style.parts.push_back(p); +} + +} // namespace GLtk +} // namespace Msp diff --git a/source/style.h b/source/style.h new file mode 100644 index 0000000..a757abc --- /dev/null +++ b/source/style.h @@ -0,0 +1,45 @@ +#ifndef MSP_GLTK_STYLE_H_ +#define MSP_GLTK_STYLE_H_ + +#include +#include +#include "color.h" +#include "part.h" + +namespace Msp { +namespace GLtk { + +class Resources; + +class Style +{ +public: + class Loader: public Parser::Loader + { + public: + Loader(Style &); + private: + Style &style; + + void font(const std::string &); + void font_color(float, float, float); + void part(const std::string &); + }; + + Style(const Resources &, const std::string &, const std::string &); + const GL::Font *get_font() const { return font; } + const Color &get_font_color() const { return font_color; } + const PartSeq &get_parts() const { return parts; } +private: + const Resources &res; + std::string widget; + std::string name; + const GL::Font *font; + Color font_color; + PartSeq parts; +}; + +} // namespace GLtk +} // namespace Msp + +#endif diff --git a/source/widget.cpp b/source/widget.cpp new file mode 100644 index 0000000..48ae0ed --- /dev/null +++ b/source/widget.cpp @@ -0,0 +1,113 @@ +#include +#include +#include "resources.h" +#include "widget.h" + +#include +using namespace std; + +namespace Msp { +namespace GLtk { + +void Widget::set_position(int x, int y) +{ + geom.x=x; + geom.y=y; +} + +void Widget::set_size(unsigned w, unsigned h) +{ + geom.w=w; + geom.h=h; +} + +void Widget::set_geometry(const Geometry &g) +{ + geom=g; +} + +void Widget::set_style(const string &s) +{ + style_name=s; + update_style(); +} + +void Widget::render() const +{ + if(!style) + throw InvalidState("Attempt to render a widget without a style"); + + GL::push_matrix(); + GL::translate(geom.x, geom.y, 0); + for(PartSeq::const_iterator i=style->get_parts().begin(); i!=style->get_parts().end(); ++i) + render_part(*i); + GL::pop_matrix(); +} + +bool Widget::button_press(int x, int y, unsigned btn) +{ + if(x>=geom.x && y>=geom.y && x(geom.w) && y(geom.h)) + { + on_button_press(x, y, btn); + return true; + } + + return false; +} + +bool Widget::button_release(int x, int y, unsigned btn) +{ + if(x>=geom.x && y>=geom.y && x(geom.w) && y(geom.h)) + { + on_button_release(x, y, btn); + return true; + } + + return false; +} + +Widget::Widget(const Resources &r): + res(r), + style(0), + state(NORMAL) +{ } + +void Widget::update_style() +{ + style=&res.get_style(get_class(), style_name); +} + +void Widget::render_part(const Part &part) const +{ + render_graphic(part); +} + +void Widget::render_graphic(const Part &part) const +{ + GL::push_matrix(); + part.render(geom, state); + GL::pop_matrix(); +} + +void Widget::render_text(const Part &part, const string &text) const +{ + const GL::Font *const font=style->get_font(); + + const float font_size=font->get_default_size(); + unsigned text_w=static_cast(font->get_string_width(text)*font_size); + + GL::push_matrix(); + + part.get_alignment().apply(geom, text_w, static_cast(font_size)); + GL::scale_uniform(font_size); + + const Color &color=style->get_font_color(); + glColor3f(color.r, color.g, color.b); + font->draw_string(text); + glColor3f(1, 1, 1); + + GL::pop_matrix(); +} + +} // namespace GLtk +} // namespace Msp diff --git a/source/widget.h b/source/widget.h new file mode 100644 index 0000000..f64e2ea --- /dev/null +++ b/source/widget.h @@ -0,0 +1,51 @@ +#ifndef MSP_GLTK_WIDGET_H_ +#define MSP_GLTK_WIDGET_H_ + +#include +#include "geometry.h" +#include "state.h" + +namespace Msp { +namespace GLtk { + +class Part; +class Resources; +class Style; + +class Widget +{ +public: + virtual ~Widget() { } + void set_position(int, int); + void set_size(unsigned, unsigned); + void set_geometry(const Geometry &); + void set_style(const std::string &); + const Geometry &get_geometry() const { return geom; } + void render() const; + bool button_press(int, int, unsigned); + bool button_release(int, int, unsigned); + bool pointer_motion(int, int); +protected: + const Resources &res; + Geometry geom; + std::string style_name; + const Style *style; + State state; + + Widget(const Resources &); + virtual const char *get_class() const { return "widget"; } + void update_style(); + virtual void render_part(const Part &) const; + void render_graphic(const Part &) const; + void render_text(const Part &, const std::string &) const; + virtual void on_button_press(int, int, unsigned) { } + virtual void on_button_release(int, int, unsigned) { } + virtual void on_pointer_motion(int, int, unsigned) { } + virtual void on_pointer_enter() { } + virtual void on_pointer_leave() { } +}; + +} // namespace GLtk +} // namespace Msp + +#endif diff --git a/source/window.h b/source/window.h new file mode 100644 index 0000000..13febae --- /dev/null +++ b/source/window.h @@ -0,0 +1,21 @@ +#ifndef MSP_GLTK_WINDOW_H_ +#define MSP_GLTK_WINDOW_H_ + +#include + +namespace Msp { +namespace GLtk { + +class Window +{ +public: + Window(); +private: + Display *display; + Window window; +}; + +} // namespace GLtk +} // namespace Msp + +#endif