]> git.tdb.fi Git - libs/gltk.git/commitdiff
Initial revision
authorMikko Rasa <tdb@tdb.fi>
Tue, 12 Jun 2007 18:54:27 +0000 (18:54 +0000)
committerMikko Rasa <tdb@tdb.fi>
Tue, 12 Jun 2007 18:54:27 +0000 (18:54 +0000)
30 files changed:
Build [new file with mode: 0644]
source/alignment.cpp [new file with mode: 0644]
source/alignment.h [new file with mode: 0644]
source/button.cpp [new file with mode: 0644]
source/button.h [new file with mode: 0644]
source/color.h [new file with mode: 0644]
source/geometry.h [new file with mode: 0644]
source/graphic.cpp [new file with mode: 0644]
source/graphic.h [new file with mode: 0644]
source/hslider.cpp [new file with mode: 0644]
source/hslider.h [new file with mode: 0644]
source/indicator.cpp [new file with mode: 0644]
source/indicator.h [new file with mode: 0644]
source/label.cpp [new file with mode: 0644]
source/label.h [new file with mode: 0644]
source/panel.cpp [new file with mode: 0644]
source/panel.h [new file with mode: 0644]
source/part.cpp [new file with mode: 0644]
source/part.h [new file with mode: 0644]
source/resources.cpp [new file with mode: 0644]
source/resources.h [new file with mode: 0644]
source/slider.cpp [new file with mode: 0644]
source/slider.h [new file with mode: 0644]
source/state.cpp [new file with mode: 0644]
source/state.h [new file with mode: 0644]
source/style.cpp [new file with mode: 0644]
source/style.h [new file with mode: 0644]
source/widget.cpp [new file with mode: 0644]
source/widget.h [new file with mode: 0644]
source/window.h [new file with mode: 0644]

diff --git a/Build b/Build
new file mode 100644 (file)
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 (file)
index 0000000..bb5d392
--- /dev/null
@@ -0,0 +1,14 @@
+#include <msp/gl/transform.h>
+#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 (file)
index 0000000..c89148d
--- /dev/null
@@ -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 (file)
index 0000000..2432259
--- /dev/null
@@ -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<unsigned>(font->get_string_width(text)*font_size);
+
+               part.get_alignment().apply(geom, text_w, static_cast<unsigned>(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<static_cast<int>(geom.w) && y<static_cast<int>(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 (file)
index 0000000..407e2f9
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef MSP_GLTK_BUTTON_H_
+#define MSP_GLTK_BUTTON_H_
+
+#include <sigc++/sigc++.h>
+#include "widget.h"
+
+namespace Msp {
+namespace GLtk {
+
+class Button: public Widget
+{
+public:
+       sigc::signal<void> 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 (file)
index 0000000..1d6b456
--- /dev/null
@@ -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 (file)
index 0000000..7e59bd4
--- /dev/null
@@ -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 (file)
index 0000000..99defc7
--- /dev/null
@@ -0,0 +1,116 @@
+#include "graphic.h"
+#include "resources.h"
+
+using namespace std;
+
+#include <iostream>
+
+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<float>(slice.x)/twidth;
+       u[1]=static_cast<float>(slice.x+border.left)/twidth;
+       u[2]=static_cast<float>(slice.x+slice.w-border.right)/twidth;
+       u[3]=static_cast<float>(slice.x+slice.w)/twidth;
+
+       const unsigned theight=texture->get_height();
+       v[0]=static_cast<float>(slice.y)/theight;
+       v[1]=static_cast<float>(slice.y+border.bottom)/theight;
+       v[2]=static_cast<float>(slice.y+slice.h-border.top)/theight;
+       v[3]=static_cast<float>(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; i<ymax; ++i)
+       {
+               glBegin(GL_QUAD_STRIP);
+               for(unsigned j=xmin; j<=xmax; ++j)
+               {
+                       glTexCoord2f(u[j], v[i]);
+                       glVertex2f(x[j], y[i]);
+                       glTexCoord2f(u[j], v[i+1]);
+                       glVertex2f(x[j], y[i+1]);
+               }
+               glEnd();
+       }
+}
+
+
+Graphic::Sides::Sides():
+       top(0),
+       right(0),
+       bottom(0),
+       left(0)
+{ }
+
+
+Graphic::Loader::Loader(Graphic &g):
+       graph(g)
+{
+       add("texture", &Loader::texture);
+       add("slice",   &Loader::slice);
+       add("border",  &Loader::border);
+       add("shadow",  &Loader::shadow);
+}
+
+void Graphic::Loader::texture(const string &n)
+{
+       graph.texture=&graph.res.get_texture(n);
+       graph.slice=Geometry(0, 0, graph.texture->get_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 (file)
index 0000000..16d8cf4
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef MSP_GLTK_GRAPHIC_H_
+#define MSP_GLTK_GRAPHIC_H_
+
+#include <msp/gl/texture2d.h>
+#include <msp/parser/loader.h>
+#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 (file)
index 0000000..c1d334d
--- /dev/null
@@ -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 (file)
index 0000000..84a164e
--- /dev/null
@@ -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 (file)
index 0000000..682837a
--- /dev/null
@@ -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 (file)
index 0000000..c8ecbc5
--- /dev/null
@@ -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 (file)
index 0000000..d0aba35
--- /dev/null
@@ -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 (file)
index 0000000..0ab2029
--- /dev/null
@@ -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 (file)
index 0000000..b029057
--- /dev/null
@@ -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 (file)
index 0000000..7a94dcd
--- /dev/null
@@ -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<Widget *> 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 (file)
index 0000000..38e75d7
--- /dev/null
@@ -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; i<N_STATES_; ++i)
+               graphic[i]=0;
+}
+
+const Graphic *Part::get_graphic(State state) const
+{
+       if(state>N_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<N_STATES_; ++i)
+                       if(!part.graphic[i])
+                               part.graphic[i]=part.graphic[s];
+       }
+}
+
+void Part::Loader::align(int x, int y)
+{
+       part.align.x=x;
+       part.align.y=y;
+}
+
+void Part::Loader::fill(bool x, bool y)
+{
+       part.fill_x=x;
+       part.fill_y=y;
+}
+
+} // namespace GLtk
+} // namespace Msp
diff --git a/source/part.h b/source/part.h
new file mode 100644 (file)
index 0000000..b8761e6
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef MSP_GLTK_PART_H_
+#define MSP_GLTK_PART_H_
+
+#include <map>
+#include <string>
+#include <msp/parser/loader.h>
+#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 &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<Part> PartSeq;
+
+} // namespace GLtk
+} // namespace Msp
+
+#endif
diff --git a/source/resources.cpp b/source/resources.cpp
new file mode 100644 (file)
index 0000000..a61566a
--- /dev/null
@@ -0,0 +1,122 @@
+#include <msp/core/error.h>
+#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<GL::Font> 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<GL::Texture2D> 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<other.widget)
+               return true;
+       return widget==other.widget && name<other.name;
+}
+
+} // namespace GLtk
+} // namespace Msp
diff --git a/source/resources.h b/source/resources.h
new file mode 100644 (file)
index 0000000..001fa63
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef MSP_GLTK_RESOURCES_H_
+#define MSP_GLTK_RESOURCES_H_
+
+#include <msp/gl/font.h>
+#include <msp/gl/texture.h>
+#include <msp/parser/loader.h>
+#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<std::string, GL::Font *> FontMap;
+       typedef std::map<std::string, GL::Texture2D *> TextureMap;
+       typedef std::map<std::string, Graphic> GraphicMap;
+       typedef std::map<StyleId, Style> 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 (file)
index 0000000..e7f67c1
--- /dev/null
@@ -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(v<min)
+               value=min;
+       else if(v>max)
+               value=max;
+       else
+       {
+               unsigned steps=static_cast<unsigned>((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 (file)
index 0000000..c88c15b
--- /dev/null
@@ -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 (file)
index 0000000..bbff03d
--- /dev/null
@@ -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 (file)
index 0000000..6cbe152
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef MSP_GLTK_STATE_H_
+#define MSP_GLTK_STATE_H_
+
+#include <istream>
+#include <msp/parser/value.h>
+
+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<GLtk::State> { 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 (file)
index 0000000..3f276ed
--- /dev/null
@@ -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 (file)
index 0000000..a757abc
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef MSP_GLTK_STYLE_H_
+#define MSP_GLTK_STYLE_H_
+
+#include <msp/gl/font.h>
+#include <msp/parser/loader.h>
+#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 (file)
index 0000000..48ae0ed
--- /dev/null
@@ -0,0 +1,113 @@
+#include <msp/gl/matrix.h>
+#include <msp/gl/transform.h>
+#include "resources.h"
+#include "widget.h"
+
+#include <iostream>
+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.x+static_cast<int>(geom.w) && y<geom.y+static_cast<int>(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.x+static_cast<int>(geom.w) && y<geom.y+static_cast<int>(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<unsigned>(font->get_string_width(text)*font_size);
+
+       GL::push_matrix();
+
+       part.get_alignment().apply(geom, text_w, static_cast<unsigned>(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 (file)
index 0000000..f64e2ea
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef MSP_GLTK_WIDGET_H_
+#define MSP_GLTK_WIDGET_H_
+
+#include <string>
+#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 (file)
index 0000000..13febae
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef MSP_GLTK_WINDOW_H_
+#define MSP_GLTK_WINDOW_H_
+
+#include <X11/X.h>
+
+namespace Msp {
+namespace GLtk {
+
+class Window
+{
+public:
+       Window();
+private:
+       Display *display;
+       Window  window;
+};
+
+} // namespace GLtk
+} // namespace Msp
+
+#endif