Skip to content

Commit a8a80f7

Browse files
committed
Implementation of Selection widgets.
SelectionWidget SelectionBox including an Item class to add items to it. Some highlights: - Item class is the only one for now that is wrapped in a struct with additional metadata, in order to know if they are owned or not. - Item class can hold ruby objects as data, and ruby objects can directly be added to a SelectionWidget. For now a UI::Item is created setting the object in item.data. How to make it more transparent? I am undecided whether to make Item#method_missing forward to Item#data, or to make Item a module and extend the passed object with the methods.
1 parent ebf6431 commit a8a80f7

15 files changed

+778
-2
lines changed

ext/ui/callback_filter.cc

+5
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ YEvent * CallbackFilter::filter (YEvent * event)
2727
method = rb_intern("value_changed_fire");
2828
break;
2929
}
30+
case YEvent::SelectionChanged:
31+
{
32+
method = rb_intern("selection_changed_fire");
33+
break;
34+
}
3035
}
3136
if (NIL_P(method))
3237
return event;

ext/ui/item.cc

+292
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
#include <yui/YItem.h>
2+
#include "exception_guard.h"
3+
#include "widget.h"
4+
#include "item.h"
5+
6+
typedef struct
7+
{
8+
YItem *ptr;
9+
bool owned;
10+
} ItemWrapper;
11+
12+
static void
13+
dealloc(ItemWrapper *wrapper)
14+
{
15+
YEXCEPTION_TRY
16+
if (!wrapper->owned) {
17+
yuiDebug() << "unowned item, destroying...";
18+
delete wrapper->ptr;
19+
}
20+
delete wrapper;
21+
YEXCEPTION_CATCH
22+
}
23+
24+
static ItemWrapper *
25+
ui_item_wrapper(VALUE item)
26+
{
27+
ItemWrapper *wrapper = 0L;
28+
29+
Data_Get_Struct (item, ItemWrapper, wrapper);
30+
if (!wrapper)
31+
rb_raise(rb_eRuntimeError, "Item was already destroyed. Probably you destroyed its owning selection widget.");
32+
return wrapper;
33+
}
34+
35+
VALUE
36+
ui_wrap_item(YItem *item)
37+
{
38+
ItemWrapper *wrapper = new ItemWrapper;
39+
wrapper->ptr = item;
40+
wrapper->owned = false;
41+
return Data_Wrap_Struct(cUIItem, 0, dealloc, wrapper);
42+
}
43+
44+
YItem *
45+
ui_unwrap_item(VALUE item)
46+
{
47+
return ui_item_wrapper(item)->ptr;
48+
}
49+
50+
// fwd decl
51+
static VALUE set_data(VALUE self, VALUE data);
52+
53+
VALUE
54+
ui_object_to_item(VALUE object) {
55+
VALUE ui = rb_define_module("UI");
56+
if (rb_class_of(object) == rb_const_get(ui, rb_intern("Item")))
57+
return object;
58+
59+
VALUE label = rb_funcall(object, rb_intern("to_s"), 0);
60+
VALUE item = rb_funcall(cUIItem, rb_intern("new"), 1, label);
61+
set_data(item, object);
62+
return item;
63+
}
64+
65+
void
66+
ui_item_set_owned(VALUE object, bool owned)
67+
{
68+
ui_item_wrapper(object)->owned = owned;
69+
}
70+
71+
bool
72+
ui_item_is_owned(VALUE object)
73+
{
74+
return ui_item_wrapper(object)->owned;
75+
}
76+
77+
/*
78+
* @return [String] the item label
79+
*/
80+
static VALUE
81+
get_label(VALUE self)
82+
{
83+
YEXCEPTION_TRY
84+
YItem *ptr = ui_unwrap_item(self);
85+
return rb_str_new2(ptr->label().c_str());
86+
YEXCEPTION_CATCH
87+
}
88+
89+
/*
90+
* Set the item label
91+
*/
92+
static VALUE
93+
set_label(VALUE self, VALUE label)
94+
{
95+
YEXCEPTION_TRY
96+
YItem *ptr = ui_unwrap_item(self);
97+
ptr->setLabel(StringValueCStr(label));
98+
return label;
99+
YEXCEPTION_CATCH
100+
}
101+
102+
/*
103+
* @return [String] the item index
104+
*/
105+
static VALUE
106+
get_index(VALUE self)
107+
{
108+
YEXCEPTION_TRY
109+
YItem *ptr = ui_unwrap_item(self);
110+
return INT2NUM(ptr->index());
111+
YEXCEPTION_CATCH
112+
}
113+
114+
/*
115+
* Set the item index
116+
*/
117+
static VALUE
118+
set_index(VALUE self, VALUE index)
119+
{
120+
YEXCEPTION_TRY
121+
YItem *ptr = ui_unwrap_item(self);
122+
ptr->setIndex(NUM2INT(index));
123+
return index;
124+
YEXCEPTION_CATCH
125+
}
126+
127+
/*
128+
* @return [String] the 's' icon name
129+
*/
130+
static VALUE
131+
get_icon_name(VALUE self)
132+
{
133+
YEXCEPTION_TRY
134+
YItem *ptr = ui_unwrap_item(self);
135+
return rb_str_new2(ptr->iconName().c_str());
136+
YEXCEPTION_CATCH
137+
}
138+
139+
/*
140+
* Set the item's icon name
141+
*/
142+
static VALUE
143+
set_icon_name(VALUE self, VALUE icon)
144+
{
145+
YEXCEPTION_TRY
146+
YItem *ptr = ui_unwrap_item(self);
147+
ptr->setIconName(StringValueCStr(icon));
148+
return icon;
149+
YEXCEPTION_CATCH
150+
}
151+
152+
/*
153+
* @return [Object] the object associated with this item
154+
*/
155+
static VALUE
156+
get_data(VALUE self)
157+
{
158+
YEXCEPTION_TRY
159+
YItem *ptr = ui_unwrap_item(self);
160+
return ptr->data() ? ((VALUE) ptr->data()) : Qnil;
161+
YEXCEPTION_CATCH
162+
}
163+
164+
/*
165+
* Set the object associated with this item
166+
*/
167+
static VALUE
168+
set_data(VALUE self, VALUE data)
169+
{
170+
YEXCEPTION_TRY
171+
YItem *ptr = ui_unwrap_item(self);
172+
ptr->setData((void *) data);
173+
return data;
174+
YEXCEPTION_CATCH
175+
}
176+
177+
/*
178+
* @return [Boolean] True if the item is selected
179+
*/
180+
static VALUE
181+
get_selected(VALUE self)
182+
{
183+
YEXCEPTION_TRY
184+
YItem *ptr = ui_unwrap_item(self);
185+
return ptr->selected() ? Qtrue : Qfalse;
186+
YEXCEPTION_CATCH
187+
}
188+
189+
/*
190+
* Select or unselect this item. This does not have any effect on any other
191+
* item; if it is desired that only one item is selected at any time, the
192+
* caller has to take care of that.
193+
*
194+
* @param [Boolean] selected whether the item is selected or not
195+
*/
196+
static VALUE
197+
set_selected(VALUE self, VALUE selected)
198+
{
199+
YEXCEPTION_TRY
200+
YItem *ptr = ui_unwrap_item(self);
201+
ptr->setSelected(RTEST(selected));
202+
return selected;
203+
YEXCEPTION_CATCH
204+
}
205+
206+
static VALUE
207+
each_child(VALUE self)
208+
{
209+
YEXCEPTION_TRY
210+
YItem *ptr = ui_unwrap_item(self);
211+
212+
for (YItemConstIterator it = ptr->childrenBegin();
213+
it != ptr->childrenEnd();
214+
++it) {
215+
216+
YItem *child = *it;
217+
if (!child)
218+
continue;
219+
220+
VALUE rb_child = widget_object_map_for(child);
221+
if (!NIL_P(rb_child))
222+
rb_yield(rb_child);
223+
}
224+
YEXCEPTION_CATCH
225+
}
226+
227+
/*
228+
* @return [Item] the item's parent (or nil if the item has no parent)
229+
*/
230+
static VALUE
231+
get_parent(VALUE self)
232+
{
233+
YEXCEPTION_TRY
234+
YItem *ptr = ui_unwrap_item(self);
235+
return widget_object_map_for(ptr->parent());
236+
YEXCEPTION_CATCH
237+
}
238+
239+
static VALUE
240+
_new(int argc, VALUE *argv, VALUE klass)
241+
{
242+
YEXCEPTION_TRY
243+
244+
VALUE label;
245+
rb_scan_args(argc, argv, "10", &label);
246+
247+
YItem *item = new YItem(StringValueCStr(label));
248+
VALUE object = ui_wrap_item(item);
249+
250+
widget_object_map_add(item, object);
251+
rb_obj_call_init(object, argc, argv);
252+
return object;
253+
YEXCEPTION_CATCH
254+
}
255+
256+
/*
257+
* Initializes an item with label +label+
258+
*
259+
* @param [String] label initial label of the item
260+
*
261+
* @example
262+
* item = UI::Item.new("Orange")
263+
*/
264+
static VALUE
265+
initialize(int argc, VALUE *argv, VALUE self)
266+
{
267+
ui_item_set_owned(self, false);
268+
}
269+
270+
VALUE cUIItem;
271+
void init_ui_item()
272+
{
273+
VALUE ui = rb_define_module("UI");
274+
275+
VALUE klass = rb_define_class_under(ui, "Item", rb_cObject);
276+
rb_define_singleton_method(klass, "new", RUBY_METHOD_FUNC(_new), -1);
277+
rb_define_method(klass, "initialize", RUBY_METHOD_FUNC(initialize), -1);
278+
rb_define_method(klass, "label", RUBY_METHOD_FUNC(get_label), 0);
279+
rb_define_method(klass, "label=", RUBY_METHOD_FUNC(set_label), 1);
280+
rb_define_method(klass, "data", RUBY_METHOD_FUNC(get_data), 0);
281+
rb_define_method(klass, "data=", RUBY_METHOD_FUNC(set_data), 1);
282+
rb_define_method(klass, "index", RUBY_METHOD_FUNC(get_index), 0);
283+
rb_define_method(klass, "index=", RUBY_METHOD_FUNC(set_index), 1);
284+
rb_define_method(klass, "icon_name", RUBY_METHOD_FUNC(get_icon_name), 0);
285+
rb_define_method(klass, "icon_name=", RUBY_METHOD_FUNC(set_icon_name), 1);
286+
rb_define_method(klass, "selected?", RUBY_METHOD_FUNC(get_selected), 0);
287+
rb_define_method(klass, "selected=", RUBY_METHOD_FUNC(set_selected), 1);
288+
rb_define_method(klass, "each_child", RUBY_METHOD_FUNC(each_child), 0);
289+
rb_define_method(klass, "parent", RUBY_METHOD_FUNC(get_parent), 0);
290+
cUIItem = klass;
291+
}
292+

ext/ui/item.h

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#ifndef RUBY_NATIVE_UI_ITEM_H
2+
#define RUBY_NATIVE_UI_ITEM_H
3+
4+
#include <yui/YItem.h>
5+
#include "ui.h"
6+
7+
void init_ui_item();
8+
9+
extern VALUE cUIItem;
10+
VALUE ui_wrap_item(YItem *item);
11+
YItem * ui_unwrap_item(VALUE item);
12+
13+
// mark an item as owned/unowned by a SelectionWidget
14+
// so that we know if we need to delete the backing
15+
// pointer later or the SelectionWidget will take care
16+
// of it.
17+
void ui_item_set_owned(VALUE object, bool owned);
18+
19+
// true is this item is owned by a SelectionWidget
20+
bool ui_item_is_owned(VALUE object);
21+
22+
// converts a ruby object to an item
23+
// if the object is an UI::Item already
24+
// the same is returned. Otherwise
25+
// an item with same label as obj.to_s
26+
// is created.
27+
VALUE ui_object_to_item(VALUE object);
28+
29+
#endif

ext/ui/selection_box.cc

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#include "widget.h"
2+
#include "exception_guard.h"
3+
#include "selection_widget.h"
4+
#include "selection_box.h"
5+
6+
static void
7+
dealloc(YSelectionBox *box)
8+
{
9+
widget_object_map_remove(box);
10+
}
11+
12+
VALUE
13+
ui_wrap_selection_box(YSelectionBox *box)
14+
{
15+
return Data_Wrap_Struct(cUISelectionBox, ui_selection_widget_mark, dealloc, box);
16+
}
17+
18+
YSelectionBox *
19+
ui_unwrap_selection_box(VALUE box)
20+
{
21+
YSelectionBox *ptr = 0L;
22+
Data_Get_Struct(box, YSelectionBox, ptr);
23+
return ptr;
24+
}
25+
26+
VALUE cUISelectionBox;
27+
void init_ui_selection_box()
28+
{
29+
VALUE ui = rb_define_module("UI");
30+
31+
VALUE klass = rb_define_class_under(ui, "SelectionBox", cUISelectionWidget);
32+
cUISelectionBox = klass;
33+
}
34+

ext/ui/selection_box.h

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#ifndef RUBY_NATIVE_UI_SELECTION_BOX_H
2+
#define RUBY_NATIVE_UI_SELECTION_BOX_H
3+
4+
#include <yui/YSelectionBox.h>
5+
#include "ui.h"
6+
7+
void init_ui_selection_box();
8+
9+
extern VALUE cUISelectionBox;
10+
VALUE ui_wrap_selection_box(YSelectionBox *btn);
11+
12+
#endif

0 commit comments

Comments
 (0)