]> git.tdb.fi Git - libs/gltk.git/commitdiff
Rework event passing system to allow for pointer grabs
authorMikko Rasa <tdb@tdb.fi>
Wed, 20 Jun 2007 20:30:07 +0000 (20:30 +0000)
committerMikko Rasa <tdb@tdb.fi>
Wed, 20 Jun 2007 20:30:07 +0000 (20:30 +0000)
Add Window class (incomplete)
Add width and height properties for Parts
move class Sides to geometry.h
Implement HSlider
Various improvements to the code

18 files changed:
source/button.cpp
source/button.h
source/geometry.cpp [new file with mode: 0644]
source/geometry.h
source/graphic.cpp
source/graphic.h
source/hslider.cpp
source/hslider.h
source/panel.cpp
source/panel.h
source/part.cpp
source/part.h
source/slider.cpp
source/slider.h
source/widget.cpp
source/widget.h
source/window.cpp [new file with mode: 0644]
source/window.h

index 243225964caa37752a8ee1979c398577f96482a8..2c8bedb17c17a34e45be58003caac18067e2d843 100644 (file)
@@ -16,46 +16,29 @@ void Button::set_text(const std::string &t)
        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
index 407e2f950bfb04424796aaf312f11c9c4a98e553..8bd2d315c26cb8439ad3cb9a5cd30a7162f7f7f3 100644 (file)
@@ -14,14 +14,14 @@ public:
 
        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
diff --git a/source/geometry.cpp b/source/geometry.cpp
new file mode 100644 (file)
index 0000000..d7a0756
--- /dev/null
@@ -0,0 +1,30 @@
+#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
index 7e59bd4936f7dc4f82797f9a97170532527b0a37..85e28161930841dfa1bb358b4489c16e888935f7 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef MSP_GLTK_GEOMETRY_H_
 #define MSP_GLTK_GEOMETRY_H_
 
+#include <msp/parser/loader.h>
+
 namespace Msp {
 namespace GLtk {
 
@@ -14,6 +16,29 @@ struct Geometry
 
        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
index 99defc7627a97749718dcefc4eed71964ae415e3..d05123ab890f0f342f858840f97f82cc4e68a6c0 100644 (file)
@@ -64,14 +64,6 @@ void Graphic::render(unsigned wd, unsigned ht) const
 }
 
 
-Graphic::Sides::Sides():
-       top(0),
-       right(0),
-       bottom(0),
-       left(0)
-{ }
-
-
 Graphic::Loader::Loader(Graphic &g):
        graph(g)
 {
@@ -102,15 +94,5 @@ 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
index 16d8cf406a006096e95fc31778136e6996384d2a..f4cc907223a3ea6fd9a009fefb0f4b0013bbd6f9 100644 (file)
@@ -26,25 +26,6 @@ public:
                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; }
index c1d334d3d3cbff366b37b59bae72ee63fbf7e40c..dda8b43168643a74825480c72e3017891adce8fd 100644 (file)
@@ -1,23 +1,76 @@
+#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
index 84a164e593a29b7bb824f23b7842f69946eed430..25ad0b19e597061f856496ade7e8d4085bfce92d 100644 (file)
@@ -10,11 +10,17 @@ class HSlider: public Slider
 {
 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
index b029057de9f7799dc64d36d86ea919dc2925eb7c..f6aad86a856d90aa0440ebb1f0634544a2b3f51b 100644 (file)
@@ -5,7 +5,9 @@ namespace Msp {
 namespace GLtk {
 
 Panel::Panel(const Resources &r):
-       Widget(r)
+       Widget(r),
+       pointer_focus(0),
+       pointer_grab(0)
 {
        update_style();
 }
@@ -16,6 +18,67 @@ Panel::~Panel()
                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);
@@ -32,16 +95,18 @@ void Panel::render_part(const Part &part) const
                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
index 7a94dcd0fdb5f02f8778afaebf1c6b298a2de418..31be7e57c1afb530c0ef58600d69c9e31110c12b 100644 (file)
@@ -11,18 +11,23 @@ class Panel: public Widget
 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
index 38e75d7c034d4526f08662ec732deb7d8493f83d..45449932618ec8a692b9b7cd5f20e275e0ad285d 100644 (file)
@@ -10,6 +10,8 @@ namespace GLtk {
 Part::Part(const Resources &r, const string &n):
        res(r),
        name(n),
+       width(1),
+       height(1),
        fill_x(true),
        fill_y(true)
 {
@@ -27,9 +29,8 @@ const Graphic *Part::get_graphic(State state) const
 
 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);
 }
@@ -43,17 +44,26 @@ Part::Loader::Loader(Part &p):
        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;
index b8761e6a8436e9cd9b5ab830cba49129c98c9228..08803dc5a7074b5d2ff71f8797f785603dc42d88 100644 (file)
@@ -20,6 +20,7 @@ public:
        {
        public:
                Loader(Part &);
+               ~Loader();
        private:
                Part &part;
 
@@ -31,6 +32,8 @@ public:
        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; }
@@ -39,6 +42,8 @@ private:
        const Resources &res;
        std::string name;
        const Graphic *graphic[N_STATES_];
+       unsigned width;
+       unsigned height;
        Alignment align;
        bool fill_x;
        bool fill_y;
index e7f67c111016cd87b3eb348883e4788292b1bb97..cb24c002b1a497bb5502f81bb566a434d5abd3c6 100644 (file)
@@ -23,6 +23,8 @@ void Slider::set_value(double v)
                unsigned steps=static_cast<unsigned>((v-min)/step+0.5);
                value=min+steps*step;
        }
+
+       signal_value_changed.emit(value);
 }
 
 } // namespace GLtk
index c88c15b9f10f84354db7a36465fb53019ecfb2b2..d4ae46b632040fe9b6fb8dd8c90a21a7a5125af8 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef MSP_GLTK_SLIDER_H_
 #define MSP_GLTK_SLIDER_H_
 
+#include <sigc++/sigc++.h>
 #include "widget.h"
 
 namespace Msp {
@@ -9,6 +10,8 @@ namespace GLtk {
 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);
@@ -18,7 +21,7 @@ protected:
        double value;
        double step;
 
-       Slider(const Resourcres &);
+       Slider(const Resources &);
 };
 
 } // namespace GLtk
index 48ae0eda4b042b3e4096a2d7f494d3ea77db2e44..e1aee846675d3b9e69e37b5d5039bd21f5baa92b 100644 (file)
@@ -44,28 +44,6 @@ void Widget::render() const
        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),
index f64e2ea08235c1a9f41e47059c813c3ce49acf30..322fbfa8a53f0b052ce94c45ab5fed847c7a6837 100644 (file)
@@ -22,9 +22,11 @@ public:
        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;
@@ -38,11 +40,6 @@ protected:
        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
diff --git a/source/window.cpp b/source/window.cpp
new file mode 100644 (file)
index 0000000..81f8ce1
--- /dev/null
@@ -0,0 +1,66 @@
+#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
index 13febaeea936dffc3d85c6d1fecfdb3ce25804ff..3990acf0ef4fe0b26af4d0e8ca29856df5b3ab34 100644 (file)
@@ -6,13 +6,30 @@
 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