text=t;
}
-void Button::render_part(const Part &part) const
+void Button::button_press(int x, int y, unsigned btn)
{
- 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)
+ if(geom.is_inside(x, y) && btn==1)
state=ACTIVE;
}
-void Button::on_button_release(int, int, unsigned btn)
+void Button::button_release(int x, int y, unsigned btn)
{
- if(btn==1/* && x>=0 && y>=0 && x<static_cast<int>(geom.w) && y<static_cast<int>(geom.h)*/)
+ if(btn==1)
{
state=NORMAL;
- signal_clicked.emit();
+ if(geom.is_inside(x, y))
+ signal_clicked.emit();
}
}
+void Button::render_part(const Part &part) const
+{
+ if(part.get_name()=="text")
+ render_text(part, text);
+ else
+ Widget::render_part(part);
+}
+
} // namespace GLtk
} // namespace Msp
Button(const Resources &, const std::string & =std::string());
void set_text(const std::string &);
+ void button_press(int, int, unsigned);
+ void button_release(int, int, unsigned);
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
--- /dev/null
+#include "geometry.h"
+
+namespace Msp {
+namespace GLtk {
+
+bool Geometry::is_inside(int x_, int y_) const
+{
+ return (x_>=x && x_<x+static_cast<int>(w) && y_>=y && y_<y+static_cast<int>(h));
+}
+
+
+Sides::Sides():
+ top(0),
+ right(0),
+ bottom(0),
+ left(0)
+{ }
+
+
+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
#ifndef MSP_GLTK_GEOMETRY_H_
#define MSP_GLTK_GEOMETRY_H_
+#include <msp/parser/loader.h>
+
namespace Msp {
namespace GLtk {
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_) { }
+ bool is_inside(int, int) const;
+};
+
+/**
+Specifies margins on the sides of an element.
+*/
+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();
};
} // namespace GLtk
}
-Graphic::Sides::Sides():
- top(0),
- right(0),
- bottom(0),
- left(0)
-{ }
-
-
Graphic::Loader::Loader(Graphic &g):
graph(g)
{
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
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; }
+#include <msp/gl/matrix.h>
+#include <msp/gl/transform.h>
+#include "graphic.h"
#include "hslider.h"
+#include "part.h"
+#include "style.h"
namespace Msp {
namespace GLtk {
HSlider::HSlider(const Resources &r):
- Slider(r)
+ Slider(r),
+ dragging(false)
{
+ update_style();
}
-void HSlider::render_part(const Part &part)
+void HSlider::button_press(int x, int y, unsigned btn)
+{
+ if(geom.is_inside(x, y))
+ {
+ int sw=get_slider_width();
+ int sx=static_cast<int>((geom.w-sw)*(value-min)/(max-min));
+ if(btn==1 && x>=sx && x<sx+sw)
+ {
+ dragging=true;
+ state=ACTIVE;
+ drag_start_x=x;
+ drag_start_value=value;
+ }
+ }
+}
+
+void HSlider::button_release(int, int, unsigned btn)
+{
+ if(btn==1)
+ {
+ dragging=false;
+ state=NORMAL;
+ }
+}
+
+void HSlider::pointer_motion(int x, int)
+{
+ if(dragging)
+ {
+ set_value(drag_start_value+(x-drag_start_x)*(max-min)/(geom.w-get_slider_width()));
+ }
+}
+
+void HSlider::render_part(const Part &part) const
{
if(part.get_name()=="slider")
{
+ unsigned gw=part.get_width();
+ unsigned gh=(part.get_fill_y() ? geom.h : part.get_height());
+ GL::push_matrix();
+ GL::translate((geom.w-gw)*(value-min)/(max-min), (geom.h-gh)*(part.get_alignment().y+1)/2, 0);
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
+ graphic->render(gw, gh);
+ GL::pop_matrix();
}
+ else
+ Widget::render_part(part);
+}
+
+unsigned HSlider::get_slider_width() const
+{
+ for(PartSeq::const_iterator i=style->get_parts().begin(); i!=style->get_parts().end(); ++i)
+ if(i->get_name()=="slider")
+ return i->get_width();
+
+ return 0;
}
} // namespace GLtk
{
public:
HSlider(const Resources &);
+ void button_press(int, int, unsigned);
+ void button_release(int, int, unsigned);
+ void pointer_motion(int, int);
private:
+ bool dragging;
+ int drag_start_x;
+ double drag_start_value;
+
+ const char *get_class() const { return "hslider"; }
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);
+ unsigned get_slider_width() const;
};
} // namespace GLtk
namespace GLtk {
Panel::Panel(const Resources &r):
- Widget(r)
+ Widget(r),
+ pointer_focus(0),
+ pointer_grab(0)
{
update_style();
}
delete *i;
}
+void Panel::button_press(int x, int y, unsigned btn)
+{
+ if(pointer_grab>0)
+ pointer_focus->button_press(x-geom.x, y-geom.y, btn);
+ else if(geom.is_inside(x, y))
+ {
+ for(ChildSeq::iterator i=children.begin(); i!=children.end(); ++i)
+ if((*i)->get_geometry().is_inside(x-geom.x, y-geom.y))
+ {
+ (*i)->button_press(x-geom.x, y-geom.y, btn);
+ pointer_grab=btn;
+ }
+ }
+}
+
+void Panel::button_release(int x, int y, unsigned btn)
+{
+ if(pointer_grab>0)
+ {
+ pointer_focus->button_release(x-geom.x, y-geom.y, btn);
+
+ if(btn==pointer_grab)
+ {
+ pointer_grab=0;
+
+ for(ChildSeq::iterator i=children.begin(); i!=children.end(); ++i)
+ if((*i)->get_geometry().is_inside(x-geom.x, y-geom.y))
+ {
+ set_pointer_focus(*i);
+ break;
+ }
+ }
+ }
+ else if(geom.is_inside(x, y))
+ {
+ for(ChildSeq::iterator i=children.begin(); i!=children.end(); ++i)
+ if((*i)->get_geometry().is_inside(x-geom.x, y-geom.y))
+ (*i)->button_release(x-geom.x, y-geom.y, btn);
+ }
+}
+
+void Panel::pointer_motion(int x, int y)
+{
+ if(pointer_grab>0)
+ pointer_focus->pointer_motion(x-geom.x, y-geom.y);
+ else if(geom.is_inside(x, y))
+ {
+ bool found=false;
+ for(ChildSeq::iterator i=children.begin(); i!=children.end(); ++i)
+ if((*i)->get_geometry().is_inside(x-geom.x, y-geom.y))
+ {
+ set_pointer_focus(*i);
+ (*i)->pointer_motion(x-geom.x, y-geom.y);
+ found=true;
+ }
+
+ if(!found)
+ set_pointer_focus(0);
+ }
+}
+
void Panel::add(Widget &wdg)
{
children.push_back(&wdg);
Widget::render_part(part);
}
-void Panel::on_button_press(int x, int y, unsigned btn)
+void Panel::set_pointer_focus(Widget *wdg)
{
- for(ChildSeq::iterator i=children.begin(); i!=children.end(); ++i)
- (*i)->button_press(x-geom.x, y-geom.y, btn);
-}
+ if(wdg!=pointer_focus && pointer_grab==0)
+ {
+ if(pointer_focus)
+ pointer_focus->pointer_leave();
-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);
+ pointer_focus=wdg;
+
+ if(pointer_focus)
+ pointer_focus->pointer_enter();
+ }
}
} // namespace GLtk
public:
Panel(const Resources &);
~Panel();
+
void add(Widget &);
+ void button_press(int, int, unsigned);
+ void button_release(int, int, unsigned);
+ void pointer_motion(int, int);
private:
typedef std::list<Widget *> ChildSeq;
ChildSeq children;
+ Widget *pointer_focus;
+ unsigned pointer_grab;
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);
+ void set_pointer_focus(Widget *);
};
} // namespace GLtk
Part::Part(const Resources &r, const string &n):
res(r),
name(n),
+ width(1),
+ height(1),
fill_x(true),
fill_y(true)
{
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;
+ unsigned gw=(fill_x ? geom.w : width);
+ unsigned gh=(fill_y ? geom.h : height);
align.apply(geom, gw, gh);
graphic[state]->render(gw, gh);
}
add("fill", &Loader::fill);
}
-void Part::Loader::graphic(State s, const string &n)
+Part::Loader::~Loader()
{
- part.graphic[s]=&part.res.get_graphic(n);
- if(s==NORMAL)
+ for(unsigned i=0; i<N_STATES_; ++i)
{
- for(unsigned i=0; i<N_STATES_; ++i)
- if(!part.graphic[i])
- part.graphic[i]=part.graphic[s];
+ if(part.graphic[i])
+ {
+ const Sides &shadow=part.graphic[i]->get_shadow();
+ part.width=max(part.width, part.graphic[i]->get_width()-shadow.left-shadow.right);
+ part.height=max(part.height, part.graphic[i]->get_height()-shadow.bottom-shadow.top);
+ }
+ else
+ part.graphic[i]=part.graphic[NORMAL];
}
}
+void Part::Loader::graphic(State s, const string &n)
+{
+ part.graphic[s]=&part.res.get_graphic(n);
+}
+
void Part::Loader::align(int x, int y)
{
part.align.x=x;
{
public:
Loader(Part &);
+ ~Loader();
private:
Part ∂
Part(const Resources &, const std::string &);
const std::string &get_name() const { return name; }
const Graphic *get_graphic(State) const;
+ unsigned get_width() const { return width; }
+ unsigned get_height() const { return height; }
const Alignment &get_alignment() const { return align; }
bool get_fill_x() const { return fill_x; }
bool get_fill_y() const { return fill_y; }
const Resources &res;
std::string name;
const Graphic *graphic[N_STATES_];
+ unsigned width;
+ unsigned height;
Alignment align;
bool fill_x;
bool fill_y;
unsigned steps=static_cast<unsigned>((v-min)/step+0.5);
value=min+steps*step;
}
+
+ signal_value_changed.emit(value);
}
} // namespace GLtk
#ifndef MSP_GLTK_SLIDER_H_
#define MSP_GLTK_SLIDER_H_
+#include <sigc++/sigc++.h>
#include "widget.h"
namespace Msp {
class Slider: public Widget
{
public:
+ sigc::signal<void, double> signal_value_changed;
+
void set_value(double);
void set_range(double, double);
void set_step(double);
double value;
double step;
- Slider(const Resourcres &);
+ Slider(const Resources &);
};
} // namespace GLtk
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),
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);
+ virtual void button_press(int, int, unsigned) { }
+ virtual void button_release(int, int, unsigned) { }
+ virtual void pointer_motion(int, int) { }
+ virtual void pointer_enter() { }
+ virtual void pointer_leave() { }
protected:
const Resources &res;
Geometry geom;
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
--- /dev/null
+#include <vector>
+#include <GL/glx.h>
+#include <msp/core/error.h>
+#include "window.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GLtk {
+
+DisplayOptions::DisplayOptions():
+ width(640),
+ height(480),
+ depth(24),
+ alpha(false),
+ doublebuffer(false),
+ multisample(0),
+ fullscreen(false)
+{ }
+
+
+Window::Window(unsigned w, unsigned h)
+{
+ DisplayOptions dopt;
+ dopt.width=w;
+ dopt.height=h;
+
+ init(dopt);
+}
+
+Window::Window(const DisplayOptions &dopt)
+{
+ init(dopt);
+}
+
+Window::~Window()
+{
+ XCloseDisplay(display);
+}
+
+void Window::init(const DisplayOptions &dopt)
+{
+ display=XOpenDisplay(0);
+ if(!display)
+ throw Exception("Couldn't open X display");
+
+ vector<int> attribs;
+ attribs.push_back(GLX_BUFFER_SIZE);
+ attribs.push_back(dopt.depth);
+ attribs.push_back(GLX_DOUBLEBUFFER);
+ attribs.push_back(1);
+ if(dopt.multisample>0)
+ {
+ attribs.push_back(GLX_SAMPLE_BUFFERS_ARB);
+ attribs.push_back(dopt.multisample);
+ }
+
+ XVisualInfo *visual=glXChooseVisual(display, DefaultScreen(display), &attribs.front());
+ if(!visual)
+ throw Exception("Couldn't get a matching visual");
+
+ window=XCreateWindow(display, DefaultRootWindow(display), 0, 0, dopt.width, dopt.height, 0, CopyFromParent, InputOutput, visual->visual, 0, 0);
+}
+
+} // namespace GLtk
+} // namespace Msp
namespace Msp {
namespace GLtk {
+struct DisplayOptions
+{
+ unsigned width;
+ unsigned height;
+ unsigned depth;
+ bool alpha;
+ bool doublebuffer;
+ unsigned multisample;
+ bool fullscreen;
+
+ DisplayOptions();
+};
+
class Window
{
public:
- Window();
+ Window(unsigned, unsigned);
+ Window(const DisplayOptions &);
+ ~Window();
private:
Display *display;
- Window window;
+ ::Window window;
+
+ void init(const DisplayOptions &);
};
} // namespace GLtk