Add a version of gtk.init() that works with D strings directly.
[girtod.git] / example_gtk3.d
blob9e574b9f097993814ae01b78e30c7311b7a351e2
1 import gtk = gtk2.gtk2;
3 int main(string argv[]) {
4 argv = gtk.init(argv);
6 auto window = new AppWin();
7 window.show_all();
9 gtk.main_();
10 return 0;
13 struct AppWin {
14 gtk.Window* window;
15 alias window this;
17 this(...) {
18 window = gtk.Window.new_(gtk.WindowType.TOPLEVEL);
20 set_title(cast(char*)"Hello World!");
21 set_default_size(200, 128);
23 this.signal_connect!"delete-event"(&delete_cb);
25 auto vbox = gtk.VBox.new_(0, 0);
26 auto disp = gtk.Entry.new_();
27 vbox.add(&disp.widget);
28 vbox.set_child_packing(&disp.widget, 0, 1, 0, gtk.PackType.START);
30 auto calc = new Calculator(disp);
32 auto keypad = new Keypad(calc);
33 vbox.add(&keypad.widget);
35 add(&vbox.widget);
38 static extern (C) int delete_cb(gtk.Widget* this_, gtk.Event* event, void* user_data) {
39 gtk.exit(0);
40 return 0;
45 // A custom widget, composited out of many std buttons:
47 struct Keypad {
48 gtk.Table* table;
49 alias table this;
51 // D lets us "magically" inherit the GTK object, but the "parent"
52 // widget has no idea about our pseudo-derived class. We keep a
53 // mapping from gtk-widgets to instances of this object;
54 // This also allows us to "cheat" and eg. redirect child widget
55 // callbacks directly to this "class".
56 static Keypad*[gtk.Widget*] widget2this;
58 Calculator* calc;
60 enum colnum=5, rownum=4;
61 static immutable string[colnum][rownum] labels = [
62 ["7", "8", "9", "/", "C"],
63 ["4", "5", "6", "*", ""],
64 ["1", "2", "3", "-", ""],
65 ["0", ".", "=", "+", ""]
68 this(Calculator* calc) {
69 this.calc = calc;
71 table = gtk.Table.new_(colnum, rownum, 0);
73 set_border_width(2);
74 set_row_spacings(4);
75 set_col_spacings(4);
77 foreach (y, labelrow; labels)
78 foreach (x, label; labelrow) {
79 auto but = gtk.Button.new_with_label(cast(char*)label);
80 but.signal_connect!"button-press-event"(&bpress_cb, cast(void*)label);
81 widget2this[&but.widget] = &this;
82 attach_defaults(&but.widget, x, x+1, y, y+1);
86 static extern (C) int bpress_cb(gtk.Widget* this_, gtk.Gdk2.EventButton* event, void* user_data) {
87 gtk._dumpObj(event);
88 if (event.type==gtk.EventType.BUTTON_PRESS && event.button==1)
89 widget2this[this_].calc.key(cast(immutable char*)user_data);
90 return 0;
94 // The code sitting between the keypad and the display:
96 // NOTE: The "diplay" could be another custom widget, just like the
97 // keypad, but to keep this example simple we'll use a gtk.Entry
98 // directly.
100 struct Calculator {
101 double v = 0, pv = 0;
102 string display_string;
103 char* str0;
104 bool entering, haveprev;
105 char pop;
107 gtk.Entry* disp;
109 import std.conv;
111 void update() {
112 import std.string;
113 str0 = cast(char*)toStringz(display_string);
114 disp.set_text(str0);
117 this(typeof(disp) disp) {
118 this.disp = disp;
119 disp.set_alignment(1);
121 clear();
122 update();
125 void oper(char op) {
126 if (!entering && op==pop)
127 return;
128 entering = 0;
129 if (!haveprev) {
130 pv = v;
131 display_string = null;
132 v = 0;
133 haveprev = 1;
134 pop = op;
135 return;
137 switch (pop) {
138 case '+': v = pv + v; break;
139 case '-': v = pv - v; break;
140 case '*': v = pv * v; break;
141 case '/': v = pv / v; break;
142 case '=': break;
143 default: assert(0);
145 display_string = to!string(v);
146 pv = v;
147 pop = op;
150 void clear() { v = 0; pv = 0; display_string = null; haveprev = 0; entering = 0; pop = 0; }
152 void key(immutable char* key) {
153 if (key[1]==0) {
154 char k = key[0];
155 switch (k) {
156 case '0': .. case '9': case '.':
157 if (entering) {
158 display_string ~= k;
159 try {
160 v = to!double(display_string);
162 catch {
163 display_string = display_string[0..$-1];
164 v = to!double(display_string);
167 else {
168 display_string = (k=='.') ? "0." : key[0..1];
169 v = to!double(display_string);
170 entering = 1;
172 break;
173 case '+', '-', '*', '/', '=': oper(k); break;
174 case 'C': clear();
176 update();