Restore full UpCast functionality, this time w/o the runtime cost.
[girtod.git] / example_gtk.d
bloba0c89be0e3262ea3ef286f70e61923a70b43246a
1 import std.string;
2 import gtk = gtk2.gtk2;
4 int main(string argv[]) {
5 argv = gtk.init(argv);
7 auto window = new AppWin("Hello World!");
8 window.show_all();
10 gtk.main_();
11 return 0;
12 }
14 struct AppWin {
15 gtk.Window* window;
16 alias window this;
18 this(string name) {
19 window = gtk.Window(gtk.WindowType.TOPLEVEL);
21 set_title(name);
22 set_default_size(200, 128);
24 this.signal_connect!"delete-event"(&delete_cb);
26 auto vbox = gtk.VBox(0, 0);
27 auto disp = gtk.Entry();
28 vbox.add(disp);
29 vbox.set_child_packing(disp, 0, 1, 0, gtk.PackType.START);
31 auto calc = new Calculator(disp);
33 auto keypad = new Keypad(calc);
34 vbox.add(keypad);
36 add(vbox);
37 }
39 static extern (C) int delete_cb(gtk.Widget* this_, gtk.Event* event, void* user_data) nothrow {
40 gtk.exit(0);
41 return 0;
42 }
44 }
46 // A custom widget, composited out of many std buttons:
48 struct Keypad {
49 gtk.Table* table;
50 alias table this;
52 // D lets us "magically" inherit the GTK object, but the "parent"
53 // widget has no idea about our pseudo-derived class. We keep a
54 // mapping from gtk-widgets to instances of this object;
55 // This also allows us to "cheat" and eg. redirect child widget
56 // callbacks directly to this "class".
57 static Keypad*[gtk.Widget*] widget2this;
59 Calculator* calc;
61 enum colnum=5, rownum=4;
62 static immutable string[colnum][rownum] labels = [
63 ["7", "8", "9", "/", "C"],
64 ["4", "5", "6", "*", ""],
65 ["1", "2", "3", "-", ""],
66 ["0", ".", "=", "+", ""]
67 ];
69 this(Calculator* calc) {
70 this.calc = calc;
72 table = gtk.Table(colnum, rownum, 0);
74 set_border_width(2);
75 set_row_spacings(4);
76 set_col_spacings(4);
78 foreach (gtk.c_uint y, labelrow; labels)
79 foreach (gtk.c_uint x, label; labelrow) {
80 auto button = gtk.Button.new_with_label(label);
81 button.signal_connect!"button-press-event"(&bpress_cb, cast(void*)label);
82 widget2this[&button.widget] = &this;
83 attach_defaults(button, x, x+1, y, y+1);
84 }
85 }
87 static extern (C) int bpress_cb(gtk.Widget* this_, gtk.Gdk2.EventButton* event,
88 void* user_data) nothrow {
89 gtk._dumpObj(event);
90 if (event.type==gtk.EventType.BUTTON_PRESS && event.button==1)
91 widget2this[this_].calc.key(cast(immutable char*)user_data);
92 return 0;
93 }
94 }
96 // The code sitting between the keypad and the display:
97 //
98 // NOTE: The "display" could be another custom widget, just like the
99 // keypad, but to keep this example simple we'll use a gtk.Entry
100 // directly.
102 struct Calculator {
103 double v = 0, pv = 0;
104 string display_string;
105 char* str0;
106 bool entering, haveprev;
107 char pop;
109 gtk.Entry* disp;
111 import std.conv;
113 nothrow:
115 void update() {
116 str0 = cast(char*)toStringz(display_string);
117 disp.set_text(str0);
120 this(typeof(disp) disp) {
121 this.disp = disp;
122 disp.set_alignment(1);
124 clear();
125 update();
128 private static DT ntto(DT, ST)(ST d) {
129 DT s;
130 try
131 s = to!DT(d);
132 catch (Exception e)
133 {}
134 return s;
137 void oper(char op) {
138 if (!entering && op==pop)
139 return;
140 entering = 0;
141 if (!haveprev) {
142 pv = v;
143 display_string = null;
144 v = 0;
145 haveprev = 1;
146 pop = op;
147 return;
149 switch (pop) {
150 case '+': v = pv + v; break;
151 case '-': v = pv - v; break;
152 case '*': v = pv * v; break;
153 case '/': v = pv / v; break;
154 case '=': break;
155 default: assert(0);
157 display_string = ntto!string(v);
158 pv = v;
159 pop = op;
162 void clear() { v = 0; pv = 0; display_string = null; haveprev = 0; entering = 0; pop = 0; }
164 void key(immutable char* key) {
165 if (key[1]==0) {
166 char k = key[0];
167 switch (k) {
168 case '0': .. case '9': case '.':
169 if (entering) {
170 display_string ~= k;
171 try {
172 v = to!double(display_string);
174 catch {
175 display_string = display_string[0..$-1];
176 v = ntto!double(display_string);
179 else {
180 display_string = (k=='.') ? "0." : key[0..1];
181 v = ntto!double(display_string);
182 entering = 1;
184 break;
185 case '+', '-', '*', '/', '=': oper(k); break;
186 case 'C': clear();
188 update();