Initial commit
[girtod.git] / example_gtk3.d
blob569aa02398b7468af51e76f6390eb53d8da676e1
1 import gtk = gtk2.gtk2;
3 int main(string argv[]) {
4 gtk.init(null,null);
6 auto win = new AppWin();
7 win.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);
72 table.set_border_width(2);
73 table.set_row_spacings(4);
74 table.set_col_spacings(4);
76 foreach (y, labelrow; labels)
77 foreach (x, label; labelrow) {
78 auto but = gtk.Button.new_with_label(cast(char*)label);
79 but.signal_connect!"button-press-event"(&bpress_cb, cast(void*)label);
80 widget2this[&but.widget] = &this;
81 attach_defaults(&but.widget, x, x+1, y, y+1);
85 static extern (C) int bpress_cb(gtk.Widget* this_, gtk.Gdk2.EventButton* event, void* user_data) {
86 gtk._dumpobj(event);
87 if (event.type==gtk.EventType.BUTTON_PRESS && event.button==1)
88 widget2this[this_].calc.key(cast(immutable char*)user_data);
89 return 0;
93 // The code sitting between the keypad and the display:
95 // NOTE: The "diplay" could be another custom widget, just like the
96 // keypad, but to keep this example simple we'll use a gtk.Entry
97 // directly.
99 struct Calculator {
100 double v = 0, pv = 0;
101 string display_string;
102 char* str0;
103 bool entering, haveprev;
104 char pop;
106 gtk.Entry* disp;
108 import std.conv;
110 void update() {
111 import std.string;
112 str0 = cast(char*)toStringz(display_string);
113 disp.set_text(str0);
116 this(typeof(disp) disp) {
117 this.disp = disp;
118 disp.set_alignment(1);
120 clear();
121 update();
124 void oper(char op) {
125 if (!entering && op==pop)
126 return;
127 entering = 0;
128 if (!haveprev) {
129 pv = v;
130 display_string = null;
131 v = 0;
132 haveprev = 1;
133 pop = op;
134 return;
136 switch (pop) {
137 case '+': v = pv + v; break;
138 case '-': v = pv - v; break;
139 case '*': v = pv * v; break;
140 case '/': v = pv / v; break;
141 case '=': break;
142 default: assert(0);
144 display_string = to!string(v);
145 pv = v;
146 pop = op;
149 void clear() { v = 0; pv = 0; display_string = null; haveprev = 0; entering = 0; pop = 0; }
151 void key(immutable char* key) {
152 if (key[1]==0) {
153 char k = key[0];
154 switch (k) {
155 case '0': .. case '9': case '.':
156 if (entering) {
157 display_string ~= k;
158 try {
159 v = to!double(display_string);
161 catch {
162 display_string = display_string[0..$-1];
163 v = to!double(display_string);
166 else {
167 display_string = (k=='.') ? "0." : key[0..1];
168 v = to!double(display_string);
169 entering = 1;
171 break;
172 case '+', '-', '*', '/', '=': oper(k); break;
173 case 'C': clear();
175 update();