1 /* $Id: ui.c,v 1.34 2008/12/11 12:18:17 ecd Exp $
2 */
3
4 #include <unistd.h>
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <stdarg.h>
8 #include <string.h>
9 #include <fcntl.h>
10 #include <signal.h>
11 #include <sys/times.h>
12 #include <math.h>
13 #include <errno.h>
14
15 #include <gtk/gtk.h>
16 #include <glib.h>
17 #include <cairo.h>
18
19 #include <x49gp.h>
20 #include <x49gp_ui.h>
21 #include <s3c2410.h>
22 #include <bitmaps.h>
23 #include <bitmap_font.h>
24 #include <symbol.h>
25 #include <glyphname.h>
26
27 #include <gdk/gdkkeysyms.h>
28
29 #if defined(__linux__)
30 #define X49GP_UI_NORMAL_FONT "urw gothic l"
31 #else
32 #define X49GP_UI_NORMAL_FONT "Century Gothic"
33 #endif
34
35
36 static const x49gp_ui_key_t x49gp_ui_keys[] =
37 {
38 {
39 "F1", "A", "Y=", NULL, NULL,
40 UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
41 UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
42 0, 0, 36, 22, 5, 1, (1 << 5), (1 << 1), 1
43 },
44 {
45 "F2", "B", "WIN", NULL, NULL,
46 UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
47 UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
48 50, 0, 36, 22, 5, 2, (1 << 5), (1 << 2), 2
49 },
50 {
51 "F3", "C", "GRAPH", NULL, NULL,
52 UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
53 UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
54 99, 0, 36, 22, 5, 3, (1 << 5), (1 << 3), 3
55 },
56 {
57 "F4", "D", "2D/3D", NULL, NULL,
58 UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
59 UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
60 149, 0, 36, 22, 5, 4, (1 << 5), (1 << 4), 4
61 },
62 {
63 "F5", "E", "TBLSET", NULL, NULL,
64 UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
65 UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
66 198, 0, 36, 22, 5, 5, (1 << 5), (1 << 5), 5
67 },
68 {
69 "F6", "F", "TABLE", NULL, NULL,
70 UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
71 UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
72 247, 0, 36, 22, 5, 6, (1 << 5), (1 << 6), 6
73 },
74 {
75 "APPS", "G", "FILES", "BEGIN", NULL,
76 UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
77 UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
78 0, 44, 36, 28, 5, 7, (1 << 5), (1 << 7), 7
79 },
80 {
81 "MODE", "H", "CUSTOM", "END", NULL,
82 UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
83 UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
84 50, 44, 36, 28, 6, 5, (1 << 6), (1 << 5), 5
85 },
86 {
87 "TOOL", "I", "i", "I", NULL,
88 UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
89 UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
90 99, 44, 36, 28, 6, 6, (1 << 6), (1 << 6), 6
91 },
92 {
93 "V\\kern-1 AR", "J", "UPDIR", "COPY", NULL,
94 UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
95 UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
96 0, 92, 36, 28, 6, 7, (1 << 6), (1 << 7), 7
97 },
98 {
99 "STO \\triangleright", "K", "RCL", "CUT", NULL,
100 UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
101 UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
102 50, 92, 36, 28, 7, 1, (1 << 7), (1 << 1), 1
103 },
104 {
105 "NXT", "L", "PREV", "PASTE", NULL,
106 UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
107 UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
108 99, 92, 36, 28, 7, 2, (1 << 7), (1 << 2), 2
109 },
110 {
111 NULL, NULL, NULL, NULL, NULL,
112 UI_COLOR_SILVER, 0.0, 0,
113 UI_SHAPE_BUTTON_ROUND, 0.0, 0,
114 200, 38, 33, 33, 6, 1, (1 << 6), (1 << 1), 1
115 },
116 {
117 NULL, NULL, NULL, NULL, NULL,
118 UI_COLOR_SILVER, 0.0, 0,
119 UI_SHAPE_BUTTON_ROUND, 0.0, 0,
120 164, 66, 33, 33, 6, 2, (1 << 6), (1 << 2), 2
121 },
122 {
123 NULL, NULL, NULL, NULL, NULL,
124 UI_COLOR_SILVER, 0.0, 0,
125 UI_SHAPE_BUTTON_ROUND, 0.0, 0,
126 200, 94, 33, 33, 6, 3, (1 << 6), (1 << 3), 3
127 },
128 {
129 NULL, NULL, NULL, NULL, NULL,
130 UI_COLOR_SILVER, 0.0, 0,
131 UI_SHAPE_BUTTON_ROUND, 0.0, 0,
132 236, 66, 33, 33, 6, 4, (1 << 6), (1 << 4), 4
133 },
134 {
135 "HIST", "M", "CMD", "UNDO", NULL,
136 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
137 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
138 0, 141, 46, 28, 4, 1, (1 << 4), (1 << 1), 1
139 },
140 {
141 "EV\\kern-1 AL", "N", "PRG", "CHARS", NULL,
142 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
143 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
144 59, 141, 46, 28, 3, 1, (1 << 3), (1 << 1), 1
145 },
146 {
147 "\\tick", "O", "MTRW", "EQW", NULL,
148 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
149 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
150 119, 141, 46, 28, 2, 1, (1 << 2), (1 << 1), 1
151 },
152 {
153 "S\\kern-1 Y\\kern-1 M\\kern-1 B", "P", "MTH", "CAT", NULL,
154 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
155 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
156 179, 141, 46, 28, 1, 1, (1 << 1), (1 << 1), 1
157 },
158 {
159 "\\arrowleftdblfull", NULL, "DEL", "CLEAR", NULL,
160 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
161 UI_SHAPE_BUTTON_NORMAL, 0.0, 0,
162 238, 141, 46, 28, 0, 1, (1 << 0), (1 << 1), 1
163 },
164 {
165 "Y\\super x\\/super", "Q", "\\math_e\\xsuperior", "LN", NULL,
166 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
167 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
168 0, 183, 46, 28, 4, 2, (1 << 4), (1 << 2), 2
169 },
170 {
171 "\\radical\\overscore\\kern-7 X", "R",
172 "\\math_x\\twosuperior",
173 "\\xsuperior\\kern-4\\math_radical\\overscore\\kern-5\\math_y",
174 NULL,
175 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
176 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
177 59, 183, 46, 28, 3, 2, (1 << 3), (1 << 2), 2
178 },
179 {
180 "SIN", "S", "ASIN", "\\math_summation", NULL,
181 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
182 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
183 119, 183, 46, 28, 2, 2, (1 << 2), (1 << 2), 2
184 },
185 {
186 "COS", "T", "ACOS", "\\math_partialdiff", NULL,
187 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
188 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
189 179, 183, 46, 28, 1, 2, (1 << 1), (1 << 2), 2
190 },
191 {
192 "TAN", "U", "ATAN", "\\math_integral", NULL,
193 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
194 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
195 238, 183, 46, 28, 0, 2, (1 << 0), (1 << 2), 2
196 },
197 {
198 "EEX", "V", "10\\xsuperior", "LOG", NULL,
199 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
200 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
201 0, 225, 46, 28, 4, 3, (1 << 4), (1 << 3), 3
202 },
203 {
204 "+\\divisionslash\\minus", "W",
205 "\\math_notequal",
206 "\\math_equal",
207 NULL,
208 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
209 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
210 59, 225, 46, 28, 3, 3, (1 << 3), (1 << 3), 3
211 },
212 {
213 "X", "X",
214 "\\math_lessequal",
215 "\\math_less",
216 NULL,
217 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
218 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
219 119, 225, 46, 28, 2, 3, (1 << 2), (1 << 3), 3
220 },
221 {
222 "1/X", "Y",
223 "\\math_greaterequal",
224 "\\math_greater",
225 NULL,
226 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
227 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
228 179, 225, 46, 28, 1, 3, (1 << 1), (1 << 3), 3
229 },
230 {
231 "\\divide", "Z", "ABS", "ARG", NULL,
232 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
233 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT_NO_SPACE,
234 238, 225, 46, 28, 0, 3, (1 << 0), (1 << 3), 3
235 },
236 {
237 "ALPHA", NULL, "USER", "ENTRY", NULL,
238 UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
239 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
240 0, 267, 46, 32, 0, 0, 0, 0, 4
241 },
242 {
243 "7", NULL, "S.SLV", "NUM.SLV", NULL,
244 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
245 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
246 59, 267, 46, 32, 3, 4, (1 << 3), (1 << 4), 4
247 },
248 {
249 "8", NULL, "EXP&LN", "TRIG", NULL,
250 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
251 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
252 119, 267, 46, 32, 2, 4, (1 << 2), (1 << 4), 4
253 },
254 {
255 "9", NULL, "FINANCE", "TIME", NULL,
256 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
257 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
258 179, 267, 46, 32, 1, 4, (1 << 1), (1 << 4), 4
259 },
260 {
261 "\\multiply", NULL, "[ ]", "\" \"", NULL,
262 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
263 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
264 238, 267, 46, 32, 0, 4, (1 << 0), (1 << 4), 4
265 },
266 {
267 "\\uparrowleft", NULL, NULL, NULL, NULL,
268 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
269 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
270 0, 313, 46, 32, 0, 0, 0, 0, 5
271 },
272 {
273 "4", NULL, "CALC", "ALG", NULL,
274 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
275 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
276 59, 313, 46, 32, 3, 5, (1 << 3), (1 << 5), 5
277 },
278 {
279 "5", NULL, "MATRICES", "STAT", NULL,
280 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
281 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
282 119, 313, 46, 32, 2, 5, (1 << 2), (1 << 5), 5
283 },
284 {
285 "6", NULL, "CONVERT", "UNITS", NULL,
286 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
287 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
288 179, 313, 46, 32, 1, 5, (1 << 1), (1 << 5), 5
289 },
290 {
291 "\\minus", NULL, "( )", "_", NULL,
292 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
293 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
294 238, 313, 46, 32, 0, 5, (1 << 0), (1 << 5), 5
295 },
296 {
297 "\\uparrowright", NULL, NULL, NULL, NULL,
298 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
299 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
300 0, 359, 46, 32, 0, 0, 0, 0, 6
301 },
302 {
303 "1", NULL, "ARITH", "CMPLX", NULL,
304 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
305 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
306 59, 359, 46, 32, 3, 6, (1 << 3), (1 << 6), 6
307 },
308 {
309 "2", NULL, "DEF", "LIB", NULL,
310 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
311 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
312 119, 359, 46, 32, 2, 6, (1 << 2), (1 << 6), 6
313 },
314 {
315 "3", NULL, "\\math_numbersign", "BASE", NULL,
316 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
317 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
318 179, 359, 46, 32, 1, 6, (1 << 1), (1 << 6), 6
319 },
320 {
321 "+", NULL,
322 "{ }",
323 "\\guillemotleft\\ \\guillemotright",
324 NULL,
325 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
326 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
327 238, 359, 46, 32, 0, 6, (1 << 0), (1 << 6), 6
328 },
329 {
330 "ON", NULL, "CONT", "OFF", "CANCEL",
331 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
332 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
333 0, 405, 46, 32, 0, 0, 0, 0, 0
334 },
335 {
336 "0", NULL,
337 "\\math_infinity",
338 "\\math_arrowright",
339 NULL,
340 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
341 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
342 59, 405, 46, 32, 3, 7, (1 << 3), (1 << 7), 7
343 },
344 {
345 "\\bullet", NULL,
346 ": :",
347 "\\math_downarrowleft",
348 NULL,
349 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
350 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
351 119, 405, 46, 32, 2, 7, (1 << 2), (1 << 7), 7
352 },
353 {
354 "SPC", NULL,
355 "\\math_pi",
356 "\\large_comma",
357 NULL,
358 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
359 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
360 179, 405, 46, 32, 1, 7, (1 << 1), (1 << 7), 7
361 },
362 {
363 "ENTER", NULL, "ANS", "\\arrowright NUM", NULL,
364 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
365 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
366 238, 405, 46, 32, 0, 7, (1 << 0), (1 << 7), 7
367 },
368 };
369 #define X49GP_UI_NR_KEYS (sizeof(x49gp_ui_keys) / sizeof(x49gp_ui_keys[0]))
370
371 static const x49gp_ui_key_t x50g_ui_keys[] =
372 {
373 {
374 "F1", "A", "Y=", NULL, NULL,
375 UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
376 UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
377 0, 0, 36, 22, 5, 1, (1 << 5), (1 << 1), 1
378 },
379 {
380 "F2", "B", "WIN", NULL, NULL,
381 UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
382 UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
383 50, 0, 36, 22, 5, 2, (1 << 5), (1 << 2), 2
384 },
385 {
386 "F3", "C", "GRAPH", NULL, NULL,
387 UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
388 UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
389 99, 0, 36, 22, 5, 3, (1 << 5), (1 << 3), 3
390 },
391 {
392 "F4", "D", "2D/3D", NULL, NULL,
393 UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
394 UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
395 149, 0, 36, 22, 5, 4, (1 << 5), (1 << 4), 4
396 },
397 {
398 "F5", "E", "TBLSET", NULL, NULL,
399 UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
400 UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
401 198, 0, 36, 22, 5, 5, (1 << 5), (1 << 5), 5
402 },
403 {
404 "F6", "F", "TABLE", NULL, NULL,
405 UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
406 UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
407 247, 0, 36, 22, 5, 6, (1 << 5), (1 << 6), 6
408 },
409 {
410 "APPS", "G", "FILES", "BEGIN", NULL,
411 UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
412 UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
413 0, 44, 36, 28, 5, 7, (1 << 5), (1 << 7), 7
414 },
415 {
416 "MODE", "H", "CUSTOM", "END", NULL,
417 UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
418 UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
419 50, 44, 36, 28, 6, 5, (1 << 6), (1 << 5), 5
420 },
421 {
422 "TOOL", "I", "i", "I", NULL,
423 UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
424 UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
425 99, 44, 36, 28, 6, 6, (1 << 6), (1 << 6), 6
426 },
427 {
428 "V\\kern-1 AR", "J", "UPDIR", "COPY", NULL,
429 UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
430 UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
431 0, 92, 36, 28, 6, 7, (1 << 6), (1 << 7), 7
432 },
433 {
434 "STO \\triangleright", "K", "RCL", "CUT", NULL,
435 UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
436 UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
437 50, 92, 36, 28, 7, 1, (1 << 7), (1 << 1), 1
438 },
439 {
440 "NXT", "L", "PREV", "PASTE", NULL,
441 UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
442 UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
443 99, 92, 36, 28, 7, 2, (1 << 7), (1 << 2), 2
444 },
445 {
446 NULL, NULL, NULL, NULL, NULL,
447 UI_COLOR_SILVER, 0.0, 0,
448 UI_SHAPE_BUTTON_ROUND, 0.0, 0,
449 200, 38, 33, 33, 6, 1, (1 << 6), (1 << 1), 1
450 },
451 {
452 NULL, NULL, NULL, NULL, NULL,
453 UI_COLOR_SILVER, 0.0, 0,
454 UI_SHAPE_BUTTON_ROUND, 0.0, 0,
455 164, 66, 33, 33, 6, 2, (1 << 6), (1 << 2), 2
456 },
457 {
458 NULL, NULL, NULL, NULL, NULL,
459 UI_COLOR_SILVER, 0.0, 0,
460 UI_SHAPE_BUTTON_ROUND, 0.0, 0,
461 200, 94, 33, 33, 6, 3, (1 << 6), (1 << 3), 3
462 },
463 {
464 NULL, NULL, NULL, NULL, NULL,
465 UI_COLOR_SILVER, 0.0, 0,
466 UI_SHAPE_BUTTON_ROUND, 0.0, 0,
467 236, 66, 33, 33, 6, 4, (1 << 6), (1 << 4), 4
468 },
469 {
470 "HIST", "M", "CMD", "UNDO", NULL,
471 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
472 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
473 0, 141, 46, 28, 4, 1, (1 << 4), (1 << 1), 1
474 },
475 {
476 "EV\\kern-1 AL", "N", "PRG", "CHARS", NULL,
477 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
478 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
479 59, 141, 46, 28, 3, 1, (1 << 3), (1 << 1), 1
480 },
481 {
482 "\\tick", "O", "MTRW", "EQW", NULL,
483 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
484 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
485 119, 141, 46, 28, 2, 1, (1 << 2), (1 << 1), 1
486 },
487 {
488 "S\\kern-1 Y\\kern-1 M\\kern-1 B", "P", "MTH", "CAT", NULL,
489 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
490 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
491 179, 141, 46, 28, 1, 1, (1 << 1), (1 << 1), 1
492 },
493 {
494 "\\arrowleftdblfull", NULL, "DEL", "CLEAR", NULL,
495 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
496 UI_SHAPE_BUTTON_NORMAL, 0.0, 0,
497 238, 141, 46, 28, 0, 1, (1 << 0), (1 << 1), 1
498 },
499 {
500 "Y\\super x\\/super", "Q", "\\math_e\\xsuperior", "LN", NULL,
501 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
502 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
503 0, 183, 46, 28, 4, 2, (1 << 4), (1 << 2), 2
504 },
505 {
506 "\\radical\\overscore\\kern-7 X", "R",
507 "\\math_x\\twosuperior",
508 "\\xsuperior\\kern-4\\math_radical\\overscore\\kern-5\\math_y",
509 NULL,
510 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
511 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
512 59, 183, 46, 28, 3, 2, (1 << 3), (1 << 2), 2
513 },
514 {
515 "SIN", "S", "ASIN", "\\math_summation", NULL,
516 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
517 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
518 119, 183, 46, 28, 2, 2, (1 << 2), (1 << 2), 2
519 },
520 {
521 "COS", "T", "ACOS", "\\math_partialdiff", NULL,
522 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
523 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
524 179, 183, 46, 28, 1, 2, (1 << 1), (1 << 2), 2
525 },
526 {
527 "TAN", "U", "ATAN", "\\math_integral", NULL,
528 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
529 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
530 238, 183, 46, 28, 0, 2, (1 << 0), (1 << 2), 2
531 },
532 {
533 "EEX", "V", "10\\xsuperior", "LOG", NULL,
534 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
535 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
536 0, 225, 46, 28, 4, 3, (1 << 4), (1 << 3), 3
537 },
538 {
539 "+\\divisionslash\\minus", "W",
540 "\\math_notequal",
541 "\\math_equal",
542 NULL,
543 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
544 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
545 59, 225, 46, 28, 3, 3, (1 << 3), (1 << 3), 3
546 },
547 {
548 "X", "X",
549 "\\math_lessequal",
550 "\\math_less",
551 NULL,
552 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
553 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
554 119, 225, 46, 28, 2, 3, (1 << 2), (1 << 3), 3
555 },
556 {
557 "1/X", "Y",
558 "\\math_greaterequal",
559 "\\math_greater",
560 NULL,
561 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
562 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
563 179, 225, 46, 28, 1, 3, (1 << 1), (1 << 3), 3
564 },
565 {
566 "\\divide", "Z", "ABS", "ARG", NULL,
567 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
568 UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT_NO_SPACE,
569 238, 225, 46, 28, 0, 3, (1 << 0), (1 << 3), 3
570 },
571 {
572 "ALPHA", NULL, "USER", "ENTRY", NULL,
573 UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
574 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
575 0, 267, 46, 32, 0, 0, 0, 0, 4
576 },
577 {
578 "7", NULL, "S.SLV", "NUM.SLV", NULL,
579 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
580 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
581 59, 267, 46, 32, 3, 4, (1 << 3), (1 << 4), 4
582 },
583 {
584 "8", NULL, "EXP&LN", "TRIG", NULL,
585 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
586 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
587 119, 267, 46, 32, 2, 4, (1 << 2), (1 << 4), 4
588 },
589 {
590 "9", NULL, "FINANCE", "TIME", NULL,
591 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
592 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
593 179, 267, 46, 32, 1, 4, (1 << 1), (1 << 4), 4
594 },
595 {
596 "\\multiply", NULL, "[ ]", "\" \"", NULL,
597 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
598 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
599 238, 267, 46, 32, 0, 4, (1 << 0), (1 << 4), 4
600 },
601 {
602 "\\uparrowleft", NULL, NULL, NULL, NULL,
603 UI_COLOR_BLACK, 19.0, CAIRO_FONT_WEIGHT_BOLD,
604 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
605 0, 313, 46, 32, 0, 0, 0, 0, 5
606 },
607 {
608 "4", NULL, "CALC", "ALG", NULL,
609 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
610 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
611 59, 313, 46, 32, 3, 5, (1 << 3), (1 << 5), 5
612 },
613 {
614 "5", NULL, "MATRICES", "STAT", NULL,
615 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
616 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
617 119, 313, 46, 32, 2, 5, (1 << 2), (1 << 5), 5
618 },
619 {
620 "6", NULL, "CONVERT", "UNITS", NULL,
621 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
622 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
623 179, 313, 46, 32, 1, 5, (1 << 1), (1 << 5), 5
624 },
625 {
626 "\\minus", NULL, "( )", "_", NULL,
627 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
628 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
629 238, 313, 46, 32, 0, 5, (1 << 0), (1 << 5), 5
630 },
631 {
632 "\\uparrowright", NULL, NULL, NULL, NULL,
633 UI_COLOR_BLACK, 19.0, CAIRO_FONT_WEIGHT_BOLD,
634 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
635 0, 359, 46, 32, 0, 0, 0, 0, 6
636 },
637 {
638 "1", NULL, "ARITH", "CMPLX", NULL,
639 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
640 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
641 59, 359, 46, 32, 3, 6, (1 << 3), (1 << 6), 6
642 },
643 {
644 "2", NULL, "DEF", "LIB", NULL,
645 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
646 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
647 119, 359, 46, 32, 2, 6, (1 << 2), (1 << 6), 6
648 },
649 {
650 "3", NULL, "\\math_numbersign", "BASE", NULL,
651 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
652 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
653 179, 359, 46, 32, 1, 6, (1 << 1), (1 << 6), 6
654 },
655 {
656 "+", NULL,
657 "{ }",
658 "\\guillemotleft\\ \\guillemotright",
659 NULL,
660 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
661 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
662 238, 359, 46, 32, 0, 6, (1 << 0), (1 << 6), 6
663 },
664 {
665 "ON", NULL, "CONT", "OFF", "CANCEL",
666 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
667 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
668 0, 405, 46, 32, 0, 0, 0, 0, 0
669 },
670 {
671 "0", NULL,
672 "\\math_infinity",
673 "\\math_arrowright",
674 NULL,
675 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
676 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
677 59, 405, 46, 32, 3, 7, (1 << 3), (1 << 7), 7
678 },
679 {
680 "\\bullet", NULL,
681 ": :",
682 "\\math_downarrowleft",
683 NULL,
684 UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
685 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
686 119, 405, 46, 32, 2, 7, (1 << 2), (1 << 7), 7
687 },
688 {
689 "SPC", NULL,
690 "\\math_pi",
691 "\\large_comma",
692 NULL,
693 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
694 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
695 179, 405, 46, 32, 1, 7, (1 << 1), (1 << 7), 7
696 },
697 {
698 "ENTER", NULL, "ANS", "\\arrowright NUM", NULL,
699 UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
700 UI_SHAPE_BUTTON_LARGE, 0.0, 0,
701 238, 405, 46, 32, 0, 7, (1 << 0), (1 << 7), 7
702 },
703 };
704 #define X50G_UI_NR_KEYS (sizeof(x50g_ui_keys) / sizeof(x50g_ui_keys[0]))
705
706 static void
x49gp_ui_color_init(GdkColor * color,u8 red,u8 green,u8 blue)707 x49gp_ui_color_init(GdkColor *color, u8 red, u8 green, u8 blue)
708 {
709 color->red = (red << 8) | red;
710 color->green = (green << 8) | green;
711 color->blue = (blue << 8) | blue;
712 }
713
714 static void
x49gp_ui_style_init(GtkStyle * style,GtkWidget * widget,GdkColor * fg,GdkColor * bg)715 x49gp_ui_style_init(GtkStyle *style, GtkWidget *widget,
716 GdkColor *fg, GdkColor *bg)
717 {
718 int i;
719
720 for (i = 0; i < 5; i++) {
721 style->fg[i] = *fg;
722 style->bg[i] = *bg;
723
724 style->text[i] = style->fg[i];
725 style->base[i] = style->bg[i];
726 }
727
728 style->xthickness = 0;
729 style->ythickness = 0;
730 }
731
732 static int
x49gp_ui_button_pixmaps_init(x49gp_t * x49gp,x49gp_ui_button_t * button,x49gp_ui_color_t color)733 x49gp_ui_button_pixmaps_init(x49gp_t *x49gp, x49gp_ui_button_t *button,
734 x49gp_ui_color_t color)
735 {
736 x49gp_ui_t *ui = x49gp->ui;
737 GdkPixbuf *src, *dst;
738 GtkStyle *style;
739 int i;
740
741 style = gtk_style_new();
742 x49gp_ui_style_init(style, button->button,
743 &ui->colors[button->key->color],
744 &ui->colors[UI_COLOR_BLACK]);
745
746 for (i = 0; i < 5; i++) {
747 style->bg_pixmap[i] = gdk_pixmap_new(ui->window->window,
748 button->key->width,
749 button->key->height, -1);
750
751 if (i == GTK_STATE_ACTIVE) {
752 if (color == UI_COLOR_SILVER) {
753 GError *gerror = NULL;
754
755 src = gdk_pixbuf_new_subpixbuf(ui->bg_pixbuf,
756 ui->kb_x_offset + button->key->x,
757 ui->kb_y_offset + button->key->y,
758 button->key->width,
759 button->key->height);
760 dst = gdk_pixbuf_copy(src);
761 g_object_unref(src);
762
763 src = gdk_pixbuf_new_from_inline(sizeof(button_round),
764 button_round, FALSE, &gerror);
765
766 gdk_pixbuf_composite(src, dst,
767 0, 0,
768 button->key->width,
769 button->key->height,
770 0.0, 0.0, 1.0, 1.0,
771 GDK_INTERP_HYPER, 0xff);
772
773 g_object_unref(src);
774 src = dst;
775 } else {
776 src = gdk_pixbuf_new_subpixbuf(ui->bg_pixbuf,
777 ui->kb_x_offset + button->key->x,
778 ui->kb_y_offset + button->key->y + 1,
779 button->key->width,
780 button->key->height);
781 }
782 } else {
783 src = gdk_pixbuf_new_subpixbuf(ui->bg_pixbuf,
784 ui->kb_x_offset + button->key->x,
785 ui->kb_y_offset + button->key->y,
786 button->key->width,
787 button->key->height);
788 }
789
790 gdk_draw_pixbuf(style->bg_pixmap[i],
791 ui->window->style->black_gc,
792 src, 0, 0, 0, 0,
793 button->key->width, button->key->height,
794 GDK_RGB_DITHER_NORMAL, 0, 0);
795
796 g_object_unref(src);
797 }
798
799 gtk_widget_set_style(button->button, style);
800 return 0;
801 }
802
803 static void
x49gp_ui_symbol_path(cairo_t * cr,double size,double xoffset,double yoffset,const x49gp_symbol_t * symbol)804 x49gp_ui_symbol_path(cairo_t *cr, double size,
805 double xoffset, double yoffset,
806 const x49gp_symbol_t *symbol)
807 {
808 const symbol_path_t *path;
809 const cairo_path_data_t *data;
810 int i;
811
812 path = symbol->path;
813 if (NULL == path) {
814 return;
815 }
816
817 cairo_move_to(cr, xoffset, yoffset);
818
819 for (i = 0; i < path->num_data; i += path->data[i].header.length) {
820 data = &path->data[i];
821
822 switch (data->header.type) {
823 case CAIRO_PATH_MOVE_TO:
824 cairo_rel_move_to(cr, size * data[1].point.x,
825 -size * data[1].point.y);
826 break;
827 case CAIRO_PATH_LINE_TO:
828 cairo_rel_line_to(cr, size * data[1].point.x,
829 -size * data[1].point.y);
830 break;
831 case CAIRO_PATH_CURVE_TO:
832 cairo_rel_curve_to(cr, size * data[1].point.x,
833 -size * data[1].point.y,
834 size * data[2].point.x,
835 -size * data[2].point.y,
836 size * data[3].point.x,
837 -size * data[3].point.y);
838 break;
839 case CAIRO_PATH_CLOSE_PATH:
840 cairo_close_path(cr);
841 break;
842 }
843 }
844 }
845
846 static void
x49gp_ui_draw_symbol(cairo_t * cr,GdkColor * color,double size,double line_width,gboolean fill,double xoffset,double yoffset,const x49gp_symbol_t * symbol)847 x49gp_ui_draw_symbol(cairo_t *cr, GdkColor *color, double size,
848 double line_width, gboolean fill,
849 double xoffset, double yoffset,
850 const x49gp_symbol_t *symbol)
851 {
852 cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
853 cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER);
854 cairo_set_line_width(cr, line_width);
855 cairo_set_source_rgb(cr, ((double) color->red) / 65535.0,
856 ((double) color->green) / 65535.0,
857 ((double) color->blue) / 65535.0);
858
859 x49gp_ui_symbol_path(cr, size, xoffset, yoffset, symbol);
860
861 if (fill) {
862 cairo_fill(cr);
863 } else {
864 cairo_stroke(cr);
865 }
866 }
867
868 static int
x49gp_ui_lookup_glyph(const char * name,int namelen,gunichar * glyph)869 x49gp_ui_lookup_glyph(const char *name, int namelen, gunichar *glyph)
870 {
871 int i;
872
873 for (i = 0; i < NR_GLYPHNAMES; i++) {
874 if ((strlen(x49gp_glyphs[i].name) == namelen) &&
875 !strncmp(x49gp_glyphs[i].name, name, namelen)) {
876 if (glyph)
877 *glyph = x49gp_glyphs[i].unichar;
878 return 1;
879 }
880 }
881
882 return 0;
883 }
884
885 static int
x49gp_text_strlen(const char * text)886 x49gp_text_strlen(const char *text)
887 {
888 const char *p, *q;
889 char c;
890 int namelen;
891 int n = 0;
892
893 p = text;
894 while ((c = *p++)) {
895 if (c != '\\') {
896 n++;
897 continue;
898 }
899
900 q = p;
901 while (*q) {
902 if ((*q == '\\') || (*q == ' '))
903 break;
904 q++;
905 }
906 if (q == p) {
907 n++;
908 p++;
909 continue;
910 }
911 namelen = q - p;
912 if (*q == ' ')
913 q++;
914
915 if (symbol_lookup_glyph_by_name(p, namelen, NULL)) {
916 p = q;
917 n++;
918 continue;
919 }
920
921 if (x49gp_ui_lookup_glyph(p, namelen, NULL)) {
922 p = q;
923 n++;
924 continue;
925 }
926
927 /*
928 * Insert symbol .notdef here...
929 */
930 p = q;
931 n++;
932 }
933
934 return n;
935 }
936
937 static int
x49gp_text_to_ucs4(const char * text,gunichar ** ucs4p)938 x49gp_text_to_ucs4(const char *text, gunichar **ucs4p)
939 {
940 const char *p, *q;
941 gunichar glyph;
942 gunichar *ucs4;
943 char c;
944 int namelen;
945 int i, n;
946
947 n = x49gp_text_strlen(text);
948 if (n <= 0)
949 return n;
950
951 ucs4 = malloc(n * sizeof(gunichar));
952
953 i = 0;
954
955 p = text;
956 while ((c = *p++)) {
957 if (i == n) {
958 free(ucs4);
959 return -1;
960 }
961
962 if (c != '\\') {
963 ucs4[i++] = c;
964 continue;
965 }
966
967 q = p;
968 while (*q) {
969 if ((*q == '\\') || (*q == ' '))
970 break;
971 q++;
972 }
973 if (q == p) {
974 ucs4[i++] = *p++;
975 continue;
976 }
977 namelen = q - p;
978 if (*q == ' ')
979 q++;
980
981 if (symbol_lookup_glyph_by_name(p, namelen, &glyph)) {
982 ucs4[i++] = glyph;
983 p = q;
984 continue;
985 }
986
987 if (x49gp_ui_lookup_glyph(p, namelen, &glyph)) {
988 ucs4[i++] = glyph;
989 p = q;
990 continue;
991 }
992
993 /*
994 * Insert symbol .notdef here...
995 */
996 ucs4[i++] = 0xe000;
997 p = q;
998 }
999
1000 *ucs4p = ucs4;
1001 return n;
1002 }
1003
1004 static void
x49gp_ui_vtext_path(cairo_t * cr,const char * family,double size,double x,double y,int n,va_list ap)1005 x49gp_ui_vtext_path(cairo_t *cr, const char *family, double size,
1006 double x, double y, int n, va_list ap)
1007 {
1008 cairo_text_extents_t extents;
1009 cairo_font_weight_t weight;
1010 cairo_font_slant_t slant;
1011 const x49gp_symbol_t *symbol;
1012 const char *text;
1013 gunichar *ucs4;
1014 char out[8];
1015 int bytes;
1016 int i, j, len;
1017
1018 for (i = 0; i < n; i++) {
1019 slant = va_arg(ap, cairo_font_slant_t);
1020 weight = va_arg(ap, cairo_font_weight_t);
1021 text = va_arg(ap, const char *);
1022
1023 cairo_select_font_face(cr, family, slant, weight);
1024 cairo_set_font_size(cr, size);
1025
1026 ucs4 = NULL;
1027 len = x49gp_text_to_ucs4(text, &ucs4);
1028 if (len <= 0) {
1029 continue;
1030 }
1031
1032 for (j = 0; j < len; j++) {
1033 if (g_unichar_type(ucs4[j]) == G_UNICODE_PRIVATE_USE) {
1034 /*
1035 * Draw Symbol, Increment x...
1036 */
1037 symbol = symbol_get_by_glyph(ucs4[j]);
1038 if (NULL == symbol)
1039 symbol = symbol_get_by_glyph(0xe000);
1040
1041 size *= symbol->prescale;
1042
1043 x49gp_ui_symbol_path(cr, size, x, y, symbol);
1044
1045 x += size * symbol->x_advance;
1046 y -= size * symbol->y_advance;
1047
1048 size *= symbol->postscale;
1049
1050 if (symbol->prescale * symbol->postscale != 1.)
1051 cairo_set_font_size(cr, size);
1052
1053 continue;
1054 }
1055
1056 bytes = g_unichar_to_utf8(ucs4[j], out);
1057 out[bytes] = '\0';
1058
1059 cairo_text_extents(cr, out, &extents);
1060
1061 cairo_move_to(cr, x, y);
1062
1063 cairo_text_path(cr, out);
1064
1065 x += extents.x_advance;
1066 y += extents.y_advance;
1067 }
1068
1069 free(ucs4);
1070 }
1071 }
1072
1073 static void
x49gp_ui_text_size(cairo_t * cr,const char * family,double size,double * x_bearing,double * y_bearing,double * width,double * height,double * ascent,double * descent,int n,...)1074 x49gp_ui_text_size(cairo_t *cr, const char *family, double size,
1075 double *x_bearing, double *y_bearing,
1076 double *width, double *height,
1077 double *ascent, double *descent,
1078 int n, ...)
1079 {
1080 va_list ap;
1081 cairo_font_extents_t font_extents;
1082 cairo_font_weight_t weight;
1083 cairo_font_slant_t slant;
1084 double x1, y1, x2, y2, a, d;
1085 const char *text;
1086 int i;
1087
1088 if (n < 1)
1089 return;
1090
1091 va_start(ap, n);
1092
1093 x49gp_ui_vtext_path(cr, family, size, 0.0, 0.0, n, ap);
1094
1095 cairo_fill_extents(cr, &x1, &y1, &x2, &y2);
1096
1097 if (y2 < 0.0)
1098 y2 = 0.0;
1099
1100 a = 0.0;
1101 d = 0.0;
1102
1103 for (i = 0; i < n; i++) {
1104 slant = va_arg(ap, cairo_font_slant_t);
1105 weight = va_arg(ap, cairo_font_weight_t);
1106 text = va_arg(ap, const char *);
1107
1108 cairo_select_font_face(cr, family, slant, weight);
1109 cairo_set_font_size(cr, size);
1110
1111 cairo_font_extents(cr, &font_extents);
1112
1113 /*
1114 * Cairo seems to return overall height in ascent,
1115 * so fix this by calculating ascent = height - descent.
1116 */
1117 if (font_extents.ascent - font_extents.descent > a)
1118 a = font_extents.ascent - font_extents.descent;
1119 if (font_extents.descent > -d)
1120 d = -font_extents.descent;
1121 }
1122
1123 *x_bearing = x1;
1124 *y_bearing = y2;
1125 *width = x2 - x1;
1126 *height = y2 - y1;
1127 *ascent = a;
1128 *descent = d;
1129
1130 va_end(ap);
1131 }
1132
1133 static void
x49gp_ui_draw_text(cairo_t * cr,GdkColor * color,const char * family,double size,double line_width,int xoffset,int yoffset,int n,...)1134 x49gp_ui_draw_text(cairo_t *cr, GdkColor *color,
1135 const char *family, double size, double line_width,
1136 int xoffset, int yoffset, int n, ...)
1137 {
1138 va_list ap;
1139
1140 if (n < 1)
1141 return;
1142
1143 va_start(ap, n);
1144
1145 cairo_set_line_width(cr, line_width);
1146 cairo_set_source_rgb(cr, ((double) color->red) / 65535.0,
1147 ((double) color->green) / 65535.0,
1148 ((double) color->blue) / 65535.0);
1149
1150 x49gp_ui_vtext_path(cr, family, size, xoffset, yoffset, n, ap);
1151
1152 if (line_width == 0.0)
1153 cairo_fill(cr);
1154 else
1155 cairo_stroke(cr);
1156
1157 va_end(ap);
1158 }
1159
1160 #if 0
1161 static void
1162 x49gp_ui_dump_path(cairo_t *cr, const char *family, int n, ...)
1163 {
1164 va_list ap;
1165 const cairo_path_t *path;
1166 const cairo_path_data_t *data;
1167 int i;
1168
1169 if (n < 1)
1170 return;
1171
1172 va_start(ap, n);
1173
1174 x49gp_ui_vtext_path(cr, family, 1000.0, 0.0, 0.0, n, ap);
1175
1176 path = cairo_copy_path(cr);
1177 if (NULL == path) {
1178 return;
1179 }
1180 cairo_new_path(cr);
1181
1182 for (i = 0; i < path->num_data; i += path->data[i].header.length) {
1183 data = &path->data[i];
1184
1185 switch (data->header.type) {
1186 case CAIRO_PATH_MOVE_TO:
1187 printf("path: move to %4.0f %4.0f\n",
1188 data[1].point.x, -data[1].point.y);
1189 break;
1190 case CAIRO_PATH_LINE_TO:
1191 printf("path: line to %4.0f %4.0f\n",
1192 data[1].point.x, -data[1].point.y);
1193 break;
1194 case CAIRO_PATH_CURVE_TO:
1195 printf("path: curve to %4.0f %4.0f\n"
1196 " %4.0f %4.0f\n"
1197 " %4.0f %4.0f\n",
1198 data[1].point.x, -data[1].point.y,
1199 data[2].point.x, -data[2].point.y,
1200 data[3].point.x, -data[3].point.y);
1201 break;
1202 case CAIRO_PATH_CLOSE_PATH:
1203 printf("path: close path\n");
1204 break;
1205 }
1206 }
1207
1208 va_end(ap);
1209 }
1210 #endif
1211
1212 static unsigned char
bitmap_font_lookup_glyph(const bitmap_font_t * font,const char * name,int namelen)1213 bitmap_font_lookup_glyph(const bitmap_font_t *font,
1214 const char *name, int namelen)
1215 {
1216 int i;
1217
1218 for (i = 0; font->glyphs[i].name; i++) {
1219 if ((strlen(font->glyphs[i].name) == namelen) &&
1220 !strncmp(font->glyphs[i].name, name, namelen)) {
1221 return i;
1222 }
1223 }
1224
1225 return 0;
1226 }
1227
1228 static unsigned char
bitmap_font_lookup_ascii(const bitmap_font_t * font,char c)1229 bitmap_font_lookup_ascii(const bitmap_font_t *font, char c)
1230 {
1231 int namelen = 0;
1232 char *name;
1233
1234 switch (c) {
1235 case ' ': name = "space"; break;
1236 case '!': name = "exclam"; break;
1237 case '"': name = "quotedbl"; break;
1238 case '#': name = "numbersign"; break;
1239 case '$': name = "dollar"; break;
1240 case '%': name = "percent"; break;
1241 case '&': name = "ampersand"; break;
1242 case '(': name = "parenleft"; break;
1243 case ')': name = "parenright"; break;
1244 case '*': name = "asterisk"; break;
1245 case '+': name = "plus"; break;
1246 case ',': name = "comma"; break;
1247 case '-': name = "hyphen"; break;
1248 case '.': name = "period"; break;
1249 case '/': name = "slash"; break;
1250 case '0': name = "zero"; break;
1251 case '1': name = "one"; break;
1252 case '2': name = "two"; break;
1253 case '3': name = "three"; break;
1254 case '4': name = "four"; break;
1255 case '5': name = "five"; break;
1256 case '6': name = "six"; break;
1257 case '7': name = "seven"; break;
1258 case '8': name = "eight"; break;
1259 case '9': name = "nine"; break;
1260 case ':': name = "colon"; break;
1261 case ';': name = "semicolon"; break;
1262 case '<': name = "less"; break;
1263 case '=': name = "equal"; break;
1264 case '>': name = "greater"; break;
1265 case '?': name = "question"; break;
1266 case '@': name = "at"; break;
1267 case '[': name = "bracketleft"; break;
1268 case '\\': name = "backslash"; break;
1269 case ']': name = "bracketright"; break;
1270 case '^': name = "asciicircum"; break;
1271 case '_': name = "underscore"; break;
1272 case '`': name = "quoteleft"; break;
1273 case '{': name = "braceleft"; break;
1274 case '|': name = "bar"; break;
1275 case '}': name = "braceright"; break;
1276 case '~': name = "asciitilde"; break;
1277 default:
1278 name = &c;
1279 namelen = 1;
1280 break;
1281 }
1282
1283 if (0 == namelen)
1284 namelen = strlen(name);
1285
1286 return bitmap_font_lookup_glyph(font, name, namelen);
1287 }
1288
1289 static int
bitmap_font_strlen(const char * text)1290 bitmap_font_strlen(const char *text)
1291 {
1292 const char *p, *q;
1293 char c;
1294 int n = 0;
1295
1296 p = text;
1297 while ((c = *p++)) {
1298 if (c != '\\') {
1299 n++;
1300 continue;
1301 }
1302
1303 q = p;
1304 while (*q) {
1305 if ((*q == '\\') || (*q == ' '))
1306 break;
1307 q++;
1308 }
1309 if (q == p) {
1310 n++;
1311 p++;
1312 continue;
1313 }
1314 if (*q == ' ')
1315 q++;
1316
1317 n++;
1318 p = q;
1319 }
1320
1321 return n;
1322 }
1323
1324 static int
bitmap_font_text_to_glyphs(const bitmap_font_t * font,const char * text,unsigned char ** glyphp)1325 bitmap_font_text_to_glyphs(const bitmap_font_t *font,
1326 const char *text, unsigned char **glyphp)
1327 {
1328 unsigned char *glyphs;
1329 const char *p, *q;
1330 unsigned char c;
1331 int namelen;
1332 int i, n;
1333
1334 n = bitmap_font_strlen(text);
1335 if (n <= 0)
1336 return n;
1337
1338 glyphs = malloc(n);
1339
1340 i = 0;
1341
1342 p = text;
1343 while ((c = *p++)) {
1344 if (i == n) {
1345 free(glyphs);
1346 return -1;
1347 }
1348
1349 if (c != '\\') {
1350 glyphs[i++] = bitmap_font_lookup_ascii(font, c);
1351 continue;
1352 }
1353
1354 q = p;
1355 while (*q) {
1356 if ((*q == '\\') || (*q == ' '))
1357 break;
1358 q++;
1359 }
1360 if (q == p) {
1361 glyphs[i++] = bitmap_font_lookup_ascii(font, *p++);
1362 continue;
1363 }
1364 namelen = q - p;
1365 if (*q == ' ')
1366 q++;
1367
1368 glyphs[i++] = bitmap_font_lookup_glyph(font, p, namelen);
1369 p = q;
1370 }
1371
1372 *glyphp = glyphs;
1373 return n;
1374
1375 }
1376
1377 static void
bitmap_font_text_size(const bitmap_font_t * font,const char * text,int * width,int * height,int * ascent,int * descent)1378 bitmap_font_text_size(const bitmap_font_t *font, const char *text,
1379 int *width, int *height, int *ascent, int *descent)
1380 {
1381 const bitmap_glyph_t *glyph;
1382 unsigned char *glyphs;
1383 int i, n, w, a, d;
1384
1385 w = 0;
1386 a = 0;
1387 d = 0;
1388
1389 n = bitmap_font_text_to_glyphs(font, text, &glyphs);
1390
1391 for (i = 0; i < n; i++) {
1392 glyph = &font->glyphs[glyphs[i]];
1393
1394 w += glyph->width;
1395
1396 if (glyph->ascent > a)
1397 a = glyph->ascent;
1398 if (glyph->descent < d)
1399 d = glyph->descent;
1400 }
1401
1402 *width = w - 1;
1403 *height = font->ascent - font->descent;
1404 *ascent = a;
1405 *descent = d;
1406
1407 if (n > 0) {
1408 free(glyphs);
1409 }
1410 }
1411
1412 static void
bitmap_font_draw_text(GdkDrawable * drawable,GdkColor * color,const bitmap_font_t * font,int x,int y,const char * text)1413 bitmap_font_draw_text(GdkDrawable *drawable, GdkColor *color,
1414 const bitmap_font_t *font,
1415 int x, int y, const char *text)
1416 {
1417 const bitmap_glyph_t *glyph;
1418 unsigned char *glyphs;
1419 GdkBitmap *bitmap;
1420 GdkGC *gc;
1421 int i, n, w, h;
1422
1423 gc = gdk_gc_new(drawable);
1424 gdk_gc_set_rgb_fg_color(gc, color);
1425
1426 n = bitmap_font_text_to_glyphs(font, text, &glyphs);
1427
1428 for (i = 0; i < n; i++) {
1429 glyph = &font->glyphs[glyphs[i]];
1430
1431 w = glyph->width - glyph->kern;
1432 h = glyph->ascent - glyph->descent;
1433
1434 if (w <= 0 || h <= 0) {
1435 x += glyph->width;
1436 continue;
1437 }
1438
1439 bitmap = gdk_bitmap_create_from_data(NULL, (char *) glyph->bits, w, h);
1440
1441 gdk_gc_set_ts_origin(gc, x + glyph->kern,
1442 y + font->ascent - glyph->ascent);
1443 gdk_gc_set_stipple(gc, bitmap);
1444 gdk_gc_set_fill(gc, GDK_STIPPLED);
1445
1446 gdk_draw_rectangle(drawable, gc, TRUE, x + glyph->kern,
1447 y + font->ascent - glyph->ascent, w, h);
1448
1449 g_object_unref(bitmap);
1450
1451 x += glyph->width;
1452 }
1453
1454 g_object_unref(gc);
1455
1456 if (n > 0) {
1457 free(glyphs);
1458 }
1459 }
1460
1461 static gboolean
x49gp_ui_button_press(GtkWidget * widget,GdkEventButton * event,gpointer user_data)1462 x49gp_ui_button_press(GtkWidget *widget, GdkEventButton *event,
1463 gpointer user_data)
1464 {
1465 x49gp_ui_button_t *button = user_data;
1466 const x49gp_ui_key_t *key = button->key;
1467 x49gp_t *x49gp = button->x49gp;
1468
1469 #ifdef DEBUG_X49GP_UI
1470 fprintf(stderr, "%s:%u: type %u, button %u\n", __FUNCTION__, __LINE__, event->type, event->button);
1471 #endif
1472
1473 if (event->type != GDK_BUTTON_PRESS)
1474 return FALSE;
1475
1476 switch (event->button) {
1477 case 1:
1478 button->down = TRUE;
1479 break;
1480 case 3:
1481 if (!button->down) {
1482 gtk_button_pressed(GTK_BUTTON(button->button));
1483 }
1484 button->down = TRUE;
1485 button->hold = TRUE;
1486 break;
1487 default:
1488 return TRUE;
1489 }
1490
1491 #ifdef DEBUG_X49GP_UI
1492 printf("%s: button %u: col %u, row %u, eint %u\n", __FUNCTION__,
1493 event->button,
1494 button->key->column, button->key->row, button->key->eint);
1495 #endif
1496
1497 if (key->rowbit) {
1498 s3c2410_io_port_g_set_bit(x49gp, key->eint, 1);
1499 x49gp->keybycol[key->column] |= key->rowbit;
1500 x49gp->keybyrow[key->row] |= key->columnbit;
1501 } else {
1502 s3c2410_io_port_f_set_bit(x49gp, key->eint, 1);
1503 }
1504
1505 return FALSE;
1506 }
1507
1508 static gboolean
x49gp_ui_button_release(GtkWidget * widget,GdkEventButton * event,gpointer user_data)1509 x49gp_ui_button_release(GtkWidget *widget, GdkEventButton *event,
1510 gpointer user_data)
1511 {
1512 x49gp_ui_button_t *button = user_data;
1513 x49gp_t *x49gp = button->x49gp;
1514 x49gp_ui_t *ui = x49gp->ui;
1515 const x49gp_ui_key_t *key;
1516 GtkButton *gtkbutton;
1517 int i;
1518
1519 if (event->type != GDK_BUTTON_RELEASE)
1520 return FALSE;
1521
1522 switch (event->button) {
1523 case 1:
1524 break;
1525 default:
1526 return TRUE;
1527 }
1528
1529 for (i = 0; i < ui->nr_buttons; i++) {
1530 button = &ui->buttons[i];
1531
1532 if (! button->down)
1533 continue;
1534
1535 #ifdef DEBUG_X49GP_UI
1536 printf("%s: button %u: col %u, row %u, eint %u\n", __FUNCTION__,
1537 event->button,
1538 button->key->column, button->key->row, button->key->eint);
1539 #endif
1540
1541 button->down = FALSE;
1542 button->hold = FALSE;
1543
1544 gtkbutton = GTK_BUTTON(button->button);
1545
1546 if (button != user_data)
1547 gtkbutton->in_button = FALSE;
1548 gtk_button_released(gtkbutton);
1549
1550 key = button->key;
1551
1552 if (key->rowbit) {
1553 s3c2410_io_port_g_set_bit(x49gp, key->eint, 0);
1554 x49gp->keybycol[key->column] &= ~(key->rowbit);
1555 x49gp->keybyrow[key->row] &= ~(key->columnbit);
1556 } else {
1557 s3c2410_io_port_f_set_bit(x49gp, key->eint, 0);
1558 }
1559 }
1560
1561 return FALSE;
1562 }
1563
1564 static gboolean
x49gp_ui_button_leave(GtkWidget * widget,GdkEventCrossing * event,gpointer user_data)1565 x49gp_ui_button_leave(GtkWidget *widget, GdkEventCrossing *event,
1566 gpointer user_data)
1567 {
1568 x49gp_ui_button_t *button = user_data;
1569
1570 if (event->type != GDK_LEAVE_NOTIFY)
1571 return FALSE;
1572
1573 if (!button->hold)
1574 return FALSE;
1575
1576 return TRUE;
1577 }
1578
1579 static gboolean
x49gp_ui_key_event(GtkWidget * widget,GdkEventKey * event,gpointer user_data)1580 x49gp_ui_key_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
1581 {
1582 x49gp_t *x49gp = user_data;
1583 x49gp_ui_t *ui = x49gp->ui;
1584 x49gp_ui_button_t *button;
1585 GdkEventButton bev;
1586 gboolean save_in;
1587 int index;
1588
1589 #ifdef DEBUG_X49GP_UI
1590 fprintf(stderr, "%s:%u: type %u, keyval %04x\n", __FUNCTION__, __LINE__, event->type, event->keyval);
1591 #endif
1592
1593 switch (event->keyval) {
1594 case GDK_A: case GDK_a: case GDK_F1: index = 0; break;
1595 case GDK_B: case GDK_b: case GDK_F2: index = 1; break;
1596 case GDK_C: case GDK_c: case GDK_F3: index = 2; break;
1597 case GDK_D: case GDK_d: case GDK_F4: index = 3; break;
1598 case GDK_E: case GDK_e: case GDK_F5: index = 4; break;
1599 case GDK_F: case GDK_f: case GDK_F6: index = 5; break;
1600 case GDK_G: case GDK_g: index = 6; break;
1601 case GDK_H: case GDK_h: index = 7; break;
1602 case GDK_I: case GDK_i: index = 8; break;
1603 case GDK_J: case GDK_j: index = 9; break;
1604 case GDK_K: case GDK_k: index = 10; break;
1605 case GDK_L: case GDK_l: index = 11; break;
1606 case GDK_Up: case GDK_KP_Up: index = 12; break;
1607 case GDK_Left: case GDK_KP_Left: index = 13; break;
1608 case GDK_Down: case GDK_KP_Down: index = 14; break;
1609 case GDK_Right: case GDK_KP_Right: index = 15; break;
1610 case GDK_M: case GDK_m: index = 16; break;
1611 case GDK_N: case GDK_n: index = 17; break;
1612 case GDK_O: case GDK_o:
1613 case GDK_apostrophe: index = 18; break;
1614 case GDK_P: case GDK_p: index = 19; break;
1615 case GDK_BackSpace: case GDK_Delete:
1616 case GDK_KP_Delete: index = 20; break;
1617 case GDK_Q: case GDK_q: index = 21; break;
1618 case GDK_R: case GDK_r: index = 22; break;
1619 case GDK_S: case GDK_s: index = 23; break;
1620 case GDK_T: case GDK_t: index = 24; break;
1621 case GDK_U: case GDK_u: index = 25; break;
1622 case GDK_V: case GDK_v: index = 26; break;
1623 case GDK_W: case GDK_w: index = 27; break;
1624 case GDK_X: case GDK_x: index = 28; break;
1625 case GDK_Y: case GDK_y: index = 29; break;
1626 case GDK_Z: case GDK_z:
1627 case GDK_slash: case GDK_KP_Divide: index = 30; break;
1628 #ifdef __APPLE__
1629 case GDK_Tab: index = 31; break;
1630 #else
1631 case GDK_Tab: index = 31; break;
1632 case GDK_Alt_L: case GDK_Alt_R:
1633 case GDK_Meta_L: case GDK_Meta_R:
1634 case GDK_Mode_switch: index = 31; break;
1635 #endif
1636 case GDK_7: case GDK_KP_7: index = 32; break;
1637 case GDK_8: case GDK_KP_8: index = 33; break;
1638 case GDK_9: case GDK_KP_9: index = 34; break;
1639 case GDK_multiply: case GDK_backslash:
1640 case GDK_KP_Multiply: index = 35; break;
1641 case GDK_Shift_L: index = 36; break;
1642 case GDK_4: case GDK_KP_4: index = 37; break;
1643 case GDK_5: case GDK_KP_5: index = 38; break;
1644 case GDK_6: case GDK_KP_6: index = 39; break;
1645 case GDK_minus: case GDK_KP_Subtract: index = 40; break;
1646 case GDK_Shift_R: case GDK_Control_L: index = 41; break;
1647 case GDK_1: case GDK_KP_1: index = 42; break;
1648 case GDK_2: case GDK_KP_2: index = 43; break;
1649 case GDK_3: case GDK_KP_3: index = 44; break;
1650 case GDK_plus: case GDK_equal:
1651 case GDK_KP_Add: index = 45; break;
1652 case GDK_Escape: index = 46; break;
1653 case GDK_0: case GDK_KP_0: index = 47; break;
1654 case GDK_period: case GDK_comma:
1655 case GDK_KP_Decimal: index = 48; break;
1656 case GDK_space: case GDK_KP_Space: index = 49; break;
1657 case GDK_Return: case GDK_KP_Enter: index = 50; break;
1658 default:
1659 return FALSE;
1660 }
1661
1662 button = &ui->buttons[index];
1663
1664 memset(&bev, 0, sizeof(GdkEventButton));
1665
1666 bev.time = event->time;
1667 bev.button = 1;
1668 bev.state = event->state;
1669
1670 save_in = GTK_BUTTON(button->button)->in_button;
1671
1672 switch (event->type) {
1673 case GDK_KEY_PRESS:
1674 bev.type = GDK_BUTTON_PRESS;
1675 x49gp_ui_button_press(button->button, &bev, button);
1676 GTK_BUTTON(button->button)->in_button = TRUE;
1677 gtk_button_pressed(GTK_BUTTON(button->button));
1678 GTK_BUTTON(button->button)->in_button = save_in;
1679 break;
1680 case GDK_KEY_RELEASE:
1681 bev.type = GDK_BUTTON_RELEASE;
1682 GTK_BUTTON(button->button)->in_button = TRUE;
1683 gtk_button_released(GTK_BUTTON(button->button));
1684 GTK_BUTTON(button->button)->in_button = save_in;
1685 x49gp_ui_button_release(button->button, &bev, button);
1686 break;
1687 default:
1688 return FALSE;
1689 }
1690
1691 return TRUE;
1692 }
1693
1694 static int
x49gp_button_expose_event(GtkWidget * widget,GdkEventExpose * event,gpointer user_data)1695 x49gp_button_expose_event(GtkWidget *widget, GdkEventExpose *event,
1696 gpointer user_data)
1697 {
1698 x49gp_ui_button_t *button = user_data;
1699 int x, y;
1700
1701 x = widget->allocation.x;
1702 y = widget->allocation.y;
1703
1704 if (GTK_WIDGET_STATE(widget) == GTK_STATE_ACTIVE)
1705 y -= 1;
1706
1707 gdk_draw_drawable(widget->window, widget->style->black_gc,
1708 button->pixmap, 0, 0, x, y,
1709 widget->allocation.width, widget->allocation.height);
1710
1711 return FALSE;
1712 }
1713
1714 static void
x49gp_button_realize(GtkWidget * widget,gpointer user_data)1715 x49gp_button_realize(GtkWidget *widget, gpointer user_data)
1716 {
1717 x49gp_ui_button_t *button = user_data;
1718 x49gp_ui_t *ui = button->x49gp->ui;
1719 const x49gp_ui_key_t *key = button->key;
1720 cairo_t *cr;
1721 double xoff, yoff, width, height, ascent, descent;
1722 unsigned int w, h;
1723 int xoffset, yoffset, x, y;
1724
1725 xoffset = widget->allocation.x;
1726 yoffset = widget->allocation.y;
1727 w = widget->allocation.width;
1728 h = widget->allocation.height;
1729
1730 button->pixmap = gdk_pixmap_new(widget->style->bg_pixmap[0], w, h, -1);
1731
1732 assert(button->pixmap);
1733
1734 gdk_draw_drawable(button->pixmap, widget->style->black_gc,
1735 widget->style->bg_pixmap[0],
1736 xoffset, yoffset,
1737 0, 0, button->key->width, button->key->height);
1738
1739 xoffset += 2;
1740 yoffset += 2;
1741 w -= 4;
1742 h -= 4;
1743
1744 cr = gdk_cairo_create(button->pixmap);
1745 assert(cr);
1746 cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
1747 cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER);
1748
1749 #if 0 /* Layout Debug */
1750 cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
1751 cairo_set_line_width(cr, 1.0);
1752 cairo_move_to(cr, xoffset, yoffset);
1753 cairo_line_to(cr, xoffset + w - 1, yoffset);
1754 cairo_line_to(cr, xoffset + w - 1, yoffset + h - 1);
1755 cairo_line_to(cr, xoffset, yoffset + h - 1);
1756 cairo_close_path(cr);
1757 cairo_stroke(cr);
1758 #endif
1759
1760 if (key->letter) {
1761 x49gp_ui_text_size(cr, X49GP_UI_NORMAL_FONT, key->letter_size,
1762 &xoff, &yoff, &width, &height, &ascent, &descent,
1763 1, CAIRO_FONT_SLANT_NORMAL, key->font_weight,
1764 key->letter);
1765
1766 switch (key->layout) {
1767 case UI_LAYOUT_LEFT:
1768 default:
1769 x = (int) floor(w - 1.0 - width - xoff + 0.5);
1770 y = (int) floor((h - 1.0 + ascent) / 2.0 + 0.5);
1771 w -= width;
1772 break;
1773 case UI_LAYOUT_LEFT_NO_SPACE:
1774 x = (int) floor(w - 1.0 - width - xoff + 0.5);
1775 y = (int) floor((h - 1.0 + ascent) / 2.0 + 0.5);
1776 break;
1777 case UI_LAYOUT_BELOW:
1778 x = (int) floor((w - 1.0 - width) / 2.0 - xoff + 0.5);
1779 y = (int) h - 1.0;
1780 h -= ascent;
1781 break;
1782 }
1783
1784 x49gp_ui_draw_text(cr, &ui->colors[UI_COLOR_YELLOW],
1785 X49GP_UI_NORMAL_FONT, key->letter_size, 0.0,
1786 x + xoffset, y + yoffset,
1787 1, CAIRO_FONT_SLANT_NORMAL, key->font_weight,
1788 key->letter);
1789 }
1790
1791 x49gp_ui_text_size(cr, X49GP_UI_NORMAL_FONT, key->font_size,
1792 &xoff, &yoff, &width, &height, &ascent, &descent,
1793 1, CAIRO_FONT_SLANT_NORMAL, key->font_weight,
1794 key->label);
1795
1796 x = (int) floor((w - 1.0 - width) / 2.0 - xoff + 0.5);
1797 y = (int) floor((h - 1.0 + ascent) / 2.0 + 0.5);
1798
1799 x49gp_ui_draw_text(cr, &widget->style->text[0],
1800 X49GP_UI_NORMAL_FONT, key->font_size, 0.0,
1801 x + xoffset, y + yoffset,
1802 1, CAIRO_FONT_SLANT_NORMAL, key->font_weight,
1803 key->label);
1804
1805 cairo_destroy(cr);
1806 }
1807
1808 static int
x49gp_lcd_expose_event(GtkWidget * widget,GdkEventExpose * event,gpointer user_data)1809 x49gp_lcd_expose_event(GtkWidget *widget, GdkEventExpose *event,
1810 gpointer user_data)
1811 {
1812 x49gp_t *x49gp = user_data;
1813 x49gp_ui_t *ui = x49gp->ui;
1814 GdkRectangle *rects;
1815 int i, n;
1816
1817 gdk_region_get_rectangles(event->region, &rects, &n);
1818 for (i = 0; i < n; i++) {
1819 gdk_draw_drawable(widget->window, widget->style->black_gc,
1820 ui->lcd_pixmap,
1821 rects[i].x, rects[i].y,
1822 rects[i].x, rects[i].y,
1823 rects[i].width, rects[i].height);
1824 }
1825 g_free(rects);
1826
1827 return FALSE;
1828 }
1829
1830 static int
x49gp_lcd_configure_event(GtkWidget * widget,GdkEventConfigure * event,gpointer user_data)1831 x49gp_lcd_configure_event(GtkWidget *widget, GdkEventConfigure *event,
1832 gpointer user_data)
1833 {
1834 x49gp_t *x49gp = user_data;
1835 x49gp_ui_t *ui = x49gp->ui;
1836
1837 if (NULL != ui->lcd_pixmap) {
1838 return FALSE;
1839 }
1840
1841 ui->ann_left = gdk_bitmap_create_from_data(ui->lcd_canvas->window,
1842 (char *) ann_left_bits,
1843 ann_left_width,
1844 ann_left_height);
1845 ui->ann_right = gdk_bitmap_create_from_data(ui->lcd_canvas->window,
1846 (char *) ann_right_bits,
1847 ann_right_width,
1848 ann_right_height);
1849 ui->ann_alpha = gdk_bitmap_create_from_data(ui->lcd_canvas->window,
1850 (char *) ann_alpha_bits,
1851 ann_alpha_width,
1852 ann_alpha_height);
1853 ui->ann_battery = gdk_bitmap_create_from_data(ui->lcd_canvas->window,
1854 (char *) ann_battery_bits,
1855 ann_battery_width,
1856 ann_battery_height);
1857 ui->ann_busy = gdk_bitmap_create_from_data(ui->lcd_canvas->window,
1858 (char *) ann_busy_bits,
1859 ann_busy_width,
1860 ann_busy_height);
1861 ui->ann_io = gdk_bitmap_create_from_data(ui->lcd_canvas->window,
1862 (char *) ann_io_bits,
1863 ann_io_width,
1864 ann_io_height);
1865
1866 ui->ann_left_gc = gdk_gc_new(ui->lcd_canvas->window);
1867 gdk_gc_copy(ui->ann_left_gc, widget->style->black_gc);
1868 gdk_gc_set_ts_origin(ui->ann_left_gc, 11, 0);
1869 gdk_gc_set_stipple(ui->ann_left_gc, ui->ann_left);
1870 gdk_gc_set_fill(ui->ann_left_gc, GDK_STIPPLED);
1871
1872 ui->ann_right_gc = gdk_gc_new(ui->lcd_canvas->window);
1873 gdk_gc_copy(ui->ann_right_gc, widget->style->black_gc);
1874 gdk_gc_set_ts_origin(ui->ann_right_gc, 56, 0);
1875 gdk_gc_set_stipple(ui->ann_right_gc, ui->ann_right);
1876 gdk_gc_set_fill(ui->ann_right_gc, GDK_STIPPLED);
1877
1878 ui->ann_alpha_gc = gdk_gc_new(ui->lcd_canvas->window);
1879 gdk_gc_copy(ui->ann_alpha_gc, widget->style->black_gc);
1880 gdk_gc_set_ts_origin(ui->ann_alpha_gc, 101, 0);
1881 gdk_gc_set_stipple(ui->ann_alpha_gc, ui->ann_alpha);
1882 gdk_gc_set_fill(ui->ann_alpha_gc, GDK_STIPPLED);
1883
1884 ui->ann_battery_gc = gdk_gc_new(ui->lcd_canvas->window);
1885 gdk_gc_copy(ui->ann_battery_gc, widget->style->black_gc);
1886 gdk_gc_set_ts_origin(ui->ann_battery_gc, 146, 0);
1887 gdk_gc_set_stipple(ui->ann_battery_gc, ui->ann_battery);
1888 gdk_gc_set_fill(ui->ann_battery_gc, GDK_STIPPLED);
1889
1890 ui->ann_busy_gc = gdk_gc_new(ui->lcd_canvas->window);
1891 gdk_gc_copy(ui->ann_busy_gc, widget->style->black_gc);
1892 gdk_gc_set_ts_origin(ui->ann_busy_gc, 191, 0);
1893 gdk_gc_set_stipple(ui->ann_busy_gc, ui->ann_busy);
1894 gdk_gc_set_fill(ui->ann_busy_gc, GDK_STIPPLED);
1895
1896 ui->ann_io_gc = gdk_gc_new(ui->lcd_canvas->window);
1897 gdk_gc_copy(ui->ann_io_gc, widget->style->black_gc);
1898 gdk_gc_set_ts_origin(ui->ann_io_gc, 236, 0);
1899 gdk_gc_set_stipple(ui->ann_io_gc, ui->ann_io);
1900 gdk_gc_set_fill(ui->ann_io_gc, GDK_STIPPLED);
1901
1902
1903 ui->lcd_pixmap = gdk_pixmap_new(ui->lcd_canvas->window,
1904 ui->lcd_width, ui->lcd_height, -1);
1905
1906 #if 0 /* Debug Symbols on LCD screen ;) */
1907 {
1908 cairo_t *cr;
1909
1910 cr = gdk_cairo_create(ui->bg_pixmap);
1911 cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
1912 cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER);
1913
1914 #if 1
1915 x49gp_ui_draw_text(cr, &widget->style->black,
1916 X49GP_UI_NORMAL_FONT, 100.0, 1.0,
1917 ui->lcd_x_offset + 10, ui->lcd_y_offset + 160,
1918 1, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD,
1919 "\\arrowleftdblfull");
1920 #else
1921 x49gp_ui_dump_path(cr, X49GP_UI_NORMAL_FONT,
1922 1, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD,
1923 "\\arrowleftdblfull");
1924 #endif
1925
1926 cairo_destroy(cr);
1927 }
1928 #endif
1929
1930 gdk_draw_drawable(ui->lcd_pixmap, widget->style->black_gc,
1931 ui->bg_pixmap, ui->lcd_x_offset, ui->lcd_y_offset,
1932 0, 0, ui->lcd_width, ui->lcd_height);
1933
1934 return FALSE;
1935 }
1936
1937 static int
x49gp_window_configure_event(GtkWidget * widget,GdkEventConfigure * event,gpointer user_data)1938 x49gp_window_configure_event(GtkWidget *widget, GdkEventConfigure *event,
1939 gpointer user_data)
1940 {
1941 x49gp_t *x49gp = user_data;
1942 x49gp_ui_t *ui = x49gp->ui;
1943 const x49gp_ui_key_t *key;
1944 cairo_t *cr;
1945 int left_color;
1946 int right_color;
1947 int below_color;
1948 int xl, xr, a;
1949 int wl = 0, wr = 0;
1950 int hl = 0, hr = 0;
1951 int dl = 0, dr = 0;
1952 int i;
1953
1954 if (NULL != ui->bg_pixmap) {
1955 return FALSE;
1956 }
1957
1958 ui->bg_pixmap = gdk_pixmap_new(widget->window,
1959 ui->width, ui->height, -1);
1960
1961 gdk_draw_pixbuf(ui->bg_pixmap, widget->style->black_gc,
1962 ui->bg_pixbuf, 0, 0, 0, 0, ui->width, ui->height,
1963 GDK_RGB_DITHER_NORMAL, 0, 0);
1964
1965 cr = gdk_cairo_create(ui->bg_pixmap);
1966 cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
1967 cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER);
1968
1969 switch (ui->calculator) {
1970 default:
1971 ui->calculator = UI_CALCULATOR_HP49GP;
1972 /* fall through */
1973
1974 case UI_CALCULATOR_HP49GP:
1975 x49gp_ui_draw_text(cr, &widget->style->black,
1976 X49GP_UI_NORMAL_FONT, 15.0, 0.0,
1977 38, 42, 2,
1978 CAIRO_FONT_SLANT_NORMAL,
1979 CAIRO_FONT_WEIGHT_BOLD,
1980 "hp",
1981 CAIRO_FONT_SLANT_NORMAL,
1982 CAIRO_FONT_WEIGHT_NORMAL,
1983 " 49g+");
1984
1985 x49gp_ui_draw_text(cr, &widget->style->black,
1986 X49GP_UI_NORMAL_FONT, 13.0, 0.0,
1987 38, 56, 1,
1988 CAIRO_FONT_SLANT_NORMAL,
1989 CAIRO_FONT_WEIGHT_NORMAL,
1990 "graphing calculator");
1991
1992 x49gp_ui_draw_symbol(cr, &widget->style->black, 10.0, 0.0, TRUE,
1993 138, 25, symbol_get_by_name("triangleup"));
1994
1995 left_color = UI_COLOR_GREEN;
1996 right_color = UI_COLOR_RED;
1997 below_color = UI_COLOR_BLACK;
1998 break;
1999
2000 case UI_CALCULATOR_HP50G:
2001 x49gp_ui_draw_text(cr, &widget->style->white,
2002 X49GP_UI_NORMAL_FONT, 15.0, 0.0,
2003 38, 42, 2,
2004 CAIRO_FONT_SLANT_NORMAL,
2005 CAIRO_FONT_WEIGHT_NORMAL,
2006 "HP",
2007 CAIRO_FONT_SLANT_NORMAL,
2008 CAIRO_FONT_WEIGHT_NORMAL,
2009 " 50g");
2010
2011 x49gp_ui_draw_text(cr, &widget->style->white,
2012 X49GP_UI_NORMAL_FONT, 13.0, 0.0,
2013 38, 56, 1,
2014 CAIRO_FONT_SLANT_NORMAL,
2015 CAIRO_FONT_WEIGHT_NORMAL,
2016 "Graphing Calculator");
2017
2018 x49gp_ui_draw_symbol(cr, &widget->style->white, 10.0, 0.0, TRUE,
2019 168, 25, symbol_get_by_name("triangleup"));
2020
2021 left_color = UI_COLOR_WHITE;
2022 right_color = UI_COLOR_ORANGE;
2023 below_color = UI_COLOR_BLUE;
2024 break;
2025 }
2026
2027 cairo_destroy(cr);
2028
2029 for (i = 0; i < ui->nr_buttons; i++) {
2030 key = &x49gp_ui_keys[i];
2031 key = &x50g_ui_keys[i];
2032
2033 if (key->left) {
2034 bitmap_font_text_size(&tiny_font, key->left, &wl, &hl, &a, &dl);
2035 if (!key->right) {
2036 xl = key->x + (key->width - wl) / 2;
2037 bitmap_font_draw_text(ui->bg_pixmap,
2038 &ui->colors[left_color],
2039 &tiny_font,
2040 ui->kb_x_offset + xl,
2041 ui->kb_y_offset + key->y - hl + dl + 1,
2042 key->left);
2043 }
2044 }
2045
2046 if (key->right) {
2047 bitmap_font_text_size(&tiny_font, key->right, &wr, &hr, &a, &dr);
2048 if (!key->left) {
2049 xr = key->x + (key->width - wr) / 2;
2050 bitmap_font_draw_text(ui->bg_pixmap,
2051 &ui->colors[right_color],
2052 &tiny_font,
2053 ui->kb_x_offset + xr,
2054 ui->kb_y_offset + key->y - hr + dr + 1,
2055 key->right);
2056 }
2057 }
2058
2059 if (key->left && key->right) {
2060 xl = key->x;
2061 xr = key->x + key->width - 1 - wr;
2062
2063 if (wl + wr > key->width - 4) {
2064 xl += (key->width - 4 - (wl + wr)) / 2;
2065 xr -= (key->width - 4 - (wl + wr)) / 2;
2066 }
2067
2068 bitmap_font_draw_text(ui->bg_pixmap,
2069 &ui->colors[left_color],
2070 &tiny_font,
2071 ui->kb_x_offset + xl,
2072 ui->kb_y_offset + key->y - hl + dl + 1,
2073 key->left);
2074
2075 bitmap_font_draw_text(ui->bg_pixmap,
2076 &ui->colors[right_color],
2077 &tiny_font,
2078 ui->kb_x_offset + xr,
2079 ui->kb_y_offset + key->y - hr + dr + 1,
2080 key->right);
2081 }
2082
2083 if (key->below) {
2084 bitmap_font_text_size(&tiny_font, key->below, &wl, &hl, &a, &dl);
2085 xl = key->x + (key->width - wl) / 2;
2086
2087 bitmap_font_draw_text(ui->bg_pixmap,
2088 &ui->colors[below_color],
2089 &tiny_font,
2090 ui->kb_x_offset + xl,
2091 ui->kb_y_offset + key->y + key->height + 2,
2092 key->below);
2093 }
2094
2095 #if 0 /* Debug Button Layout */
2096 gdk_draw_rectangle(ui->bg_pixmap, ui->window->style->white_gc,
2097 FALSE,
2098 ui->kb_x_offset + key->x,
2099 ui->kb_y_offset + key->y,
2100 key->width, key->height);
2101 #endif
2102 }
2103
2104 gdk_window_set_back_pixmap(widget->window, ui->bg_pixmap, FALSE);
2105
2106 return FALSE;
2107 }
2108
2109 static gboolean
x49gp_window_button_press(GtkWidget * widget,GdkEventButton * event,gpointer user_data)2110 x49gp_window_button_press(GtkWidget *widget, GdkEventButton *event,
2111 gpointer user_data)
2112 {
2113 #ifdef DEBUG_X49GP_UI
2114 fprintf(stderr, "%s:%u: type %u, button %u\n", __FUNCTION__, __LINE__, event->type, event->button);
2115 #endif
2116
2117 gdk_window_focus(widget->window, event->time);
2118 gdk_window_raise(widget->window);
2119
2120 if (event->type != GDK_BUTTON_PRESS)
2121 return FALSE;
2122
2123 if (event->button != 1)
2124 return FALSE;
2125
2126 gdk_window_begin_move_drag(widget->window, event->button,
2127 event->x_root, event->y_root,
2128 event->time);
2129
2130 return FALSE;
2131 }
2132
2133 static void
x49gp_ui_quit(GtkWidget * widget,GdkEvent * event,gpointer user_data)2134 x49gp_ui_quit(GtkWidget *widget, GdkEvent *event, gpointer user_data)
2135 {
2136 x49gp_t *x49gp = user_data;
2137
2138 x49gp->arm_exit++;
2139 }
2140
2141 static void
x49gp_ui_place_at(x49gp_t * x49gp,GtkFixed * fixed,GtkWidget * widget,gint x,gint y,gint width,gint height)2142 x49gp_ui_place_at(x49gp_t *x49gp, GtkFixed *fixed, GtkWidget *widget,
2143 gint x, gint y, gint width, gint height)
2144 {
2145 gtk_widget_set_size_request(widget, width, height);
2146 gtk_fixed_put(fixed, widget, x, y);
2147 }
2148
2149 static int
gui_init(x49gp_module_t * module)2150 gui_init(x49gp_module_t *module)
2151 {
2152 x49gp_t *x49gp = module->x49gp;
2153 x49gp_ui_t *ui;
2154
2155 ui = malloc(sizeof(x49gp_ui_t));
2156 if (NULL == ui) {
2157 fprintf(stderr, "%s: %s:%u: Out of memory\n",
2158 x49gp->progname, __FUNCTION__, __LINE__);
2159 return -ENOMEM;
2160 }
2161 memset(ui, 0, sizeof(x49gp_ui_t));
2162
2163 ui->nr_buttons = X49GP_UI_NR_KEYS;
2164 ui->buttons = malloc(ui->nr_buttons * sizeof(x49gp_ui_button_t));
2165 if (NULL == ui->buttons) {
2166 fprintf(stderr, "%s: %s:%u: Out of memory\n",
2167 x49gp->progname, __FUNCTION__, __LINE__);
2168 free(ui);
2169 return -ENOMEM;
2170 }
2171 memset(ui->buttons, 0, ui->nr_buttons * sizeof(x49gp_ui_button_t));
2172
2173 module->user_data = ui;
2174 x49gp->ui = ui;
2175
2176 return 0;
2177 }
2178
2179 static int
gui_exit(x49gp_module_t * module)2180 gui_exit(x49gp_module_t *module)
2181 {
2182 return 0;
2183 }
2184
2185 static int
gui_reset(x49gp_module_t * module,x49gp_reset_t reset)2186 gui_reset(x49gp_module_t *module, x49gp_reset_t reset)
2187 {
2188 return 0;
2189 }
2190
2191 static int
gui_load(x49gp_module_t * module,GKeyFile * keyfile)2192 gui_load(x49gp_module_t *module, GKeyFile *keyfile)
2193 {
2194 x49gp_t *x49gp = module->x49gp;
2195 x49gp_ui_t *ui = module->user_data;
2196 x49gp_ui_button_t *button;
2197 const x49gp_ui_key_t *key;
2198 GError *gerror = NULL;
2199 GdkBitmap *shape;
2200 char *imagefile;
2201 char *name;
2202 int i;
2203
2204 imagefile = x49gp_module_get_filename(module, keyfile, "image");
2205 x49gp_module_get_string(module, keyfile, "name", "hp49g+", &name);
2206
2207 if (access(imagefile, R_OK) == -1) {
2208 fprintf(stderr, "Calculator skin file \"%s\" not accessible.\n", imagefile);
2209 return 1;
2210 }
2211
2212 if (!strcmp(name, "hp49g+")) {
2213 ui->calculator = UI_CALCULATOR_HP49GP;
2214 } else if (!strcmp(name, "hp50g")) {
2215 ui->calculator = UI_CALCULATOR_HP50G;
2216 } else {
2217 ui->calculator = 0;
2218 }
2219
2220 gdk_pixbuf_get_file_info(imagefile, &ui->width, &ui->height);
2221
2222 ui->lcd_width = 131 * 2;
2223 ui->lcd_top_margin = 16;
2224 ui->lcd_height = 80 * 2 + ui->lcd_top_margin;
2225
2226 ui->lcd_x_offset = (ui->width - ui->lcd_width) / 2;
2227 ui->lcd_y_offset = 69;
2228
2229 ui->kb_x_offset = 36;
2230 ui->kb_y_offset = 301;
2231
2232 ui->bg_pixbuf = gdk_pixbuf_new_from_file(imagefile, &gerror);
2233
2234
2235 ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2236 gtk_widget_set(ui->window, "can-focus", TRUE, NULL);
2237 gtk_widget_set(ui->window, "accept-focus", TRUE, NULL);
2238 gtk_widget_set(ui->window, "focus-on-map", TRUE, NULL);
2239 gtk_widget_set(ui->window, "resizable", FALSE, NULL);
2240 gtk_window_set_decorated(GTK_WINDOW(ui->window), FALSE);
2241
2242 gtk_widget_set_name(ui->window, name);
2243 gtk_window_set_title(GTK_WINDOW(ui->window), name);
2244
2245 // gtk_window_set_icon(GTK_WINDOW(ui->window), ui->bg_pixbuf);
2246
2247 gdk_pixbuf_render_pixmap_and_mask(ui->bg_pixbuf, NULL, &shape, 255);
2248
2249 gtk_widget_set_size_request(ui->window, ui->width, ui->height);
2250 gtk_widget_shape_combine_mask(ui->window, shape, 0, 0);
2251
2252 g_object_unref(shape);
2253
2254 gtk_widget_realize(ui->window);
2255
2256 ui->shapes[UI_SHAPE_BUTTON_TINY] = gdk_bitmap_create_from_data(NULL,
2257 (char *) button_tiny_bits,
2258 button_tiny_width,
2259 button_tiny_height);
2260 ui->shapes[UI_SHAPE_BUTTON_SMALL] = gdk_bitmap_create_from_data(NULL,
2261 (char *) button_small_bits,
2262 button_small_width,
2263 button_small_height);
2264 ui->shapes[UI_SHAPE_BUTTON_NORMAL] = gdk_bitmap_create_from_data(NULL,
2265 (char *) button_normal_bits,
2266 button_normal_width,
2267 button_normal_height);
2268 ui->shapes[UI_SHAPE_BUTTON_LARGE] = gdk_bitmap_create_from_data(NULL,
2269 (char *) button_large_bits,
2270 button_large_width,
2271 button_large_height);
2272 ui->shapes[UI_SHAPE_BUTTON_ROUND] = gdk_bitmap_create_from_data(NULL,
2273 (char *) button_round_bits,
2274 button_round_width,
2275 button_round_height);
2276
2277
2278 ui->fixed = gtk_fixed_new();
2279 gtk_container_add(GTK_CONTAINER(ui->window), ui->fixed);
2280
2281 ui->background = gtk_drawing_area_new();
2282 gtk_drawing_area_size(GTK_DRAWING_AREA(ui->background),
2283 ui->width, ui->height);
2284 x49gp_ui_place_at(x49gp, GTK_FIXED(ui->fixed), ui->background,
2285 0, 0, ui->width, ui->height);
2286
2287 x49gp_ui_color_init(&ui->colors[UI_COLOR_BLACK], 0x00, 0x00, 0x00);
2288 x49gp_ui_color_init(&ui->colors[UI_COLOR_WHITE], 0xff, 0xff, 0xff);
2289 x49gp_ui_color_init(&ui->colors[UI_COLOR_YELLOW], 0xfa, 0xe8, 0x2c);
2290 x49gp_ui_color_init(&ui->colors[UI_COLOR_RED], 0x8e, 0x25, 0x18);
2291 x49gp_ui_color_init(&ui->colors[UI_COLOR_GREEN], 0x14, 0x4d, 0x49);
2292 x49gp_ui_color_init(&ui->colors[UI_COLOR_SILVER], 0xe0, 0xe0, 0xe0);
2293 x49gp_ui_color_init(&ui->colors[UI_COLOR_ORANGE], 0xc0, 0x6e, 0x60);
2294 x49gp_ui_color_init(&ui->colors[UI_COLOR_BLUE], 0x40, 0x60, 0xa4);
2295
2296 x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_0], 0xab, 0xd2, 0xb4);
2297 x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_1], 0xa0, 0xc4, 0xa8);
2298 x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_2], 0x94, 0xb6, 0x9c);
2299 x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_3], 0x89, 0xa8, 0x90);
2300 x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_4], 0x7d, 0x9a, 0x84);
2301 x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_5], 0x72, 0x8c, 0x78);
2302 x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_6], 0x67, 0x7e, 0x6c);
2303 x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_7], 0x5b, 0x70, 0x60);
2304 x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_8], 0x50, 0x62, 0x54);
2305 x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_9], 0x44, 0x54, 0x48);
2306 x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_10], 0x39, 0x46, 0x3c);
2307 x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_11], 0x2e, 0x38, 0x30);
2308 x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_12], 0x22, 0x2a, 0x24);
2309 x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_13], 0x17, 0x1c, 0x18);
2310 x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_14], 0x0b, 0x03, 0x0c);
2311 x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_15], 0x00, 0x00, 0x00);
2312
2313
2314 ui->lcd_canvas = gtk_drawing_area_new();
2315 gtk_drawing_area_size(GTK_DRAWING_AREA(ui->lcd_canvas),
2316 ui->lcd_width, ui->lcd_height);
2317 x49gp_ui_place_at(x49gp, GTK_FIXED(ui->fixed), ui->lcd_canvas,
2318 ui->lcd_x_offset, ui->lcd_y_offset,
2319 ui->lcd_width, ui->lcd_height);
2320
2321
2322 for (i = 0; i < ui->nr_buttons; i++) {
2323 key = &x49gp_ui_keys[i];
2324 key = &x50g_ui_keys[i];
2325 button = &ui->buttons[i];
2326
2327 button->x49gp = x49gp;
2328 button->key = key;
2329
2330 button->button = gtk_button_new();
2331 gtk_widget_set_size_request(button->button,
2332 key->width, key->height);
2333 gtk_widget_set(button->button, "can-focus", FALSE, NULL);
2334
2335 x49gp_ui_button_pixmaps_init(x49gp, button, key->color);
2336
2337 if (key->label) {
2338 button->label = gtk_label_new("");
2339 gtk_widget_set_style(button->label,
2340 button->button->style);
2341 gtk_container_add(GTK_CONTAINER(button->button),
2342 button->label);
2343
2344 g_signal_connect(G_OBJECT(button->label),
2345 "expose-event",
2346 G_CALLBACK(x49gp_button_expose_event),
2347 button);
2348
2349 g_signal_connect_after(G_OBJECT(button->label),
2350 "realize",
2351 G_CALLBACK(x49gp_button_realize),
2352 button);
2353 }
2354
2355 button->box = gtk_event_box_new();
2356 gtk_event_box_set_visible_window(GTK_EVENT_BOX(button->box),
2357 TRUE);
2358 gtk_event_box_set_above_child(GTK_EVENT_BOX(button->box),
2359 FALSE);
2360 gtk_widget_shape_combine_mask(button->box,
2361 ui->shapes[key->shape], 0, 0);
2362 gtk_container_add(GTK_CONTAINER(button->box), button->button);
2363
2364
2365 x49gp_ui_place_at(x49gp, GTK_FIXED(ui->fixed), button->box,
2366 ui->kb_x_offset + key->x,
2367 ui->kb_y_offset + key->y,
2368 key->width, key->height);
2369
2370 g_signal_connect(G_OBJECT(button->button),
2371 "button-press-event",
2372 G_CALLBACK(x49gp_ui_button_press), button);
2373
2374 g_signal_connect(G_OBJECT(button->button),
2375 "button-release-event",
2376 G_CALLBACK(x49gp_ui_button_release), button);
2377
2378 g_signal_connect(G_OBJECT(button->button),
2379 "leave-notify-event",
2380 G_CALLBACK(x49gp_ui_button_leave), button);
2381
2382 gtk_widget_add_events(button->button,
2383 GDK_BUTTON_PRESS_MASK |
2384 GDK_BUTTON_RELEASE_MASK |
2385 GDK_LEAVE_NOTIFY_MASK);
2386 }
2387
2388 g_signal_connect(G_OBJECT(ui->background), "configure-event",
2389 G_CALLBACK(x49gp_window_configure_event), x49gp);
2390
2391 g_signal_connect(G_OBJECT(ui->lcd_canvas), "expose-event",
2392 G_CALLBACK(x49gp_lcd_expose_event), x49gp);
2393 g_signal_connect(G_OBJECT(ui->lcd_canvas), "configure-event",
2394 G_CALLBACK(x49gp_lcd_configure_event), x49gp);
2395
2396 g_signal_connect(G_OBJECT(ui->window), "delete-event",
2397 G_CALLBACK(x49gp_ui_quit), x49gp);
2398 g_signal_connect(G_OBJECT(ui->window), "destroy",
2399 G_CALLBACK(x49gp_ui_quit), x49gp);
2400
2401 g_signal_connect(G_OBJECT(ui->window), "key-press-event",
2402 G_CALLBACK(x49gp_ui_key_event), x49gp);
2403 g_signal_connect(G_OBJECT(ui->window), "key-release-event",
2404 G_CALLBACK(x49gp_ui_key_event), x49gp);
2405
2406 g_signal_connect(G_OBJECT(ui->window), "button-press-event",
2407 G_CALLBACK(x49gp_window_button_press), x49gp);
2408
2409 gtk_widget_add_events(ui->window,
2410 GDK_BUTTON_PRESS_MASK |
2411 GDK_KEY_PRESS_MASK |
2412 GDK_KEY_RELEASE_MASK);
2413
2414 gtk_widget_show_all(ui->window);
2415 return 0;
2416 }
2417
2418 static int
gui_save(x49gp_module_t * module,GKeyFile * keyfile)2419 gui_save(x49gp_module_t *module, GKeyFile *keyfile)
2420 {
2421 return 0;
2422 }
2423
2424 int
x49gp_ui_init(x49gp_t * x49gp)2425 x49gp_ui_init(x49gp_t *x49gp)
2426 {
2427 x49gp_module_t *module;
2428
2429 if (x49gp_module_init(x49gp, "gui", gui_init, gui_exit,
2430 gui_reset, gui_load, gui_save, NULL,
2431 &module)) {
2432 return -1;
2433 }
2434
2435 return x49gp_module_register(module);
2436 }
2437