1 /* Toy calculator from example 02 turned into a reusable widget.
2 * - by Richard W.M. Jones <rich@annexia.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 * $Id: toy_calculator.c,v 1.3 2002/11/07 10:49:01 rich Exp $
28 #include "ml_window.h"
29 #include "ml_table_layout.h"
30 #include "ml_text_label.h"
32 #include "ml_button.h"
33 #include "ml_widget.h"
35 #include "toy_calculator.h"
37 static void repaint (void *, ml_session, const char *, io_handle);
39 struct ml_widget_operations toy_calculator_ops =
46 struct ml_widget_operations *ops;
47 pool pool; /* Pool for allocations. */
48 ml_text_label disp; /* The display. */
49 char digits[16]; /* Display digits (only 10+1 used). */
50 double reg; /* Hidden register. */
51 int op; /* Operation: PLUS, MINUS, TIMES, DIVIDE. */
52 ml_box box; /* The top-level box. */
55 /* Lots of callback functions for each button. */
56 static void press_button_0 (ml_session, void *);
57 static void press_button_1 (ml_session, void *);
58 static void press_button_2 (ml_session, void *);
59 static void press_button_3 (ml_session, void *);
60 static void press_button_4 (ml_session, void *);
62 static void press_button_5 (ml_session, void *);
63 static void press_button_6 (ml_session, void *);
64 static void press_button_7 (ml_session, void *);
65 static void press_button_8 (ml_session, void *);
66 static void press_button_9 (ml_session, void *);
68 static void press_button_DOT (ml_session, void *);
69 static void press_button_EQUALS (ml_session, void *);
70 static void press_button_PLUS (ml_session, void *);
71 static void press_button_MINUS (ml_session, void *);
72 static void press_button_TIMES (ml_session, void *);
73 static void press_button_DIVIDE (ml_session, void *);
74 static void press_button_CLEAR (ml_session, void *);
75 static void press_button_AC (ml_session, void *);
77 /* These are used as indexes in the b[] array. */
88 new_toy_calculator (pool pool, ml_session session)
96 w = pmalloc (pool, sizeof *w);
97 w->ops = &toy_calculator_ops;
99 strcpy (w->digits, "0");
103 /* Create the box surrounding the calculator. */
104 box = new_ml_box (pool);
106 /* A table layout widget is used to arrange the buttons and the screen.
107 * There are 6 rows, each with 4 columns.
109 tbl = new_ml_table_layout (pool, 6, 4);
111 /* Create the numeric buttons. */
112 b[0] = new_ml_button (pool, "0");
113 ml_button_set_callback (b[0], press_button_0, session, w);
114 ml_widget_set_property (b[0], "button.style", "key");
115 b[1] = new_ml_button (pool, "1");
116 ml_button_set_callback (b[1], press_button_1, session, w);
117 ml_widget_set_property (b[1], "button.style", "key");
118 b[2] = new_ml_button (pool, "2");
119 ml_button_set_callback (b[2], press_button_2, session, w);
120 ml_widget_set_property (b[2], "button.style", "key");
121 b[3] = new_ml_button (pool, "3");
122 ml_button_set_callback (b[3], press_button_3, session, w);
123 ml_widget_set_property (b[3], "button.style", "key");
124 b[4] = new_ml_button (pool, "4");
125 ml_button_set_callback (b[4], press_button_4, session, w);
126 ml_widget_set_property (b[4], "button.style", "key");
128 b[5] = new_ml_button (pool, "5");
129 ml_button_set_callback (b[5], press_button_5, session, w);
130 ml_widget_set_property (b[5], "button.style", "key");
131 b[6] = new_ml_button (pool, "6");
132 ml_button_set_callback (b[6], press_button_6, session, w);
133 ml_widget_set_property (b[6], "button.style", "key");
134 b[7] = new_ml_button (pool, "7");
135 ml_button_set_callback (b[7], press_button_7, session, w);
136 ml_widget_set_property (b[7], "button.style", "key");
137 b[8] = new_ml_button (pool, "8");
138 ml_button_set_callback (b[8], press_button_8, session, w);
139 ml_widget_set_property (b[8], "button.style", "key");
140 b[9] = new_ml_button (pool, "9");
141 ml_button_set_callback (b[9], press_button_9, session, w);
142 ml_widget_set_property (b[9], "button.style", "key");
144 /* Create the other buttons. */
145 b[DOT] = new_ml_button (pool, ".");
146 ml_button_set_callback (b[DOT], press_button_DOT, session, w);
147 ml_widget_set_property (b[DOT], "button.style", "key");
148 b[EQUALS] = new_ml_button (pool, "=");
149 ml_button_set_callback (b[EQUALS], press_button_EQUALS, session, w);
150 ml_widget_set_property (b[EQUALS], "button.style", "key");
151 b[PLUS] = new_ml_button (pool, "+");
152 ml_button_set_callback (b[PLUS], press_button_PLUS, session, w);
153 ml_widget_set_property (b[PLUS], "button.style", "key");
154 b[MINUS] = new_ml_button (pool, "-");
155 ml_button_set_callback (b[MINUS], press_button_MINUS, session, w);
156 ml_widget_set_property (b[MINUS], "button.style", "key");
157 b[TIMES] = new_ml_button (pool, "x");
158 ml_button_set_callback (b[TIMES], press_button_TIMES, session, w);
159 ml_widget_set_property (b[TIMES], "button.style", "key");
160 b[DIVIDE] = new_ml_button (pool, "/");
161 ml_button_set_callback (b[DIVIDE], press_button_DIVIDE, session, w);
162 ml_widget_set_property (b[DIVIDE], "button.style", "key");
163 b[CLEAR] = new_ml_button (pool, "C");
164 ml_button_set_callback (b[CLEAR], press_button_CLEAR, session, w);
165 ml_widget_set_property (b[CLEAR], "button.style", "key");
166 b[AC] = new_ml_button (pool, "AC");
167 ml_button_set_callback (b[AC], press_button_AC, session, w);
169 /* Create the display. */
170 disp = new_ml_text_label (pool, "0");
171 ml_widget_set_property (disp, "font.weight", "bold");
172 ml_widget_set_property (disp, "font.size", "large");
174 /* Pack the buttons and display into the table layout widget. */
175 ml_table_layout_pack (tbl, disp, 0, 0);
176 ml_table_layout_set_colspan (tbl, 0, 0, 4);
177 ml_table_layout_set_align (tbl, 0, 0, "right");
179 ml_table_layout_pack (tbl, b[CLEAR], 1, 2);
180 ml_table_layout_pack (tbl, b[AC], 1, 3);
182 ml_table_layout_pack (tbl, b[7], 2, 0);
183 ml_table_layout_pack (tbl, b[8], 2, 1);
184 ml_table_layout_pack (tbl, b[9], 2, 2);
185 ml_table_layout_pack (tbl, b[DIVIDE], 2, 3);
187 ml_table_layout_pack (tbl, b[4], 3, 0);
188 ml_table_layout_pack (tbl, b[5], 3, 1);
189 ml_table_layout_pack (tbl, b[6], 3, 2);
190 ml_table_layout_pack (tbl, b[TIMES], 3, 3);
192 ml_table_layout_pack (tbl, b[1], 4, 0);
193 ml_table_layout_pack (tbl, b[2], 4, 1);
194 ml_table_layout_pack (tbl, b[3], 4, 2);
195 ml_table_layout_pack (tbl, b[MINUS], 4, 3);
197 ml_table_layout_pack (tbl, b[DOT], 5, 0);
198 ml_table_layout_pack (tbl, b[0], 5, 1);
199 ml_table_layout_pack (tbl, b[EQUALS], 5, 2);
200 ml_table_layout_pack (tbl, b[PLUS], 5, 3);
202 /* Pack the table into the box. */
203 ml_box_pack (box, tbl);
205 /* Save the display widget in the widget structure so that the
206 * callback functions can update it.
210 /* Save the box, so we can repaint. */
216 static void press_button_N (toy_calculator, int);
219 press_button_0 (ml_session session, void *vw)
221 toy_calculator w = (toy_calculator) vw;
223 press_button_N (w, 0);
227 press_button_1 (ml_session session, void *vw)
229 toy_calculator w = (toy_calculator) vw;
231 press_button_N (w, 1);
235 press_button_2 (ml_session session, void *vw)
237 toy_calculator w = (toy_calculator) vw;
239 press_button_N (w, 2);
243 press_button_3 (ml_session session, void *vw)
245 toy_calculator w = (toy_calculator) vw;
247 press_button_N (w, 3);
251 press_button_4 (ml_session session, void *vw)
253 toy_calculator w = (toy_calculator) vw;
255 press_button_N (w, 4);
259 press_button_5 (ml_session session, void *vw)
261 toy_calculator w = (toy_calculator) vw;
263 press_button_N (w, 5);
267 press_button_6 (ml_session session, void *vw)
269 toy_calculator w = (toy_calculator) vw;
271 press_button_N (w, 6);
275 press_button_7 (ml_session session, void *vw)
277 toy_calculator w = (toy_calculator) vw;
279 press_button_N (w, 7);
283 press_button_8 (ml_session session, void *vw)
285 toy_calculator w = (toy_calculator) vw;
287 press_button_N (w, 8);
291 press_button_9 (ml_session session, void *vw)
293 toy_calculator w = (toy_calculator) vw;
295 press_button_N (w, 9);
299 press_button_N (toy_calculator w, int n)
303 if (strcmp (w->digits, "0") == 0)
306 len = strlen (w->digits);
308 if ((strchr (w->digits, '.') && len < 11) || len < 10)
310 w->digits[len] = '0' + n;
311 w->digits[len+1] = '\0';
312 ml_widget_set_property (w->disp, "text", w->digits);
317 press_button_DOT (ml_session session, void *vw)
319 toy_calculator w = (toy_calculator) vw;
320 int len = strlen (w->digits);
322 if (strchr (w->digits, '.') == 0 && len < 10)
324 strcat (w->digits, ".");
325 ml_widget_set_property (w->disp, "text", w->digits);
330 press_button_EQUALS (ml_session session, void *vw)
332 toy_calculator w = (toy_calculator) vw;
337 sscanf (w->digits, "%lf", &a);
341 else if (w->op == MINUS)
343 else if (w->op == TIMES)
345 else if (w->op == DIVIDE && a != 0)
348 snprintf (w->digits, 10, "%g", w->reg);
349 ml_widget_set_property (w->disp, "text", w->digits);
355 press_button_PLUS (ml_session session, void *vw)
357 toy_calculator w = (toy_calculator) vw;
359 /* Act like we just pressed the EQUALS key. */
360 press_button_EQUALS (session, vw);
362 sscanf (w->digits, "%lf", &w->reg);
363 strcpy (w->digits, "0"); /* But DON'T update the label yet. */
368 press_button_MINUS (ml_session session, void *vw)
370 toy_calculator w = (toy_calculator) vw;
372 /* Act like we just pressed the EQUALS key. */
373 press_button_EQUALS (session, vw);
375 sscanf (w->digits, "%lf", &w->reg);
376 strcpy (w->digits, "0"); /* But DON'T update the label yet. */
381 press_button_TIMES (ml_session session, void *vw)
383 toy_calculator w = (toy_calculator) vw;
385 /* Act like we just pressed the EQUALS key. */
386 press_button_EQUALS (session, vw);
388 sscanf (w->digits, "%lf", &w->reg);
389 strcpy (w->digits, "0"); /* But DON'T update the label yet. */
394 press_button_DIVIDE (ml_session session, void *vw)
396 toy_calculator w = (toy_calculator) vw;
398 /* Act like we just pressed the EQUALS key. */
399 press_button_EQUALS (session, vw);
401 sscanf (w->digits, "%lf", &w->reg);
402 strcpy (w->digits, "0"); /* But DON'T update the label yet. */
407 press_button_CLEAR (ml_session session, void *vw)
409 toy_calculator w = (toy_calculator) vw;
411 strcpy (w->digits, "0");
412 ml_widget_set_property (w->disp, "text", "0");
416 press_button_AC (ml_session session, void *vw)
418 toy_calculator w = (toy_calculator) vw;
420 strcpy (w->digits, "0");
422 ml_widget_set_property (w->disp, "text", "0");
426 repaint (void *vw, ml_session session, const char *windowid, io_handle io)
428 toy_calculator w = (toy_calculator) vw;
430 ml_widget_repaint (w->box, session, windowid, io);