]> git.tdb.fi Git - libs/gltk.git/blob - source/dropdown.cpp
Add a signal to notify when the automatic size of a widget changes
[libs/gltk.git] / source / dropdown.cpp
1 /* $Id$
2
3 This file is part of libmspgltk
4 Copyright © 2007-2011  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 "root.h"
14 #include "style.h"
15 #include "text.h"
16
17 using namespace std;
18
19 namespace Msp {
20 namespace GLtk {
21
22 Dropdown::Dropdown():
23         dropped(false)
24 {
25         add(list);
26         list.signal_item_selected.connect(sigc::mem_fun(this, &Dropdown::list_item_selected));
27         list.signal_autosize_changed.connect(sigc::mem_fun(this, &Dropdown::list_autosize_changed));
28 }
29
30 void Dropdown::autosize()
31 {
32         if(!style)
33                 return;
34
35         Widget::autosize();
36         geom.w = max(geom.w, list.get_geometry().w);
37
38         if(const Part *text_part = style->get_part("text"))
39         {
40                 const Sides &margin = text_part->get_margin();
41                 const GL::Font *font = style->get_font();
42                 float font_size = font->get_default_size();
43                 unsigned line_height = static_cast<unsigned>((font->get_ascent()-font->get_descent())*font_size);
44                 geom.h = max(geom.h, line_height+margin.top+margin.bottom);
45         }
46 }
47
48 void Dropdown::append(const string &item)
49 {
50         list.append(item);
51 }
52
53 void Dropdown::insert(unsigned i, const string &v)
54 {
55         list.insert(i, v);
56 }
57
58 void Dropdown::remove(unsigned i)
59 {
60         list.remove(i);
61 }
62
63 void Dropdown::clear()
64 {
65         list.clear();
66 }
67
68 unsigned Dropdown::get_n_items() const
69 {
70         return list.get_n_items();
71 }
72
73 void Dropdown::set_selected_index(int i)
74 {
75         list.set_selected_index(i);
76 }
77
78 const string &Dropdown::get_selected() const
79 {
80         return list.get_selected();
81 }
82
83 int Dropdown::get_selected_index() const
84 {
85         return list.get_selected_index();
86 }
87
88 void Dropdown::render_special(const Part &part) const
89 {
90         if(part.get_name()=="text")
91         {
92                 if(list.get_selected_index()>=0)
93                         Text(*style, list.get_selected()).render(part, geom);
94         }
95         else if(part.get_name()=="list" && dropped)
96                 list.render();
97 }
98
99 void Dropdown::button_press(int x, int y, unsigned btn)
100 {
101         if(dropped)
102         {
103                 Container::button_press(x, y, btn);
104                 if(!click_focus)
105                 {
106                         dropped = false;
107                         state &= ~ACTIVE;
108                         signal_ungrab_pointer.emit();
109                 }
110         }
111         else if(btn==1)
112         {
113                 dropped = true;
114                 state |= ACTIVE;
115                 signal_grab_pointer.emit();
116         }
117 }
118
119 void Dropdown::on_geometry_change()
120 {
121         resize_list();
122 }
123
124 void Dropdown::on_style_change()
125 {
126         resize_list();
127 }
128
129 void Dropdown::list_autosize_changed()
130 {
131         resize_list();
132         signal_autosize_changed.emit();
133 }
134
135 void Dropdown::resize_list()
136 {
137         list.autosize_all();
138         Geometry lgeom = list.get_geometry();
139         lgeom.x = 0;
140         lgeom.y = -lgeom.h;
141         lgeom.w = max(geom.w, lgeom.w);
142         int root_x = geom.x;
143         int root_y = geom.y;
144         for(Widget *p=parent; p; p=p->get_parent())
145         {
146                 root_x += p->get_geometry().x;
147                 root_y += p->get_geometry().y;
148                 if(Root *root = dynamic_cast<Root *>(p))
149                 {
150                         const Geometry &rgeom = root->get_geometry();
151                         if(lgeom.h*2>rgeom.h)
152                                 lgeom.h = rgeom.h/2;
153                         if(root_y+lgeom.y<0)
154                                 lgeom.y = -root_y;
155                         if(root_y+lgeom.y+lgeom.h>rgeom.h)
156                                 lgeom.y = rgeom.h-lgeom.h-root_y;
157                         if(root_x+lgeom.x+lgeom.w>rgeom.w)
158                                 lgeom.x = rgeom.w-lgeom.w-root_x;
159                         break;
160                 }
161         }
162         list.set_geometry(lgeom);
163 }
164
165 void Dropdown::list_item_selected(unsigned index, const std::string &item)
166 {
167         if(dropped)
168         {
169                 dropped = false;
170                 state &= ~ACTIVE;
171                 signal_ungrab_pointer.emit();
172         }
173
174         signal_item_selected.emit(index, item);
175 }
176
177
178 Dropdown::Loader::Loader(Dropdown &d):
179         Widget::Loader(d)
180 {
181         add("item", &Loader::item);
182 }
183
184 void Dropdown::Loader::item(const string &str)
185 {
186         dynamic_cast<Dropdown &>(obj).append(str);
187 }
188
189 } // namespace GLtk
190 } // namespace Msp