]> git.tdb.fi Git - libs/gltk.git/blob - source/dropdown.cpp
Prevent problems if a button press handler throws
[libs/gltk.git] / source / dropdown.cpp
1 /* $Id$
2
3 This file is part of libmspgltk
4 Copyright © 2007  Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <msp/gl/font.h>
9 #include "dropdown.h"
10 #include "list.h"
11 #include "panel.h"
12 #include "part.h"
13 #include "style.h"
14
15 using namespace std;
16
17 namespace Msp {
18 namespace GLtk {
19
20 Dropdown::Dropdown(const Resources &r):
21         Widget(r),
22         list(r),
23         dropped(false),
24         list_active(false)
25 {
26         list.signal_item_selected.connect(sigc::mem_fun(this, &Dropdown::list_item_selected));
27
28         update_style();
29 }
30
31 Dropdown::~Dropdown()
32 {
33 }
34
35 void Dropdown::append(const string &item)
36 {
37         list.append(item);
38         resize_list();
39 }
40
41 void Dropdown::insert(unsigned i, const string &v)
42 {
43         list.insert(i, v);
44         resize_list();
45 }
46
47 void Dropdown::remove(unsigned i)
48 {
49         list.remove(i);
50         resize_list();
51 }
52
53 void Dropdown::clear()
54 {
55         list.clear();
56         resize_list();
57 }
58
59 unsigned Dropdown::get_n_items() const
60 {
61         return list.get_n_items();
62 }
63
64 void Dropdown::set_selected_index(int i)
65 {
66         list.set_selected_index(i);
67 }
68
69 const string &Dropdown::get_selected() const
70 {
71         return list.get_selected();
72 }
73
74 int Dropdown::get_selected_index() const
75 {
76         return list.get_selected_index();
77 }
78
79 void Dropdown::button_press(int x, int y, unsigned btn)
80 {
81         if(list.get_geometry().is_inside(x, y))
82         {
83                 const Geometry &lgeom=list.get_geometry();
84                 list.button_press(x-lgeom.x, y-lgeom.y, btn);
85                 list_active=true;
86         }
87         else if(dropped)
88         {
89                 dropped=false;
90                 state&=~ACTIVE;
91                 parent->ungrab_pointer(*this);
92         }
93         else if(btn==1)
94         {
95                 dropped=true;
96                 state|=ACTIVE;
97
98                 if(parent)
99                 {
100                         parent->raise(*this);
101                         parent->grab_pointer(*this);
102                 }
103         }
104 }
105
106 void Dropdown::button_release(int x, int y, unsigned btn)
107 {
108         if(list_active)
109         {
110                 const Geometry &lgeom=list.get_geometry();
111                 list.button_release(x-lgeom.x, y-lgeom.y, btn);
112                 list_active=false;
113         }
114 }
115
116 void Dropdown::pointer_motion(int x, int y)
117 {
118         if(list_active)
119         {
120                 const Geometry &lgeom=list.get_geometry();
121                 list.pointer_motion(x-lgeom.x, y-lgeom.y);
122         }
123 }
124
125 void Dropdown::render_special(const Part &part) const
126 {
127         if(part.get_name()=="text")
128         {
129                 if(list.get_selected_index()>=0)
130                         render_text(part, list.get_selected());
131         }
132         else if(part.get_name()=="list" && dropped)
133                 list.render();
134 }
135
136 void Dropdown::on_geometry_change()
137 {
138         resize_list();
139 }
140
141 void Dropdown::resize_list()
142 {
143         // XXX This is a hack.
144         unsigned n_items=list.get_n_items();
145         const Style &stl=list.get_style();
146         const GL::Font &font=*stl.get_font();
147         unsigned h=min(max(n_items, 1U), 20U)*static_cast<unsigned>((font.get_ascent()-font.get_descent())*font.get_default_size());
148         for(std::list<Part>::const_iterator i=stl.get_parts().begin(); i!=stl.get_parts().end(); ++i)
149                 if(i->get_name()=="items")
150                 {
151                         const Sides &margin=i->get_margin();
152                         h+=margin.top+margin.bottom;
153                 }
154         list.set_geometry(Geometry(0, -h, geom.w, h));
155 }
156
157 void Dropdown::list_item_selected(unsigned index, const std::string &item)
158 {
159         if(dropped)
160         {
161                 list_active=false;
162                 dropped=false;
163                 state&=~ACTIVE;
164                 if(parent)
165                         parent->ungrab_pointer(*this);
166         }
167
168         signal_item_selected.emit(index, item);
169 }
170
171
172 Dropdown::Loader::Loader(Dropdown &d):
173         Widget::Loader(d)
174 {
175         add("item", &Loader::item);
176 }
177
178 void Dropdown::Loader::item(const string &str)
179 {
180         static_cast<Dropdown &>(wdg).append(str);
181 }
182
183 } // namespace GLtk
184 } // namespace Msp