From c062ca892fc6e10f74a76991b5d4b4349c046b5f Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Wed, 20 Jun 2007 20:30:07 +0000 Subject: [PATCH] Rework event passing system to allow for pointer grabs Add Window class (incomplete) Add width and height properties for Parts move class Sides to geometry.h Implement HSlider Various improvements to the code --- source/button.cpp | 45 ++++++++---------------- source/button.h | 4 +-- source/geometry.cpp | 30 ++++++++++++++++ source/geometry.h | 25 ++++++++++++++ source/graphic.cpp | 18 ---------- source/graphic.h | 19 ----------- source/hslider.cpp | 65 +++++++++++++++++++++++++++++++---- source/hslider.h | 12 +++++-- source/panel.cpp | 83 ++++++++++++++++++++++++++++++++++++++++----- source/panel.h | 9 +++-- source/part.cpp | 28 ++++++++++----- source/part.h | 5 +++ source/slider.cpp | 2 ++ source/slider.h | 5 ++- source/widget.cpp | 22 ------------ source/widget.h | 13 +++---- source/window.cpp | 66 +++++++++++++++++++++++++++++++++++ source/window.h | 21 ++++++++++-- 18 files changed, 340 insertions(+), 132 deletions(-) create mode 100644 source/geometry.cpp create mode 100644 source/window.cpp diff --git a/source/button.cpp b/source/button.cpp index 2432259..2c8bedb 100644 --- a/source/button.cpp +++ b/source/button.cpp @@ -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(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) + 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(geom.w) && y(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 diff --git a/source/button.h b/source/button.h index 407e2f9..8bd2d31 100644 --- a/source/button.h +++ b/source/button.h @@ -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 index 0000000..d7a0756 --- /dev/null +++ b/source/geometry.cpp @@ -0,0 +1,30 @@ +#include "geometry.h" + +namespace Msp { +namespace GLtk { + +bool Geometry::is_inside(int x_, int y_) const +{ + return (x_>=x && x_(w) && y_>=y && y_(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 diff --git a/source/geometry.h b/source/geometry.h index 7e59bd4..85e2816 100644 --- a/source/geometry.h +++ b/source/geometry.h @@ -1,6 +1,8 @@ #ifndef MSP_GLTK_GEOMETRY_H_ #define MSP_GLTK_GEOMETRY_H_ +#include + 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 diff --git a/source/graphic.cpp b/source/graphic.cpp index 99defc7..d05123a 100644 --- a/source/graphic.cpp +++ b/source/graphic.cpp @@ -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 diff --git a/source/graphic.h b/source/graphic.h index 16d8cf4..f4cc907 100644 --- a/source/graphic.h +++ b/source/graphic.h @@ -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; } diff --git a/source/hslider.cpp b/source/hslider.cpp index c1d334d..dda8b43 100644 --- a/source/hslider.cpp +++ b/source/hslider.cpp @@ -1,23 +1,76 @@ +#include +#include +#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((geom.w-sw)*(value-min)/(max-min)); + if(btn==1 && x>=sx && xget_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 diff --git a/source/hslider.h b/source/hslider.h index 84a164e..25ad0b1 100644 --- a/source/hslider.h +++ b/source/hslider.h @@ -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 diff --git a/source/panel.cpp b/source/panel.cpp index b029057..f6aad86 100644 --- a/source/panel.cpp +++ b/source/panel.cpp @@ -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 diff --git a/source/panel.h b/source/panel.h index 7a94dcd..31be7e5 100644 --- a/source/panel.h +++ b/source/panel.h @@ -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 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 diff --git a/source/part.cpp b/source/part.cpp index 38e75d7..4544993 100644 --- a/source/part.cpp +++ b/source/part.cpp @@ -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; iget_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; diff --git a/source/part.h b/source/part.h index b8761e6..08803dc 100644 --- a/source/part.h +++ b/source/part.h @@ -20,6 +20,7 @@ public: { public: Loader(Part &); + ~Loader(); private: 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; diff --git a/source/slider.cpp b/source/slider.cpp index e7f67c1..cb24c00 100644 --- a/source/slider.cpp +++ b/source/slider.cpp @@ -23,6 +23,8 @@ void Slider::set_value(double v) unsigned steps=static_cast((v-min)/step+0.5); value=min+steps*step; } + + signal_value_changed.emit(value); } } // namespace GLtk diff --git a/source/slider.h b/source/slider.h index c88c15b..d4ae46b 100644 --- a/source/slider.h +++ b/source/slider.h @@ -1,6 +1,7 @@ #ifndef MSP_GLTK_SLIDER_H_ #define MSP_GLTK_SLIDER_H_ +#include #include "widget.h" namespace Msp { @@ -9,6 +10,8 @@ namespace GLtk { class Slider: public Widget { public: + sigc::signal 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 diff --git a/source/widget.cpp b/source/widget.cpp index 48ae0ed..e1aee84 100644 --- a/source/widget.cpp +++ b/source/widget.cpp @@ -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.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), diff --git a/source/widget.h b/source/widget.h index f64e2ea..322fbfa 100644 --- a/source/widget.h +++ b/source/widget.h @@ -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 index 0000000..81f8ce1 --- /dev/null +++ b/source/window.cpp @@ -0,0 +1,66 @@ +#include +#include +#include +#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 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 diff --git a/source/window.h b/source/window.h index 13febae..3990acf 100644 --- a/source/window.h +++ b/source/window.h @@ -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 -- 2.43.0