1
0
Fork 0
forked from Miroirs/x49gp
x50ng/ui.c
claudiol c61f11cff2 On behalf of: 3298 - Applied 23 patches by 3298:
Misc changes, mostly fixes:
- fix ./newconfig systems other than OSX (broke in c8b823f)
- fix palette usage in 2-bit color mode (was broken ever since grayscale was implemented in 18e1003 and its improperly attributed copy f7913eb)
- fix continuing from breakpoints in the debugger (never worked, was exposed when the debugger was enabled in 9c1f2ed)
- restore the printf statements commented out in 9c1f2ed and hide them with #ifdefs instead
- close the server socket after accepting a debugger connection to allow another simultaneous debug session to be started using the same TCP port
- use the symbolic constant DEFAULT_GDBSTUB_PORT (already defined in gdb_stub.h as 1234) when starting the gdb server in main.c in place of the raw number 1234
- change Makefile to read the name of the firmware file from the file update.scp instead of hardcoding it; this allows users to switch to another firmware
by simply pasting it along with its accompanying update.scp into the x49gp directory

- Enhance port G (keyboard) handling to remember the value of output bits across periods with these bits configured as input
This fixes interaction with HPGCC3 keyboard routines, and it also fixes keys with eint==7 (assuming the stock firmware is in use)
needing a double-tap to work unless pressed very shortly after another keypress (the latter broke in b5f93ed)
- Get rid of the deprecated function warning by switching from gdk_pixbuf_new_from_inline to gdk_pixbuf_new_from_data (based on code by chwdt)
- Delete remaining now-redundant CVS files
- Don't release all buttons anymore if there are still physical keys and/or the left mouse button are holding some down
On the other hand, forcibly release all buttons when losing focus to avoid getting stuck in a state with buttons down
when they are not held down by anything; this would happen due to missed events while not in focus
- Add a context menu to the screen, containing only "Reset" and "Quit" items for now
- Ensure that the files backing flash, sram, and s3c2410-sram exist and have the correct size when opening them
Note that if the flash file does not exist, this will not fill it with the code that's supposed to be in there, obviously causing the calculator to crash. That's an improvement for later.
- Allow the config system to fill not only numbers, but also strings (including filenames) with default values
basename is excluded, but it's planned to be dropped entirely.
- Add an "install" target to the Makefile
- Implement a more generic command-line parser for substantially improved flexibility
- Also adds a proper help option, though the manual referenced in the corresponding output (a manpage, hopefully) does not exist yet.
- Drop the "basename" config property in favor of interpreting relative paths in the config as relative to the config file's location
- Retire the "image" config property in favor of simply loading the image from next to the binary or from the install directory
- Split the UI name property into name (affecting only the window title) and type (affecting the UI image and in the future also the default bootcode) properties
- Change the default calculator type to the 50g everywhere, which probably matches today's user expectations better than the 49g+.
- Create a flash file from the calculator model's appropriate boot file if it does not exist, relying on the bootcode to detect the absence of a firmware
  The bootcode will complain about the missing firmware and enter update mode, so the user needs to supply their favorite firmware version and point the bootcode's updater to it.
  The easiest way is probably pointing the emulated SD card at a directory containing the firmware and its accompanying update.scp file, and then starting the SD-based update.
- Add SD mount / unmount options to the right-click / menu-key popup menu
- Remove most of the old script-based config-generating system since the binary now has these capabilities as well
- Add an applications menu item for installing
- Keep some debug output on stderr and a huge vvfat.log file from showing up when not debugging x49gp itself
- Allow (re-)connecting a debugger to a running session
  This is done through the right-click / menu-key popup menu.
  To avoid confusion due to the accidental clicks leading to an unresponsive interface (caused by waiting for the debugger to connect),
  this option is hidden unless option -d or its new companion -D (same as -d, but does not start the debug interface right away) is present.
- Improved support for hardware keyboards
- Update README.md, add manpage, rename other README files to TODO to reflect their contents
2018-05-07 17:32:14 -04:00

2737 lines
70 KiB
C

/* $Id: ui.c,v 1.34 2008/12/11 12:18:17 ecd Exp $
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/times.h>
#include <math.h>
#include <errno.h>
#include <arpa/inet.h> /* For ntohl() */
#include <gtk/gtk.h>
#include <glib.h>
#include <cairo.h>
#include <x49gp.h>
#include <x49gp_ui.h>
#include <s3c2410.h>
#include <bitmaps.h>
#include <bitmap_font.h>
#include <symbol.h>
#include <glyphname.h>
#include "gdbstub.h"
#include <gdk/gdkkeysyms.h>
#if defined(__linux__)
#define X49GP_UI_NORMAL_FONT "urw gothic l"
#else
#define X49GP_UI_NORMAL_FONT "Century Gothic"
#endif
static const x49gp_ui_key_t x49gp_ui_keys[] =
{
{
"F1", "A", "Y=", NULL, NULL,
UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
0, 0, 36, 22, 5, 1, (1 << 5), (1 << 1), 1
},
{
"F2", "B", "WIN", NULL, NULL,
UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
50, 0, 36, 22, 5, 2, (1 << 5), (1 << 2), 2
},
{
"F3", "C", "GRAPH", NULL, NULL,
UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
99, 0, 36, 22, 5, 3, (1 << 5), (1 << 3), 3
},
{
"F4", "D", "2D/3D", NULL, NULL,
UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
149, 0, 36, 22, 5, 4, (1 << 5), (1 << 4), 4
},
{
"F5", "E", "TBLSET", NULL, NULL,
UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
198, 0, 36, 22, 5, 5, (1 << 5), (1 << 5), 5
},
{
"F6", "F", "TABLE", NULL, NULL,
UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
247, 0, 36, 22, 5, 6, (1 << 5), (1 << 6), 6
},
{
"APPS", "G", "FILES", "BEGIN", NULL,
UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
0, 44, 36, 28, 5, 7, (1 << 5), (1 << 7), 7
},
{
"MODE", "H", "CUSTOM", "END", NULL,
UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
50, 44, 36, 28, 6, 5, (1 << 6), (1 << 5), 5
},
{
"TOOL", "I", "i", "I", NULL,
UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
99, 44, 36, 28, 6, 6, (1 << 6), (1 << 6), 6
},
{
"V\\kern-1 AR", "J", "UPDIR", "COPY", NULL,
UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
0, 92, 36, 28, 6, 7, (1 << 6), (1 << 7), 7
},
{
"STO \\triangleright", "K", "RCL", "CUT", NULL,
UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
50, 92, 36, 28, 7, 1, (1 << 7), (1 << 1), 1
},
{
"NXT", "L", "PREV", "PASTE", NULL,
UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
99, 92, 36, 28, 7, 2, (1 << 7), (1 << 2), 2
},
{
NULL, NULL, NULL, NULL, NULL,
UI_COLOR_SILVER, 0.0, 0,
UI_SHAPE_BUTTON_ROUND, 0.0, 0,
200, 38, 33, 33, 6, 1, (1 << 6), (1 << 1), 1
},
{
NULL, NULL, NULL, NULL, NULL,
UI_COLOR_SILVER, 0.0, 0,
UI_SHAPE_BUTTON_ROUND, 0.0, 0,
164, 66, 33, 33, 6, 2, (1 << 6), (1 << 2), 2
},
{
NULL, NULL, NULL, NULL, NULL,
UI_COLOR_SILVER, 0.0, 0,
UI_SHAPE_BUTTON_ROUND, 0.0, 0,
200, 94, 33, 33, 6, 3, (1 << 6), (1 << 3), 3
},
{
NULL, NULL, NULL, NULL, NULL,
UI_COLOR_SILVER, 0.0, 0,
UI_SHAPE_BUTTON_ROUND, 0.0, 0,
236, 66, 33, 33, 6, 4, (1 << 6), (1 << 4), 4
},
{
"HIST", "M", "CMD", "UNDO", NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
0, 141, 46, 28, 4, 1, (1 << 4), (1 << 1), 1
},
{
"EV\\kern-1 AL", "N", "PRG", "CHARS", NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
59, 141, 46, 28, 3, 1, (1 << 3), (1 << 1), 1
},
{
"\\tick", "O", "MTRW", "EQW", NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
119, 141, 46, 28, 2, 1, (1 << 2), (1 << 1), 1
},
{
"S\\kern-1 Y\\kern-1 M\\kern-1 B", "P", "MTH", "CAT", NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
179, 141, 46, 28, 1, 1, (1 << 1), (1 << 1), 1
},
{
"\\arrowleftdblfull", NULL, "DEL", "CLEAR", NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 0.0, 0,
238, 141, 46, 28, 0, 1, (1 << 0), (1 << 1), 1
},
{
"Y\\super x\\/super", "Q", "\\math_e\\xsuperior", "LN", NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
0, 183, 46, 28, 4, 2, (1 << 4), (1 << 2), 2
},
{
"\\radical\\overscore\\kern-7 X", "R",
"\\math_x\\twosuperior",
"\\xsuperior\\kern-4\\math_radical\\overscore\\kern-5\\math_y",
NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
59, 183, 46, 28, 3, 2, (1 << 3), (1 << 2), 2
},
{
"SIN", "S", "ASIN", "\\math_summation", NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
119, 183, 46, 28, 2, 2, (1 << 2), (1 << 2), 2
},
{
"COS", "T", "ACOS", "\\math_partialdiff", NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
179, 183, 46, 28, 1, 2, (1 << 1), (1 << 2), 2
},
{
"TAN", "U", "ATAN", "\\math_integral", NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
238, 183, 46, 28, 0, 2, (1 << 0), (1 << 2), 2
},
{
"EEX", "V", "10\\xsuperior", "LOG", NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
0, 225, 46, 28, 4, 3, (1 << 4), (1 << 3), 3
},
{
"+\\divisionslash\\minus", "W",
"\\math_notequal",
"\\math_equal",
NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
59, 225, 46, 28, 3, 3, (1 << 3), (1 << 3), 3
},
{
"X", "X",
"\\math_lessequal",
"\\math_less",
NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
119, 225, 46, 28, 2, 3, (1 << 2), (1 << 3), 3
},
{
"1/X", "Y",
"\\math_greaterequal",
"\\math_greater",
NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
179, 225, 46, 28, 1, 3, (1 << 1), (1 << 3), 3
},
{
"\\divide", "Z", "ABS", "ARG", NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT_NO_SPACE,
238, 225, 46, 28, 0, 3, (1 << 0), (1 << 3), 3
},
{
"ALPHA", NULL, "USER", "ENTRY", NULL,
UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
0, 267, 46, 32, 0, 0, 0, 0, 4
},
{
"7", NULL, "S.SLV", "NUM.SLV", NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
59, 267, 46, 32, 3, 4, (1 << 3), (1 << 4), 4
},
{
"8", NULL, "EXP&LN", "TRIG", NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
119, 267, 46, 32, 2, 4, (1 << 2), (1 << 4), 4
},
{
"9", NULL, "FINANCE", "TIME", NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
179, 267, 46, 32, 1, 4, (1 << 1), (1 << 4), 4
},
{
"\\multiply", NULL, "[ ]", "\" \"", NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
238, 267, 46, 32, 0, 4, (1 << 0), (1 << 4), 4
},
{
"\\uparrowleft", NULL, NULL, NULL, NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
0, 313, 46, 32, 0, 0, 0, 0, 5
},
{
"4", NULL, "CALC", "ALG", NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
59, 313, 46, 32, 3, 5, (1 << 3), (1 << 5), 5
},
{
"5", NULL, "MATRICES", "STAT", NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
119, 313, 46, 32, 2, 5, (1 << 2), (1 << 5), 5
},
{
"6", NULL, "CONVERT", "UNITS", NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
179, 313, 46, 32, 1, 5, (1 << 1), (1 << 5), 5
},
{
"\\minus", NULL, "( )", "_", NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
238, 313, 46, 32, 0, 5, (1 << 0), (1 << 5), 5
},
{
"\\uparrowright", NULL, NULL, NULL, NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
0, 359, 46, 32, 0, 0, 0, 0, 6
},
{
"1", NULL, "ARITH", "CMPLX", NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
59, 359, 46, 32, 3, 6, (1 << 3), (1 << 6), 6
},
{
"2", NULL, "DEF", "LIB", NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
119, 359, 46, 32, 2, 6, (1 << 2), (1 << 6), 6
},
{
"3", NULL, "\\math_numbersign", "BASE", NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
179, 359, 46, 32, 1, 6, (1 << 1), (1 << 6), 6
},
{
"+", NULL,
"{ }",
"\\guillemotleft\\ \\guillemotright",
NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
238, 359, 46, 32, 0, 6, (1 << 0), (1 << 6), 6
},
{
"ON", NULL, "CONT", "OFF", "CANCEL",
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
0, 405, 46, 32, 0, 0, 0, 0, 0
},
{
"0", NULL,
"\\math_infinity",
"\\math_arrowright",
NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
59, 405, 46, 32, 3, 7, (1 << 3), (1 << 7), 7
},
{
"\\bullet", NULL,
": :",
"\\math_downarrowleft",
NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
119, 405, 46, 32, 2, 7, (1 << 2), (1 << 7), 7
},
{
"SPC", NULL,
"\\math_pi",
"\\large_comma",
NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
179, 405, 46, 32, 1, 7, (1 << 1), (1 << 7), 7
},
{
"ENTER", NULL, "ANS", "\\arrowright NUM", NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
238, 405, 46, 32, 0, 7, (1 << 0), (1 << 7), 7
},
};
#define X49GP_UI_NR_KEYS (sizeof(x49gp_ui_keys) / sizeof(x49gp_ui_keys[0]))
static const x49gp_ui_key_t x50g_ui_keys[] =
{
{
"F1", "A", "Y=", NULL, NULL,
UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
0, 0, 36, 22, 5, 1, (1 << 5), (1 << 1), 1
},
{
"F2", "B", "WIN", NULL, NULL,
UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
50, 0, 36, 22, 5, 2, (1 << 5), (1 << 2), 2
},
{
"F3", "C", "GRAPH", NULL, NULL,
UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
99, 0, 36, 22, 5, 3, (1 << 5), (1 << 3), 3
},
{
"F4", "D", "2D/3D", NULL, NULL,
UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
149, 0, 36, 22, 5, 4, (1 << 5), (1 << 4), 4
},
{
"F5", "E", "TBLSET", NULL, NULL,
UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
198, 0, 36, 22, 5, 5, (1 << 5), (1 << 5), 5
},
{
"F6", "F", "TABLE", NULL, NULL,
UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
247, 0, 36, 22, 5, 6, (1 << 5), (1 << 6), 6
},
{
"APPS", "G", "FILES", "BEGIN", NULL,
UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
0, 44, 36, 28, 5, 7, (1 << 5), (1 << 7), 7
},
{
"MODE", "H", "CUSTOM", "END", NULL,
UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
50, 44, 36, 28, 6, 5, (1 << 6), (1 << 5), 5
},
{
"TOOL", "I", "i", "I", NULL,
UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
99, 44, 36, 28, 6, 6, (1 << 6), (1 << 6), 6
},
{
"V\\kern-1 AR", "J", "UPDIR", "COPY", NULL,
UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
0, 92, 36, 28, 6, 7, (1 << 6), (1 << 7), 7
},
{
"STO \\triangleright", "K", "RCL", "CUT", NULL,
UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
50, 92, 36, 28, 7, 1, (1 << 7), (1 << 1), 1
},
{
"NXT", "L", "PREV", "PASTE", NULL,
UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
99, 92, 36, 28, 7, 2, (1 << 7), (1 << 2), 2
},
{
NULL, NULL, NULL, NULL, NULL,
UI_COLOR_SILVER, 0.0, 0,
UI_SHAPE_BUTTON_ROUND, 0.0, 0,
200, 38, 33, 33, 6, 1, (1 << 6), (1 << 1), 1
},
{
NULL, NULL, NULL, NULL, NULL,
UI_COLOR_SILVER, 0.0, 0,
UI_SHAPE_BUTTON_ROUND, 0.0, 0,
164, 66, 33, 33, 6, 2, (1 << 6), (1 << 2), 2
},
{
NULL, NULL, NULL, NULL, NULL,
UI_COLOR_SILVER, 0.0, 0,
UI_SHAPE_BUTTON_ROUND, 0.0, 0,
200, 94, 33, 33, 6, 3, (1 << 6), (1 << 3), 3
},
{
NULL, NULL, NULL, NULL, NULL,
UI_COLOR_SILVER, 0.0, 0,
UI_SHAPE_BUTTON_ROUND, 0.0, 0,
236, 66, 33, 33, 6, 4, (1 << 6), (1 << 4), 4
},
{
"HIST", "M", "CMD", "UNDO", NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
0, 141, 46, 28, 4, 1, (1 << 4), (1 << 1), 1
},
{
"EV\\kern-1 AL", "N", "PRG", "CHARS", NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
59, 141, 46, 28, 3, 1, (1 << 3), (1 << 1), 1
},
{
"\\tick", "O", "MTRW", "EQW", NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
119, 141, 46, 28, 2, 1, (1 << 2), (1 << 1), 1
},
{
"S\\kern-1 Y\\kern-1 M\\kern-1 B", "P", "MTH", "CAT", NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
179, 141, 46, 28, 1, 1, (1 << 1), (1 << 1), 1
},
{
"\\arrowleftdblfull", NULL, "DEL", "CLEAR", NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 0.0, 0,
238, 141, 46, 28, 0, 1, (1 << 0), (1 << 1), 1
},
{
"Y\\super x\\/super", "Q", "\\math_e\\xsuperior", "LN", NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
0, 183, 46, 28, 4, 2, (1 << 4), (1 << 2), 2
},
{
"\\radical\\overscore\\kern-7 X", "R",
"\\math_x\\twosuperior",
"\\xsuperior\\kern-4\\math_radical\\overscore\\kern-5\\math_y",
NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
59, 183, 46, 28, 3, 2, (1 << 3), (1 << 2), 2
},
{
"SIN", "S", "ASIN", "\\math_summation", NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
119, 183, 46, 28, 2, 2, (1 << 2), (1 << 2), 2
},
{
"COS", "T", "ACOS", "\\math_partialdiff", NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
179, 183, 46, 28, 1, 2, (1 << 1), (1 << 2), 2
},
{
"TAN", "U", "ATAN", "\\math_integral", NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
238, 183, 46, 28, 0, 2, (1 << 0), (1 << 2), 2
},
{
"EEX", "V", "10\\xsuperior", "LOG", NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
0, 225, 46, 28, 4, 3, (1 << 4), (1 << 3), 3
},
{
"+\\divisionslash\\minus", "W",
"\\math_notequal",
"\\math_equal",
NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
59, 225, 46, 28, 3, 3, (1 << 3), (1 << 3), 3
},
{
"X", "X",
"\\math_lessequal",
"\\math_less",
NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
119, 225, 46, 28, 2, 3, (1 << 2), (1 << 3), 3
},
{
"1/X", "Y",
"\\math_greaterequal",
"\\math_greater",
NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
179, 225, 46, 28, 1, 3, (1 << 1), (1 << 3), 3
},
{
"\\divide", "Z", "ABS", "ARG", NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT_NO_SPACE,
238, 225, 46, 28, 0, 3, (1 << 0), (1 << 3), 3
},
{
"ALPHA", NULL, "USER", "ENTRY", NULL,
UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
0, 267, 46, 32, 0, 0, 0, 0, 4
},
{
"7", NULL, "S.SLV", "NUM.SLV", NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
59, 267, 46, 32, 3, 4, (1 << 3), (1 << 4), 4
},
{
"8", NULL, "EXP&LN", "TRIG", NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
119, 267, 46, 32, 2, 4, (1 << 2), (1 << 4), 4
},
{
"9", NULL, "FINANCE", "TIME", NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
179, 267, 46, 32, 1, 4, (1 << 1), (1 << 4), 4
},
{
"\\multiply", NULL, "[ ]", "\" \"", NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
238, 267, 46, 32, 0, 4, (1 << 0), (1 << 4), 4
},
{
"\\uparrowleft", NULL, NULL, NULL, NULL,
UI_COLOR_BLACK, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
0, 313, 46, 32, 0, 0, 0, 0, 5
},
{
"4", NULL, "CALC", "ALG", NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
59, 313, 46, 32, 3, 5, (1 << 3), (1 << 5), 5
},
{
"5", NULL, "MATRICES", "STAT", NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
119, 313, 46, 32, 2, 5, (1 << 2), (1 << 5), 5
},
{
"6", NULL, "CONVERT", "UNITS", NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
179, 313, 46, 32, 1, 5, (1 << 1), (1 << 5), 5
},
{
"\\minus", NULL, "( )", "_", NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
238, 313, 46, 32, 0, 5, (1 << 0), (1 << 5), 5
},
{
"\\uparrowright", NULL, NULL, NULL, NULL,
UI_COLOR_BLACK, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
0, 359, 46, 32, 0, 0, 0, 0, 6
},
{
"1", NULL, "ARITH", "CMPLX", NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
59, 359, 46, 32, 3, 6, (1 << 3), (1 << 6), 6
},
{
"2", NULL, "DEF", "LIB", NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
119, 359, 46, 32, 2, 6, (1 << 2), (1 << 6), 6
},
{
"3", NULL, "\\math_numbersign", "BASE", NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
179, 359, 46, 32, 1, 6, (1 << 1), (1 << 6), 6
},
{
"+", NULL,
"{ }",
"\\guillemotleft\\ \\guillemotright",
NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
238, 359, 46, 32, 0, 6, (1 << 0), (1 << 6), 6
},
{
"ON", NULL, "CONT", "OFF", "CANCEL",
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
0, 405, 46, 32, 0, 0, 0, 0, 0
},
{
"0", NULL,
"\\math_infinity",
"\\math_arrowright",
NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
59, 405, 46, 32, 3, 7, (1 << 3), (1 << 7), 7
},
{
"\\bullet", NULL,
": :",
"\\math_downarrowleft",
NULL,
UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
119, 405, 46, 32, 2, 7, (1 << 2), (1 << 7), 7
},
{
"SPC", NULL,
"\\math_pi",
"\\large_comma",
NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
179, 405, 46, 32, 1, 7, (1 << 1), (1 << 7), 7
},
{
"ENTER", NULL, "ANS", "\\arrowright NUM", NULL,
UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
UI_SHAPE_BUTTON_LARGE, 0.0, 0,
238, 405, 46, 32, 0, 7, (1 << 0), (1 << 7), 7
},
};
#define X50G_UI_NR_KEYS (sizeof(x50g_ui_keys) / sizeof(x50g_ui_keys[0]))
static void
x49gp_ui_color_init(GdkColor *color, u8 red, u8 green, u8 blue)
{
color->red = (red << 8) | red;
color->green = (green << 8) | green;
color->blue = (blue << 8) | blue;
}
static void
x49gp_ui_style_init(GtkStyle *style, GtkWidget *widget,
GdkColor *fg, GdkColor *bg)
{
int i;
for (i = 0; i < 5; i++) {
style->fg[i] = *fg;
style->bg[i] = *bg;
style->text[i] = style->fg[i];
style->base[i] = style->bg[i];
}
style->xthickness = 0;
style->ythickness = 0;
}
static const uint32_t PIXBUF_MAGIC = 0x47646b50;
typedef struct {
uint32_t magic;
uint32_t length;
uint32_t pixdata_type;
uint32_t rowstride;
uint32_t width;
uint32_t height;
} pixbuf_inline_data_t;
static GdkPixbuf *
x49gp_pixbuf_new_from_inline(gint data_length, const guint8 *data)
{
const pixbuf_inline_data_t *pbd = (const pixbuf_inline_data_t *) data;
uint32_t magic, rowstride, width, height, length;
const guint8 *pixdata;
magic = ntohl(pbd->magic);
if (magic != PIXBUF_MAGIC) {
return NULL;
}
length = ntohl(pbd->length);
/* The data comes from a C string, which contains a trailing \0. */
/* This will be counted by sizeof(), but the embedded header */
/* specifies the true size. Compensate by adding 1 to it. */
if (length + 1 != data_length) {
return NULL;
}
width = ntohl(pbd->width);
height = ntohl(pbd->height);
rowstride = ntohl(pbd->rowstride);
pixdata = (void *) (pbd + 1);
return gdk_pixbuf_new_from_data(pixdata, GDK_COLORSPACE_RGB, TRUE, 8,
width, height, rowstride, NULL, NULL);
}
static int
x49gp_ui_button_pixmaps_init(x49gp_t *x49gp, x49gp_ui_button_t *button,
x49gp_ui_color_t color)
{
x49gp_ui_t *ui = x49gp->ui;
GdkPixbuf *src, *dst;
GtkStyle *style;
int i;
style = gtk_style_new();
x49gp_ui_style_init(style, button->button,
&ui->colors[button->key->color],
&ui->colors[UI_COLOR_BLACK]);
for (i = 0; i < 5; i++) {
style->bg_pixmap[i] = gdk_pixmap_new(ui->window->window,
button->key->width,
button->key->height, -1);
if (i == GTK_STATE_ACTIVE) {
if (color == UI_COLOR_SILVER) {
src = gdk_pixbuf_new_subpixbuf(ui->bg_pixbuf,
ui->kb_x_offset + button->key->x,
ui->kb_y_offset + button->key->y,
button->key->width,
button->key->height);
dst = gdk_pixbuf_copy(src);
g_object_unref(src);
src = x49gp_pixbuf_new_from_inline(sizeof(button_round),
button_round);
gdk_pixbuf_composite(src, dst,
0, 0,
button->key->width,
button->key->height,
0.0, 0.0, 1.0, 1.0,
GDK_INTERP_HYPER, 0xff);
g_object_unref(src);
src = dst;
} else {
src = gdk_pixbuf_new_subpixbuf(ui->bg_pixbuf,
ui->kb_x_offset + button->key->x,
ui->kb_y_offset + button->key->y + 1,
button->key->width,
button->key->height);
}
} else {
src = gdk_pixbuf_new_subpixbuf(ui->bg_pixbuf,
ui->kb_x_offset + button->key->x,
ui->kb_y_offset + button->key->y,
button->key->width,
button->key->height);
}
gdk_draw_pixbuf(style->bg_pixmap[i],
ui->window->style->black_gc,
src, 0, 0, 0, 0,
button->key->width, button->key->height,
GDK_RGB_DITHER_NORMAL, 0, 0);
g_object_unref(src);
}
gtk_widget_set_style(button->button, style);
return 0;
}
static void
x49gp_ui_symbol_path(cairo_t *cr, double size,
double xoffset, double yoffset,
const x49gp_symbol_t *symbol)
{
const symbol_path_t *path;
const cairo_path_data_t *data;
int i;
path = symbol->path;
if (NULL == path) {
return;
}
cairo_move_to(cr, xoffset, yoffset);
for (i = 0; i < path->num_data; i += path->data[i].header.length) {
data = &path->data[i];
switch (data->header.type) {
case CAIRO_PATH_MOVE_TO:
cairo_rel_move_to(cr, size * data[1].point.x,
-size * data[1].point.y);
break;
case CAIRO_PATH_LINE_TO:
cairo_rel_line_to(cr, size * data[1].point.x,
-size * data[1].point.y);
break;
case CAIRO_PATH_CURVE_TO:
cairo_rel_curve_to(cr, size * data[1].point.x,
-size * data[1].point.y,
size * data[2].point.x,
-size * data[2].point.y,
size * data[3].point.x,
-size * data[3].point.y);
break;
case CAIRO_PATH_CLOSE_PATH:
cairo_close_path(cr);
break;
}
}
}
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)
{
cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER);
cairo_set_line_width(cr, line_width);
cairo_set_source_rgb(cr, ((double) color->red) / 65535.0,
((double) color->green) / 65535.0,
((double) color->blue) / 65535.0);
x49gp_ui_symbol_path(cr, size, xoffset, yoffset, symbol);
if (fill) {
cairo_fill(cr);
} else {
cairo_stroke(cr);
}
}
static int
x49gp_ui_lookup_glyph(const char *name, int namelen, gunichar *glyph)
{
int i;
for (i = 0; i < NR_GLYPHNAMES; i++) {
if ((strlen(x49gp_glyphs[i].name) == namelen) &&
!strncmp(x49gp_glyphs[i].name, name, namelen)) {
if (glyph)
*glyph = x49gp_glyphs[i].unichar;
return 1;
}
}
return 0;
}
static int
x49gp_text_strlen(const char *text)
{
const char *p, *q;
char c;
int namelen;
int n = 0;
p = text;
while ((c = *p++)) {
if (c != '\\') {
n++;
continue;
}
q = p;
while (*q) {
if ((*q == '\\') || (*q == ' '))
break;
q++;
}
if (q == p) {
n++;
p++;
continue;
}
namelen = q - p;
if (*q == ' ')
q++;
if (symbol_lookup_glyph_by_name(p, namelen, NULL)) {
p = q;
n++;
continue;
}
if (x49gp_ui_lookup_glyph(p, namelen, NULL)) {
p = q;
n++;
continue;
}
/*
* Insert symbol .notdef here...
*/
p = q;
n++;
}
return n;
}
static int
x49gp_text_to_ucs4(const char *text, gunichar **ucs4p)
{
const char *p, *q;
gunichar glyph;
gunichar *ucs4;
char c;
int namelen;
int i, n;
n = x49gp_text_strlen(text);
if (n <= 0)
return n;
ucs4 = malloc(n * sizeof(gunichar));
i = 0;
p = text;
while ((c = *p++)) {
if (i == n) {
free(ucs4);
return -1;
}
if (c != '\\') {
ucs4[i++] = c;
continue;
}
q = p;
while (*q) {
if ((*q == '\\') || (*q == ' '))
break;
q++;
}
if (q == p) {
ucs4[i++] = *p++;
continue;
}
namelen = q - p;
if (*q == ' ')
q++;
if (symbol_lookup_glyph_by_name(p, namelen, &glyph)) {
ucs4[i++] = glyph;
p = q;
continue;
}
if (x49gp_ui_lookup_glyph(p, namelen, &glyph)) {
ucs4[i++] = glyph;
p = q;
continue;
}
/*
* Insert symbol .notdef here...
*/
ucs4[i++] = 0xe000;
p = q;
}
*ucs4p = ucs4;
return n;
}
static void
x49gp_ui_vtext_path(cairo_t *cr, const char *family, double size,
double x, double y, int n, va_list ap)
{
cairo_text_extents_t extents;
cairo_font_weight_t weight;
cairo_font_slant_t slant;
const x49gp_symbol_t *symbol;
const char *text;
gunichar *ucs4;
char out[8];
int bytes;
int i, j, len;
for (i = 0; i < n; i++) {
slant = va_arg(ap, cairo_font_slant_t);
weight = va_arg(ap, cairo_font_weight_t);
text = va_arg(ap, const char *);
cairo_select_font_face(cr, family, slant, weight);
cairo_set_font_size(cr, size);
ucs4 = NULL;
len = x49gp_text_to_ucs4(text, &ucs4);
if (len <= 0) {
continue;
}
for (j = 0; j < len; j++) {
if (g_unichar_type(ucs4[j]) == G_UNICODE_PRIVATE_USE) {
/*
* Draw Symbol, Increment x...
*/
symbol = symbol_get_by_glyph(ucs4[j]);
if (NULL == symbol)
symbol = symbol_get_by_glyph(0xe000);
size *= symbol->prescale;
x49gp_ui_symbol_path(cr, size, x, y, symbol);
x += size * symbol->x_advance;
y -= size * symbol->y_advance;
size *= symbol->postscale;
if (symbol->prescale * symbol->postscale != 1.)
cairo_set_font_size(cr, size);
continue;
}
bytes = g_unichar_to_utf8(ucs4[j], out);
out[bytes] = '\0';
cairo_text_extents(cr, out, &extents);
cairo_move_to(cr, x, y);
cairo_text_path(cr, out);
x += extents.x_advance;
y += extents.y_advance;
}
free(ucs4);
}
}
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, ...)
{
va_list ap0, ap1;
cairo_font_extents_t font_extents;
cairo_font_weight_t weight;
cairo_font_slant_t slant;
double x1, y1, x2, y2, a, d;
const char *text;
int i;
if (n < 1)
return;
va_start(ap0, n);
va_copy(ap1, ap0);
x49gp_ui_vtext_path(cr, family, size, 0.0, 0.0, n, ap0);
va_end(ap0);
cairo_fill_extents(cr, &x1, &y1, &x2, &y2);
if (y2 < 0.0)
y2 = 0.0;
a = 0.0;
d = 0.0;
for (i = 0; i < n; i++) {
slant = va_arg(ap1, cairo_font_slant_t);
weight = va_arg(ap1, cairo_font_weight_t);
text = va_arg(ap1, const char *);
(void) text;
cairo_select_font_face(cr, family, slant, weight);
cairo_set_font_size(cr, size);
cairo_font_extents(cr, &font_extents);
/*
* Cairo seems to return overall height in ascent,
* so fix this by calculating ascent = height - descent.
*/
if (font_extents.ascent - font_extents.descent > a)
a = font_extents.ascent - font_extents.descent;
if (font_extents.descent > -d)
d = -font_extents.descent;
}
*x_bearing = x1;
*y_bearing = y2;
*width = x2 - x1;
*height = y2 - y1;
*ascent = a;
*descent = d;
va_end(ap1);
}
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, ...)
{
va_list ap;
if (n < 1)
return;
va_start(ap, n);
cairo_set_line_width(cr, line_width);
cairo_set_source_rgb(cr, ((double) color->red) / 65535.0,
((double) color->green) / 65535.0,
((double) color->blue) / 65535.0);
x49gp_ui_vtext_path(cr, family, size, xoffset, yoffset, n, ap);
if (line_width == 0.0)
cairo_fill(cr);
else
cairo_stroke(cr);
va_end(ap);
}
#if 0
static void
x49gp_ui_dump_path(cairo_t *cr, const char *family, int n, ...)
{
va_list ap;
const cairo_path_t *path;
const cairo_path_data_t *data;
int i;
if (n < 1)
return;
va_start(ap, n);
x49gp_ui_vtext_path(cr, family, 1000.0, 0.0, 0.0, n, ap);
path = cairo_copy_path(cr);
if (NULL == path) {
return;
}
cairo_new_path(cr);
for (i = 0; i < path->num_data; i += path->data[i].header.length) {
data = &path->data[i];
switch (data->header.type) {
case CAIRO_PATH_MOVE_TO:
printf("path: move to %4.0f %4.0f\n",
data[1].point.x, -data[1].point.y);
break;
case CAIRO_PATH_LINE_TO:
printf("path: line to %4.0f %4.0f\n",
data[1].point.x, -data[1].point.y);
break;
case CAIRO_PATH_CURVE_TO:
printf("path: curve to %4.0f %4.0f\n"
" %4.0f %4.0f\n"
" %4.0f %4.0f\n",
data[1].point.x, -data[1].point.y,
data[2].point.x, -data[2].point.y,
data[3].point.x, -data[3].point.y);
break;
case CAIRO_PATH_CLOSE_PATH:
printf("path: close path\n");
break;
}
}
va_end(ap);
}
#endif
static unsigned char
bitmap_font_lookup_glyph(const bitmap_font_t *font,
const char *name, int namelen)
{
int i;
for (i = 0; font->glyphs[i].name; i++) {
if ((strlen(font->glyphs[i].name) == namelen) &&
!strncmp(font->glyphs[i].name, name, namelen)) {
return i;
}
}
return 0;
}
static unsigned char
bitmap_font_lookup_ascii(const bitmap_font_t *font, char c)
{
int namelen = 0;
char *name;
switch (c) {
case ' ': name = "space"; break;
case '!': name = "exclam"; break;
case '"': name = "quotedbl"; break;
case '#': name = "numbersign"; break;
case '$': name = "dollar"; break;
case '%': name = "percent"; break;
case '&': name = "ampersand"; break;
case '(': name = "parenleft"; break;
case ')': name = "parenright"; break;
case '*': name = "asterisk"; break;
case '+': name = "plus"; break;
case ',': name = "comma"; break;
case '-': name = "hyphen"; break;
case '.': name = "period"; break;
case '/': name = "slash"; break;
case '0': name = "zero"; break;
case '1': name = "one"; break;
case '2': name = "two"; break;
case '3': name = "three"; break;
case '4': name = "four"; break;
case '5': name = "five"; break;
case '6': name = "six"; break;
case '7': name = "seven"; break;
case '8': name = "eight"; break;
case '9': name = "nine"; break;
case ':': name = "colon"; break;
case ';': name = "semicolon"; break;
case '<': name = "less"; break;
case '=': name = "equal"; break;
case '>': name = "greater"; break;
case '?': name = "question"; break;
case '@': name = "at"; break;
case '[': name = "bracketleft"; break;
case '\\': name = "backslash"; break;
case ']': name = "bracketright"; break;
case '^': name = "asciicircum"; break;
case '_': name = "underscore"; break;
case '`': name = "quoteleft"; break;
case '{': name = "braceleft"; break;
case '|': name = "bar"; break;
case '}': name = "braceright"; break;
case '~': name = "asciitilde"; break;
default:
name = &c;
namelen = 1;
break;
}
if (0 == namelen)
namelen = strlen(name);
return bitmap_font_lookup_glyph(font, name, namelen);
}
static int
bitmap_font_strlen(const char *text)
{
const char *p, *q;
char c;
int n = 0;
p = text;
while ((c = *p++)) {
if (c != '\\') {
n++;
continue;
}
q = p;
while (*q) {
if ((*q == '\\') || (*q == ' '))
break;
q++;
}
if (q == p) {
n++;
p++;
continue;
}
if (*q == ' ')
q++;
n++;
p = q;
}
return n;
}
static int
bitmap_font_text_to_glyphs(const bitmap_font_t *font,
const char *text, unsigned char **glyphp)
{
unsigned char *glyphs;
const char *p, *q;
unsigned char c;
int namelen;
int i, n;
n = bitmap_font_strlen(text);
if (n <= 0)
return n;
glyphs = malloc(n);
i = 0;
p = text;
while ((c = *p++)) {
if (i == n) {
free(glyphs);
return -1;
}
if (c != '\\') {
glyphs[i++] = bitmap_font_lookup_ascii(font, c);
continue;
}
q = p;
while (*q) {
if ((*q == '\\') || (*q == ' '))
break;
q++;
}
if (q == p) {
glyphs[i++] = bitmap_font_lookup_ascii(font, *p++);
continue;
}
namelen = q - p;
if (*q == ' ')
q++;
glyphs[i++] = bitmap_font_lookup_glyph(font, p, namelen);
p = q;
}
*glyphp = glyphs;
return n;
}
static void
bitmap_font_text_size(const bitmap_font_t *font, const char *text,
int *width, int *height, int *ascent, int *descent)
{
const bitmap_glyph_t *glyph;
unsigned char *glyphs;
int i, n, w, a, d;
w = 0;
a = 0;
d = 0;
n = bitmap_font_text_to_glyphs(font, text, &glyphs);
for (i = 0; i < n; i++) {
glyph = &font->glyphs[glyphs[i]];
w += glyph->width;
if (glyph->ascent > a)
a = glyph->ascent;
if (glyph->descent < d)
d = glyph->descent;
}
*width = w - 1;
*height = font->ascent - font->descent;
*ascent = a;
*descent = d;
if (n > 0) {
free(glyphs);
}
}
static void
bitmap_font_draw_text(GdkDrawable *drawable, GdkColor *color,
const bitmap_font_t *font,
int x, int y, const char *text)
{
const bitmap_glyph_t *glyph;
unsigned char *glyphs;
GdkBitmap *bitmap;
GdkGC *gc;
int i, n, w, h;
gc = gdk_gc_new(drawable);
gdk_gc_set_rgb_fg_color(gc, color);
n = bitmap_font_text_to_glyphs(font, text, &glyphs);
for (i = 0; i < n; i++) {
glyph = &font->glyphs[glyphs[i]];
w = glyph->width - glyph->kern;
h = glyph->ascent - glyph->descent;
if (w <= 0 || h <= 0) {
x += glyph->width;
continue;
}
bitmap = gdk_bitmap_create_from_data(NULL, (char *) glyph->bits, w, h);
gdk_gc_set_ts_origin(gc, x + glyph->kern,
y + font->ascent - glyph->ascent);
gdk_gc_set_stipple(gc, bitmap);
gdk_gc_set_fill(gc, GDK_STIPPLED);
gdk_draw_rectangle(drawable, gc, TRUE, x + glyph->kern,
y + font->ascent - glyph->ascent, w, h);
g_object_unref(bitmap);
x += glyph->width;
}
g_object_unref(gc);
if (n > 0) {
free(glyphs);
}
}
static void
x49gp_ui_choose_file(x49gp_t *x49gp, const char *prompt,
GtkFileChooserAction action, char **filename)
{
GtkWidget *dialog;
x49gp_ui_t *ui = x49gp->ui;
dialog = gtk_file_chooser_dialog_new(prompt, GTK_WINDOW(ui->window),
action,
GTK_STOCK_CANCEL,
GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN,
GTK_RESPONSE_ACCEPT,
NULL);
gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(dialog), TRUE);
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE);
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
*filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
} else {
*filename = NULL;
}
gtk_widget_destroy(dialog);
}
static gboolean
x49gp_ui_button_press(GtkWidget *widget, GdkEventButton *event,
gpointer user_data)
{
x49gp_ui_button_t *button = user_data;
const x49gp_ui_key_t *key = button->key;
x49gp_t *x49gp = button->x49gp;
x49gp_ui_t *ui = x49gp->ui;
#ifdef DEBUG_X49GP_UI
fprintf(stderr, "%s:%u: type %u, button %u\n", __FUNCTION__, __LINE__, event->type, event->button);
#endif
if (event->type != GDK_BUTTON_PRESS)
return FALSE;
switch (event->button) {
case 1:
ui->buttons_down++;
if (button->down) return FALSE;
button->down = TRUE;
break;
case 3:
button->hold = TRUE;
if (button->down) return FALSE;
gtk_button_pressed(GTK_BUTTON(button->button));
button->down = TRUE;
break;
default:
return TRUE;
}
#ifdef DEBUG_X49GP_UI
printf("%s: button %u: col %u, row %u, eint %u\n", __FUNCTION__,
event->button,
button->key->column, button->key->row, button->key->eint);
#endif
if (key->rowbit) {
s3c2410_io_port_g_update(x49gp, key->column, key->row, key->columnbit, key->rowbit, 1);
} else {
s3c2410_io_port_f_set_bit(x49gp, key->eint, 1);
}
return FALSE;
}
static void
x49gp_release_single_button(x49gp_ui_button_t *button, x49gp_ui_button_t *cause)
{
x49gp_t *x49gp = button->x49gp;
const x49gp_ui_key_t *key;
GtkButton *gtkbutton;
#ifdef DEBUG_X49GP_UI
printf("%s: button %u: col %u, row %u, eint %u\n", __FUNCTION__,
event->button,
button->key->column, button->key->row, button->key->eint);
#endif
button->down = FALSE;
button->hold = FALSE;
gtkbutton = GTK_BUTTON(button->button);
if (button != cause)
gtkbutton->in_button = FALSE;
gtk_button_released(gtkbutton);
key = button->key;
if (key->rowbit) {
s3c2410_io_port_g_update(x49gp, key->column, key->row, key->columnbit, key->rowbit, 0);
} else {
s3c2410_io_port_f_set_bit(x49gp, key->eint, 0);
}
}
static void
x49gp_release_all_buttons(x49gp_t *x49gp, x49gp_ui_button_t *cause)
{
x49gp_ui_button_t *button;
x49gp_ui_t *ui = x49gp->ui;
int i;
for (i = 0; i < ui->nr_buttons; i++) {
button = &ui->buttons[i];
if (! button->down)
continue;
x49gp_release_single_button(button, cause);
}
}
static gboolean
x49gp_ui_button_release(GtkWidget *widget, GdkEventButton *event,
gpointer user_data)
{
x49gp_ui_button_t *button = user_data;
x49gp_t *x49gp = button->x49gp;
x49gp_ui_t *ui = x49gp->ui;
if (event->type != GDK_BUTTON_RELEASE)
return FALSE;
switch (event->button) {
case 1:
break;
default:
return TRUE;
}
if (ui->buttons_down > 0)
ui->buttons_down--;
if (ui->buttons_down == 0) {
x49gp_release_all_buttons(x49gp, button);
} else {
x49gp_release_single_button(button, button);
}
return FALSE;
}
static gboolean
x49gp_ui_show_menu(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
{
x49gp_t *x49gp = user_data;
x49gp_ui_t *ui = x49gp->ui;
gtk_widget_set_sensitive(ui->menu_unmount,
s3c2410_sdi_is_mounted(x49gp));
if (ui->menu_debug)
gtk_widget_set_sensitive(ui->menu_debug,
! gdbserver_isactive());
if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
gtk_menu_popup(GTK_MENU(ui->menu), NULL, NULL, NULL, NULL,
event->button, event->time);
return TRUE;
}
return FALSE;
}
static gboolean
x49gp_ui_button_leave(GtkWidget *widget, GdkEventCrossing *event,
gpointer user_data)
{
x49gp_ui_button_t *button = user_data;
if (event->type != GDK_LEAVE_NOTIFY)
return FALSE;
if (!button->hold)
return FALSE;
return TRUE;
}
static gboolean
x49gp_ui_focus_lost(GtkWidget *widget, GdkEventFocus *event,
gpointer user_data)
{
x49gp_t *x49gp = user_data;
x49gp_ui_t *ui = x49gp->ui;
if (event->type != GDK_FOCUS_CHANGE)
return FALSE;
ui->buttons_down = 0;
x49gp_release_all_buttons(x49gp, NULL);
return FALSE;
}
static void
x49gp_ui_popup_at_widget(GtkMenu *menu, gint *x, gint *y, gboolean *push_in,
gpointer user_data)
{
GtkWidget *widget = GTK_WIDGET(user_data);
gdk_window_get_origin(widget->window, x, y);
*x += widget->allocation.x;
*y += widget->allocation.y;
}
static void
x49gp_ui_mount_sd_folder(GtkMenuItem *menuitem, gpointer user_data)
{
x49gp_t *x49gp = user_data;
char *filename;
x49gp_ui_choose_file(x49gp, "Choose SD folder ...",
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, &filename);
if (filename != NULL) s3c2410_sdi_mount(x49gp, filename);
}
static void
x49gp_ui_mount_sd_image(GtkMenuItem *menuitem, gpointer user_data)
{
x49gp_t *x49gp = user_data;
char *filename;
x49gp_ui_choose_file(x49gp, "Choose SD image ...",
GTK_FILE_CHOOSER_ACTION_OPEN, &filename);
if (filename != NULL) s3c2410_sdi_mount(x49gp, filename);
}
static void
x49gp_ui_debug(GtkMenuItem *menuitem, gpointer user_data)
{
x49gp_t *x49gp = user_data;
if(x49gp->debug_port != 0 && ! gdbserver_isactive()) {
gdbserver_start(x49gp->debug_port);
gdb_handlesig(x49gp->env, 0);
}
}
static void
x49gp_ui_calculator_reset(GtkMenuItem *menuitem, gpointer user_data)
{
x49gp_t *x49gp = user_data;
x49gp_modules_reset(x49gp, X49GP_RESET_POWER_ON);
cpu_reset(x49gp->env);
x49gp_set_idle(x49gp, 0);
}
static gboolean
x49gp_ui_key_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
{
x49gp_t *x49gp = user_data;
x49gp_ui_t *ui = x49gp->ui;
x49gp_ui_button_t *button;
GdkEventButton bev;
gboolean save_in;
int index;
guint keyval;
#ifdef DEBUG_X49GP_UI
fprintf(stderr, "%s:%u: type %u, keyval %04x\n", __FUNCTION__, __LINE__, event->type, event->keyval);
#endif
/* We want to know the keyval as interpreted without modifiers. */
/* However, there is one modifier we do care about: NumLock, */
/* which normally is represented by MOD2. */
if (! gdk_keymap_translate_keyboard_state(gdk_keymap_get_default(),
event->hardware_keycode,
event->state & GDK_MOD2_MASK,
event->group,
&keyval, NULL, NULL, NULL))
return FALSE;
#ifdef DEBUG_X49GP_UI
fprintf(stderr, "%s:%u: state %u, base keyval %04x\n", __FUNCTION__, __LINE__, event->state, keyval);
#endif
switch (keyval) {
case GDK_KEY_a: case GDK_KEY_F1: index = 0; break;
case GDK_KEY_b: case GDK_KEY_F2: index = 1; break;
case GDK_KEY_c: case GDK_KEY_F3: index = 2; break;
case GDK_KEY_d: case GDK_KEY_F4: index = 3; break;
case GDK_KEY_e: case GDK_KEY_F5: index = 4; break;
case GDK_KEY_f: case GDK_KEY_F6: index = 5; break;
case GDK_KEY_g: index = 6; break;
case GDK_KEY_h: index = 7; break;
case GDK_KEY_i: index = 8; break;
case GDK_KEY_j: index = 9; break;
case GDK_KEY_k: index = 10; break;
case GDK_KEY_l: index = 11; break;
case GDK_KEY_Up: case GDK_KEY_KP_Up: index = 12; break;
case GDK_KEY_Left: case GDK_KEY_KP_Left: index = 13; break;
case GDK_KEY_Down: case GDK_KEY_KP_Down: index = 14; break;
case GDK_KEY_Right: case GDK_KEY_KP_Right: index = 15; break;
case GDK_KEY_m: index = 16; break;
case GDK_KEY_n: index = 17; break;
case GDK_KEY_o: case GDK_KEY_apostrophe: index = 18; break;
case GDK_KEY_p: index = 19; break;
case GDK_KEY_BackSpace: case GDK_KEY_Delete:
case GDK_KEY_KP_Delete: index = 20; break;
case GDK_KEY_dead_circumflex: case GDK_KEY_asciicircum:
case GDK_KEY_q: case GDK_KEY_caret: index = 21; break;
case GDK_KEY_r: index = 22; break;
case GDK_KEY_s: index = 23; break;
case GDK_KEY_t: index = 24; break;
case GDK_KEY_u: index = 25; break;
case GDK_KEY_v: index = 26; break;
case GDK_KEY_w: index = 27; break;
case GDK_KEY_x: index = 28; break;
case GDK_KEY_y: index = 29; break;
case GDK_KEY_z:
case GDK_KEY_slash: case GDK_KEY_KP_Divide: index = 30; break;
case GDK_KEY_Tab: index = 31; break;
#ifndef __APPLE__
//case GDK_KEY_Alt_L: case GDK_KEY_Alt_R:
//case GDK_KEY_Meta_L: case GDK_KEY_Meta_R:
case GDK_KEY_Mode_switch: index = 31; break;
#endif
case GDK_KEY_7: case GDK_KEY_KP_7: index = 32; break;
case GDK_KEY_8: case GDK_KEY_KP_8: index = 33; break;
case GDK_KEY_9: case GDK_KEY_KP_9: index = 34; break;
case GDK_KEY_multiply: case GDK_KEY_KP_Multiply: index = 35; break;
case GDK_KEY_Shift_L: case GDK_KEY_Shift_R: index = 36; break;
case GDK_KEY_4: case GDK_KEY_KP_4: index = 37; break;
case GDK_KEY_5: case GDK_KEY_KP_5: index = 38; break;
case GDK_KEY_6: case GDK_KEY_KP_6: index = 39; break;
case GDK_KEY_minus: case GDK_KEY_KP_Subtract: index = 40; break;
case GDK_KEY_Control_L: case GDK_KEY_Control_R: index = 41; break;
case GDK_KEY_1: case GDK_KEY_KP_1: index = 42; break;
case GDK_KEY_2: case GDK_KEY_KP_2: index = 43; break;
case GDK_KEY_3: case GDK_KEY_KP_3: index = 44; break;
case GDK_KEY_plus: case GDK_KEY_KP_Add: index = 45; break;
case GDK_KEY_Escape: index = 46; break;
case GDK_KEY_0: case GDK_KEY_KP_0: index = 47; break;
case GDK_KEY_period: case GDK_KEY_comma:
case GDK_KEY_KP_Decimal: case GDK_KP_Separator: index = 48; break;
case GDK_KEY_space: case GDK_KEY_KP_Space: index = 49; break;
case GDK_KEY_Return: case GDK_KEY_KP_Enter: index = 50; break;
/* QUERTY compat: US English, UK English, International English */
case GDK_KEY_backslash: index = 35; break;
case GDK_KEY_equal: index = 45; break;
/* QUERTZ compat: German */
case GDK_KEY_ssharp: index = 30; break;
case GDK_KEY_numbersign: index = 35; break;
case GDK_KEY_F12:
switch (event->type) {
case GDK_KEY_PRESS:
x49gp_modules_reset(x49gp, X49GP_RESET_POWER_ON);
cpu_reset(x49gp->env);
x49gp_set_idle(x49gp, 1);
break;
case GDK_KEY_RELEASE:
x49gp_set_idle(x49gp, 0);
break;
default:
break;
}
return FALSE;
case GDK_KEY_Menu:
gtk_widget_set_sensitive(ui->menu_unmount,
s3c2410_sdi_is_mounted(x49gp));
if (ui->menu_debug)
gtk_widget_set_sensitive(ui->menu_debug,
! gdbserver_isactive());
gtk_menu_popup(GTK_MENU(ui->menu), NULL, NULL,
x49gp_ui_popup_at_widget, ui->lcd_canvas,
0, event->time);
return FALSE;
default:
return FALSE;
}
button = &ui->buttons[index];
memset(&bev, 0, sizeof(GdkEventButton));
bev.time = event->time;
bev.button = 1;
bev.state = event->state;
save_in = GTK_BUTTON(button->button)->in_button;
switch (event->type) {
case GDK_KEY_PRESS:
bev.type = GDK_BUTTON_PRESS;
x49gp_ui_button_press(button->button, &bev, button);
GTK_BUTTON(button->button)->in_button = TRUE;
gtk_button_pressed(GTK_BUTTON(button->button));
GTK_BUTTON(button->button)->in_button = save_in;
break;
case GDK_KEY_RELEASE:
bev.type = GDK_BUTTON_RELEASE;
GTK_BUTTON(button->button)->in_button = TRUE;
gtk_button_released(GTK_BUTTON(button->button));
GTK_BUTTON(button->button)->in_button = save_in;
x49gp_ui_button_release(button->button, &bev, button);
break;
default:
return FALSE;
}
return TRUE;
}
static int
x49gp_button_expose_event(GtkWidget *widget, GdkEventExpose *event,
gpointer user_data)
{
x49gp_ui_button_t *button = user_data;
int x, y;
x = widget->allocation.x;
y = widget->allocation.y;
if (GTK_WIDGET_STATE(widget) == GTK_STATE_ACTIVE)
y -= 1;
gdk_draw_drawable(widget->window, widget->style->black_gc,
button->pixmap, 0, 0, x, y,
widget->allocation.width, widget->allocation.height);
return FALSE;
}
static void
x49gp_button_realize(GtkWidget *widget, gpointer user_data)
{
x49gp_ui_button_t *button = user_data;
x49gp_ui_t *ui = button->x49gp->ui;
const x49gp_ui_key_t *key = button->key;
cairo_t *cr;
double xoff, yoff, width, height, ascent, descent;
unsigned int w, h;
int xoffset, yoffset, x, y;
xoffset = widget->allocation.x;
yoffset = widget->allocation.y;
w = widget->allocation.width;
h = widget->allocation.height;
button->pixmap = gdk_pixmap_new(widget->style->bg_pixmap[0], w, h, -1);
gdk_draw_drawable(button->pixmap, widget->style->black_gc,
widget->style->bg_pixmap[0],
xoffset, yoffset,
0, 0, button->key->width, button->key->height);
xoffset += 2;
yoffset += 2;
w -= 4;
h -= 4;
cr = gdk_cairo_create(button->pixmap);
cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER);
#if 0 /* Layout Debug */
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
cairo_set_line_width(cr, 1.0);
cairo_move_to(cr, xoffset, yoffset);
cairo_line_to(cr, xoffset + w - 1, yoffset);
cairo_line_to(cr, xoffset + w - 1, yoffset + h - 1);
cairo_line_to(cr, xoffset, yoffset + h - 1);
cairo_close_path(cr);
cairo_stroke(cr);
#endif
if (key->letter) {
x49gp_ui_text_size(cr, X49GP_UI_NORMAL_FONT, key->letter_size,
&xoff, &yoff, &width, &height, &ascent, &descent,
1, CAIRO_FONT_SLANT_NORMAL, key->font_weight,
key->letter);
switch (key->layout) {
case UI_LAYOUT_LEFT:
default:
x = (int) floor(w - 1.0 - width - xoff + 0.5);
y = (int) floor((h - 1.0 + ascent) / 2.0 + 0.5);
w -= width;
break;
case UI_LAYOUT_LEFT_NO_SPACE:
x = (int) floor(w - 1.0 - width - xoff + 0.5);
y = (int) floor((h - 1.0 + ascent) / 2.0 + 0.5);
break;
case UI_LAYOUT_BELOW:
x = (int) floor((w - 1.0 - width) / 2.0 - xoff + 0.5);
y = (int) h - 1.0;
h -= ascent;
break;
}
x49gp_ui_draw_text(cr, &ui->colors[UI_COLOR_YELLOW],
X49GP_UI_NORMAL_FONT, key->letter_size, 0.0,
x + xoffset, y + yoffset,
1, CAIRO_FONT_SLANT_NORMAL, key->font_weight,
key->letter);
}
x49gp_ui_text_size(cr, X49GP_UI_NORMAL_FONT, key->font_size,
&xoff, &yoff, &width, &height, &ascent, &descent,
1, CAIRO_FONT_SLANT_NORMAL, key->font_weight,
key->label);
x = (int) floor((w - 1.0 - width) / 2.0 - xoff + 0.5);
y = (int) floor((h - 1.0 + ascent) / 2.0 + 0.5);
x49gp_ui_draw_text(cr, &widget->style->text[0],
X49GP_UI_NORMAL_FONT, key->font_size, 0.0,
x + xoffset, y + yoffset,
1, CAIRO_FONT_SLANT_NORMAL, key->font_weight,
key->label);
cairo_destroy(cr);
}
static int
x49gp_lcd_expose_event(GtkWidget *widget, GdkEventExpose *event,
gpointer user_data)
{
x49gp_t *x49gp = user_data;
x49gp_ui_t *ui = x49gp->ui;
GdkRectangle *rects;
int i, n;
gdk_region_get_rectangles(event->region, &rects, &n);
for (i = 0; i < n; i++) {
gdk_draw_drawable(widget->window, widget->style->black_gc,
ui->lcd_pixmap,
rects[i].x, rects[i].y,
rects[i].x, rects[i].y,
rects[i].width, rects[i].height);
}
g_free(rects);
return FALSE;
}
static int
x49gp_lcd_configure_event(GtkWidget *widget, GdkEventConfigure *event,
gpointer user_data)
{
x49gp_t *x49gp = user_data;
x49gp_ui_t *ui = x49gp->ui;
if (NULL != ui->lcd_pixmap) {
return FALSE;
}
ui->ann_left = gdk_bitmap_create_from_data(ui->lcd_canvas->window,
(char *) ann_left_bits,
ann_left_width,
ann_left_height);
ui->ann_right = gdk_bitmap_create_from_data(ui->lcd_canvas->window,
(char *) ann_right_bits,
ann_right_width,
ann_right_height);
ui->ann_alpha = gdk_bitmap_create_from_data(ui->lcd_canvas->window,
(char *) ann_alpha_bits,
ann_alpha_width,
ann_alpha_height);
ui->ann_battery = gdk_bitmap_create_from_data(ui->lcd_canvas->window,
(char *) ann_battery_bits,
ann_battery_width,
ann_battery_height);
ui->ann_busy = gdk_bitmap_create_from_data(ui->lcd_canvas->window,
(char *) ann_busy_bits,
ann_busy_width,
ann_busy_height);
ui->ann_io = gdk_bitmap_create_from_data(ui->lcd_canvas->window,
(char *) ann_io_bits,
ann_io_width,
ann_io_height);
ui->ann_left_gc = gdk_gc_new(ui->lcd_canvas->window);
gdk_gc_copy(ui->ann_left_gc, widget->style->black_gc);
gdk_gc_set_ts_origin(ui->ann_left_gc, 11, 0);
gdk_gc_set_stipple(ui->ann_left_gc, ui->ann_left);
gdk_gc_set_fill(ui->ann_left_gc, GDK_STIPPLED);
ui->ann_right_gc = gdk_gc_new(ui->lcd_canvas->window);
gdk_gc_copy(ui->ann_right_gc, widget->style->black_gc);
gdk_gc_set_ts_origin(ui->ann_right_gc, 56, 0);
gdk_gc_set_stipple(ui->ann_right_gc, ui->ann_right);
gdk_gc_set_fill(ui->ann_right_gc, GDK_STIPPLED);
ui->ann_alpha_gc = gdk_gc_new(ui->lcd_canvas->window);
gdk_gc_copy(ui->ann_alpha_gc, widget->style->black_gc);
gdk_gc_set_ts_origin(ui->ann_alpha_gc, 101, 0);
gdk_gc_set_stipple(ui->ann_alpha_gc, ui->ann_alpha);
gdk_gc_set_fill(ui->ann_alpha_gc, GDK_STIPPLED);
ui->ann_battery_gc = gdk_gc_new(ui->lcd_canvas->window);
gdk_gc_copy(ui->ann_battery_gc, widget->style->black_gc);
gdk_gc_set_ts_origin(ui->ann_battery_gc, 146, 0);
gdk_gc_set_stipple(ui->ann_battery_gc, ui->ann_battery);
gdk_gc_set_fill(ui->ann_battery_gc, GDK_STIPPLED);
ui->ann_busy_gc = gdk_gc_new(ui->lcd_canvas->window);
gdk_gc_copy(ui->ann_busy_gc, widget->style->black_gc);
gdk_gc_set_ts_origin(ui->ann_busy_gc, 191, 0);
gdk_gc_set_stipple(ui->ann_busy_gc, ui->ann_busy);
gdk_gc_set_fill(ui->ann_busy_gc, GDK_STIPPLED);
ui->ann_io_gc = gdk_gc_new(ui->lcd_canvas->window);
gdk_gc_copy(ui->ann_io_gc, widget->style->black_gc);
gdk_gc_set_ts_origin(ui->ann_io_gc, 236, 0);
gdk_gc_set_stipple(ui->ann_io_gc, ui->ann_io);
gdk_gc_set_fill(ui->ann_io_gc, GDK_STIPPLED);
ui->lcd_pixmap = gdk_pixmap_new(ui->lcd_canvas->window,
ui->lcd_width, ui->lcd_height, -1);
#if 0 /* Debug Symbols on LCD screen ;) */
{
cairo_t *cr;
cr = gdk_cairo_create(ui->bg_pixmap);
cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER);
#if 1
x49gp_ui_draw_text(cr, &widget->style->black,
X49GP_UI_NORMAL_FONT, 100.0, 1.0,
ui->lcd_x_offset + 10, ui->lcd_y_offset + 160,
1, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD,
"\\arrowleftdblfull");
#else
x49gp_ui_dump_path(cr, X49GP_UI_NORMAL_FONT,
1, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD,
"\\arrowleftdblfull");
#endif
cairo_destroy(cr);
}
#endif
gdk_draw_drawable(ui->lcd_pixmap, widget->style->black_gc,
ui->bg_pixmap, ui->lcd_x_offset, ui->lcd_y_offset,
0, 0, ui->lcd_width, ui->lcd_height);
return FALSE;
}
static int
x49gp_window_configure_event(GtkWidget *widget, GdkEventConfigure *event,
gpointer user_data)
{
x49gp_t *x49gp = user_data;
x49gp_ui_t *ui = x49gp->ui;
const x49gp_ui_key_t *key;
cairo_t *cr;
int left_color;
int right_color;
int below_color;
int xl, xr, a;
int wl = 0, wr = 0;
int hl = 0, hr = 0;
int dl = 0, dr = 0;
int i;
if (NULL != ui->bg_pixmap) {
return FALSE;
}
ui->bg_pixmap = gdk_pixmap_new(widget->window,
ui->width, ui->height, -1);
gdk_draw_pixbuf(ui->bg_pixmap, widget->style->black_gc,
ui->bg_pixbuf, 0, 0, 0, 0, ui->width, ui->height,
GDK_RGB_DITHER_NORMAL, 0, 0);
cr = gdk_cairo_create(ui->bg_pixmap);
cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER);
switch (ui->calculator) {
default:
ui->calculator = UI_CALCULATOR_HP49GP;
/* fall through */
case UI_CALCULATOR_HP49GP:
x49gp_ui_draw_text(cr, &widget->style->black,
X49GP_UI_NORMAL_FONT, 15.0, 0.0,
38, 42, 2,
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_BOLD,
"hp",
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL,
" 49g+");
x49gp_ui_draw_text(cr, &widget->style->black,
X49GP_UI_NORMAL_FONT, 13.0, 0.0,
38, 56, 1,
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL,
"graphing calculator");
x49gp_ui_draw_symbol(cr, &widget->style->black, 10.0, 0.0, TRUE,
138, 25, symbol_get_by_name("triangleup"));
left_color = UI_COLOR_GREEN;
right_color = UI_COLOR_RED;
below_color = UI_COLOR_BLACK;
break;
case UI_CALCULATOR_HP50G:
x49gp_ui_draw_text(cr, &widget->style->white,
X49GP_UI_NORMAL_FONT, 15.0, 0.0,
38, 42, 2,
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL,
"HP",
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL,
" 50g");
x49gp_ui_draw_text(cr, &widget->style->white,
X49GP_UI_NORMAL_FONT, 13.0, 0.0,
38, 56, 1,
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL,
"Graphing Calculator");
x49gp_ui_draw_symbol(cr, &widget->style->white, 10.0, 0.0, TRUE,
168, 25, symbol_get_by_name("triangleup"));
left_color = UI_COLOR_WHITE;
right_color = UI_COLOR_ORANGE;
below_color = UI_COLOR_BLUE;
break;
}
cairo_destroy(cr);
for (i = 0; i < ui->nr_buttons; i++) {
key = &x49gp_ui_keys[i];
key = &x50g_ui_keys[i];
if (key->left) {
bitmap_font_text_size(&tiny_font, key->left, &wl, &hl, &a, &dl);
if (!key->right) {
xl = key->x + (key->width - wl) / 2;
bitmap_font_draw_text(ui->bg_pixmap,
&ui->colors[left_color],
&tiny_font,
ui->kb_x_offset + xl,
ui->kb_y_offset + key->y - hl + dl + 1,
key->left);
}
}
if (key->right) {
bitmap_font_text_size(&tiny_font, key->right, &wr, &hr, &a, &dr);
if (!key->left) {
xr = key->x + (key->width - wr) / 2;
bitmap_font_draw_text(ui->bg_pixmap,
&ui->colors[right_color],
&tiny_font,
ui->kb_x_offset + xr,
ui->kb_y_offset + key->y - hr + dr + 1,
key->right);
}
}
if (key->left && key->right) {
xl = key->x;
xr = key->x + key->width - 1 - wr;
if (wl + wr > key->width - 4) {
xl += (key->width - 4 - (wl + wr)) / 2;
xr -= (key->width - 4 - (wl + wr)) / 2;
}
bitmap_font_draw_text(ui->bg_pixmap,
&ui->colors[left_color],
&tiny_font,
ui->kb_x_offset + xl,
ui->kb_y_offset + key->y - hl + dl + 1,
key->left);
bitmap_font_draw_text(ui->bg_pixmap,
&ui->colors[right_color],
&tiny_font,
ui->kb_x_offset + xr,
ui->kb_y_offset + key->y - hr + dr + 1,
key->right);
}
if (key->below) {
bitmap_font_text_size(&tiny_font, key->below, &wl, &hl, &a, &dl);
xl = key->x + (key->width - wl) / 2;
bitmap_font_draw_text(ui->bg_pixmap,
&ui->colors[below_color],
&tiny_font,
ui->kb_x_offset + xl,
ui->kb_y_offset + key->y + key->height + 2,
key->below);
}
#if 0 /* Debug Button Layout */
gdk_draw_rectangle(ui->bg_pixmap, ui->window->style->white_gc,
FALSE,
ui->kb_x_offset + key->x,
ui->kb_y_offset + key->y,
key->width, key->height);
#endif
}
gdk_window_set_back_pixmap(widget->window, ui->bg_pixmap, FALSE);
return FALSE;
}
static gboolean
x49gp_window_button_press(GtkWidget *widget, GdkEventButton *event,
gpointer user_data)
{
#ifdef DEBUG_X49GP_UI
fprintf(stderr, "%s:%u: type %u, button %u\n", __FUNCTION__, __LINE__, event->type, event->button);
#endif
gdk_window_focus(widget->window, event->time);
gdk_window_raise(widget->window);
if (event->type != GDK_BUTTON_PRESS)
return FALSE;
if (event->button != 1)
return FALSE;
gdk_window_begin_move_drag(widget->window, event->button,
event->x_root, event->y_root,
event->time);
return FALSE;
}
static void
x49gp_ui_quit(gpointer user_data, GtkWidget *widget, GdkEvent *event)
{
x49gp_t *x49gp = user_data;
x49gp->arm_exit++;
}
static void
x49gp_ui_place_at(x49gp_t *x49gp, GtkFixed *fixed, GtkWidget *widget,
gint x, gint y, gint width, gint height)
{
gtk_widget_set_size_request(widget, width, height);
gtk_fixed_put(fixed, widget, x, y);
}
static int
gui_init(x49gp_module_t *module)
{
x49gp_t *x49gp = module->x49gp;
x49gp_ui_t *ui;
ui = malloc(sizeof(x49gp_ui_t));
if (NULL == ui) {
fprintf(stderr, "%s: %s:%u: Out of memory\n",
x49gp->progname, __FUNCTION__, __LINE__);
return -ENOMEM;
}
memset(ui, 0, sizeof(x49gp_ui_t));
ui->nr_buttons = X49GP_UI_NR_KEYS;
ui->buttons = malloc(ui->nr_buttons * sizeof(x49gp_ui_button_t));
if (NULL == ui->buttons) {
fprintf(stderr, "%s: %s:%u: Out of memory\n",
x49gp->progname, __FUNCTION__, __LINE__);
free(ui);
return -ENOMEM;
}
memset(ui->buttons, 0, ui->nr_buttons * sizeof(x49gp_ui_button_t));
module->user_data = ui;
x49gp->ui = ui;
return 0;
}
static int
gui_exit(x49gp_module_t *module)
{
return 0;
}
static int
gui_reset(x49gp_module_t *module, x49gp_reset_t reset)
{
return 0;
}
static int
gui_load(x49gp_module_t *module, GKeyFile *keyfile)
{
x49gp_t *x49gp = module->x49gp;
x49gp_ui_t *ui = module->user_data;
x49gp_ui_button_t *button;
const x49gp_ui_key_t *key;
GtkWidget *screen_box;
GtkWidget *menu_mount_folder, *menu_mount_image, *menu_unmount;
GtkWidget *menu_debug, *menu_reset, *menu_quit;
GError *gerror = NULL;
GdkBitmap *shape;
char *typestr;
char *imagefile;
int fd;
int i;
x49gp_module_get_string(module, keyfile, "type", "hp50g", &typestr);
if (!strcmp(typestr, "hp49g+")) {
ui->calculator = UI_CALCULATOR_HP49GP;
} else if (!strcmp(typestr, "hp50g")) {
ui->calculator = UI_CALCULATOR_HP50G;
} else {
fprintf(stderr, "Invalid calculator type, reverting to default\n");
ui->calculator = UI_CALCULATOR_HP50G;
}
x49gp_module_get_string(module, keyfile, "name",
ui->calculator == UI_CALCULATOR_HP49GP ?
"HP 49g+" : "HP 50g",
&(ui->name));
fd = x49gp_module_open_rodata(module,
ui->calculator == UI_CALCULATOR_HP49GP ?
"hp49g+.png" : "hp50g.png",
&imagefile);
if (fd < 0) return fd;
gdk_pixbuf_get_file_info(imagefile, &ui->width, &ui->height);
ui->lcd_width = 131 * 2;
ui->lcd_top_margin = 16;
ui->lcd_height = 80 * 2 + ui->lcd_top_margin;
ui->lcd_x_offset = (ui->width - ui->lcd_width) / 2;
ui->lcd_y_offset = 69;
ui->kb_x_offset = 36;
ui->kb_y_offset = 301;
ui->bg_pixbuf = gdk_pixbuf_new_from_file(imagefile, &gerror);
close(fd);
ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_set(ui->window, "can-focus", TRUE, NULL);
gtk_widget_set(ui->window, "accept-focus", TRUE, NULL);
gtk_widget_set(ui->window, "focus-on-map", TRUE, NULL);
gtk_widget_set(ui->window, "resizable", FALSE, NULL);
gtk_window_set_decorated(GTK_WINDOW(ui->window), FALSE);
gtk_widget_set_name(ui->window, ui->name);
gtk_window_set_title(GTK_WINDOW(ui->window), ui->name);
// gtk_window_set_icon(GTK_WINDOW(ui->window), ui->bg_pixbuf);
gdk_pixbuf_render_pixmap_and_mask(ui->bg_pixbuf, NULL, &shape, 255);
gtk_widget_set_size_request(ui->window, ui->width, ui->height);
gtk_widget_shape_combine_mask(ui->window, shape, 0, 0);
g_object_unref(shape);
gtk_widget_realize(ui->window);
ui->shapes[UI_SHAPE_BUTTON_TINY] = gdk_bitmap_create_from_data(NULL,
(char *) button_tiny_bits,
button_tiny_width,
button_tiny_height);
ui->shapes[UI_SHAPE_BUTTON_SMALL] = gdk_bitmap_create_from_data(NULL,
(char *) button_small_bits,
button_small_width,
button_small_height);
ui->shapes[UI_SHAPE_BUTTON_NORMAL] = gdk_bitmap_create_from_data(NULL,
(char *) button_normal_bits,
button_normal_width,
button_normal_height);
ui->shapes[UI_SHAPE_BUTTON_LARGE] = gdk_bitmap_create_from_data(NULL,
(char *) button_large_bits,
button_large_width,
button_large_height);
ui->shapes[UI_SHAPE_BUTTON_ROUND] = gdk_bitmap_create_from_data(NULL,
(char *) button_round_bits,
button_round_width,
button_round_height);
ui->fixed = gtk_fixed_new();
gtk_container_add(GTK_CONTAINER(ui->window), ui->fixed);
ui->background = gtk_drawing_area_new();
gtk_drawing_area_size(GTK_DRAWING_AREA(ui->background),
ui->width, ui->height);
x49gp_ui_place_at(x49gp, GTK_FIXED(ui->fixed), ui->background,
0, 0, ui->width, ui->height);
x49gp_ui_color_init(&ui->colors[UI_COLOR_BLACK], 0x00, 0x00, 0x00);
x49gp_ui_color_init(&ui->colors[UI_COLOR_WHITE], 0xff, 0xff, 0xff);
x49gp_ui_color_init(&ui->colors[UI_COLOR_YELLOW], 0xfa, 0xe8, 0x2c);
x49gp_ui_color_init(&ui->colors[UI_COLOR_RED], 0x8e, 0x25, 0x18);
x49gp_ui_color_init(&ui->colors[UI_COLOR_GREEN], 0x14, 0x4d, 0x49);
x49gp_ui_color_init(&ui->colors[UI_COLOR_SILVER], 0xe0, 0xe0, 0xe0);
x49gp_ui_color_init(&ui->colors[UI_COLOR_ORANGE], 0xc0, 0x6e, 0x60);
x49gp_ui_color_init(&ui->colors[UI_COLOR_BLUE], 0x40, 0x60, 0xa4);
x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_0], 0xab, 0xd2, 0xb4);
x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_1], 0xa0, 0xc4, 0xa8);
x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_2], 0x94, 0xb6, 0x9c);
x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_3], 0x89, 0xa8, 0x90);
x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_4], 0x7d, 0x9a, 0x84);
x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_5], 0x72, 0x8c, 0x78);
x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_6], 0x67, 0x7e, 0x6c);
x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_7], 0x5b, 0x70, 0x60);
x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_8], 0x50, 0x62, 0x54);
x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_9], 0x44, 0x54, 0x48);
x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_10], 0x39, 0x46, 0x3c);
x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_11], 0x2e, 0x38, 0x30);
x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_12], 0x22, 0x2a, 0x24);
x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_13], 0x17, 0x1c, 0x18);
x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_14], 0x0b, 0x03, 0x0c);
x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_15], 0x00, 0x00, 0x00);
ui->lcd_canvas = gtk_drawing_area_new();
gtk_drawing_area_size(GTK_DRAWING_AREA(ui->lcd_canvas),
ui->lcd_width, ui->lcd_height);
screen_box = gtk_event_box_new();
gtk_event_box_set_visible_window(GTK_EVENT_BOX(screen_box),
TRUE);
gtk_event_box_set_above_child(GTK_EVENT_BOX(screen_box),
FALSE);
gtk_container_add(GTK_CONTAINER(screen_box), ui->lcd_canvas);
x49gp_ui_place_at(x49gp, GTK_FIXED(ui->fixed), screen_box,
ui->lcd_x_offset, ui->lcd_y_offset,
ui->lcd_width, ui->lcd_height);
for (i = 0; i < ui->nr_buttons; i++) {
key = &x49gp_ui_keys[i];
key = &x50g_ui_keys[i];
button = &ui->buttons[i];
button->x49gp = x49gp;
button->key = key;
button->button = gtk_button_new();
gtk_widget_set_size_request(button->button,
key->width, key->height);
gtk_widget_set(button->button, "can-focus", FALSE, NULL);
x49gp_ui_button_pixmaps_init(x49gp, button, key->color);
if (key->label) {
button->label = gtk_label_new("");
gtk_widget_set_style(button->label,
button->button->style);
gtk_container_add(GTK_CONTAINER(button->button),
button->label);
g_signal_connect(G_OBJECT(button->label),
"expose-event",
G_CALLBACK(x49gp_button_expose_event),
button);
g_signal_connect_after(G_OBJECT(button->label),
"realize",
G_CALLBACK(x49gp_button_realize),
button);
}
button->box = gtk_event_box_new();
gtk_event_box_set_visible_window(GTK_EVENT_BOX(button->box),
TRUE);
gtk_event_box_set_above_child(GTK_EVENT_BOX(button->box),
FALSE);
gtk_widget_shape_combine_mask(button->box,
ui->shapes[key->shape], 0, 0);
gtk_container_add(GTK_CONTAINER(button->box), button->button);
x49gp_ui_place_at(x49gp, GTK_FIXED(ui->fixed), button->box,
ui->kb_x_offset + key->x,
ui->kb_y_offset + key->y,
key->width, key->height);
g_signal_connect(G_OBJECT(button->button),
"button-press-event",
G_CALLBACK(x49gp_ui_button_press), button);
g_signal_connect(G_OBJECT(button->button),
"button-release-event",
G_CALLBACK(x49gp_ui_button_release), button);
g_signal_connect(G_OBJECT(button->button),
"leave-notify-event",
G_CALLBACK(x49gp_ui_button_leave), button);
gtk_widget_add_events(button->button,
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_LEAVE_NOTIFY_MASK);
}
ui->menu = gtk_menu_new();
menu_mount_folder = gtk_menu_item_new_with_label("Mount SD folder ...");
gtk_menu_shell_append(GTK_MENU_SHELL(ui->menu), menu_mount_folder);
g_signal_connect(G_OBJECT(menu_mount_folder), "activate",
G_CALLBACK(x49gp_ui_mount_sd_folder), x49gp);
menu_mount_image = gtk_menu_item_new_with_label("Mount SD image ...");
gtk_menu_shell_append(GTK_MENU_SHELL(ui->menu), menu_mount_image);
g_signal_connect(G_OBJECT(menu_mount_image), "activate",
G_CALLBACK(x49gp_ui_mount_sd_image), x49gp);
menu_unmount = gtk_menu_item_new_with_label("Unmount SD");
gtk_menu_shell_append(GTK_MENU_SHELL(ui->menu), menu_unmount);
g_signal_connect_swapped(G_OBJECT(menu_unmount), "activate",
G_CALLBACK(s3c2410_sdi_unmount), x49gp);
ui->menu_unmount = menu_unmount;
if (x49gp->debug_port != 0) {
gtk_menu_shell_append(GTK_MENU_SHELL(ui->menu),
gtk_separator_menu_item_new());
menu_debug = gtk_menu_item_new_with_label("Start debugger");
gtk_menu_shell_append(GTK_MENU_SHELL(ui->menu), menu_debug);
g_signal_connect(G_OBJECT(menu_debug), "activate",
G_CALLBACK(x49gp_ui_debug), x49gp);
ui->menu_debug = menu_debug;
} else
ui->menu_debug = NULL;
gtk_menu_shell_append(GTK_MENU_SHELL(ui->menu),
gtk_separator_menu_item_new());
menu_reset = gtk_menu_item_new_with_label("Reset");
gtk_menu_shell_append(GTK_MENU_SHELL(ui->menu), menu_reset);
g_signal_connect(G_OBJECT(menu_reset), "activate",
G_CALLBACK(x49gp_ui_calculator_reset), x49gp);
menu_quit = gtk_menu_item_new_with_label("Quit");
gtk_menu_shell_append(GTK_MENU_SHELL(ui->menu), menu_quit);
g_signal_connect_swapped(G_OBJECT(menu_quit), "activate",
G_CALLBACK(x49gp_ui_quit), x49gp);
gtk_widget_show_all(ui->menu);
g_signal_connect(G_OBJECT(screen_box), "button-press-event",
G_CALLBACK(x49gp_ui_show_menu), x49gp);
g_signal_connect(G_OBJECT(ui->background), "configure-event",
G_CALLBACK(x49gp_window_configure_event), x49gp);
g_signal_connect(G_OBJECT(ui->lcd_canvas), "expose-event",
G_CALLBACK(x49gp_lcd_expose_event), x49gp);
g_signal_connect(G_OBJECT(ui->lcd_canvas), "configure-event",
G_CALLBACK(x49gp_lcd_configure_event), x49gp);
g_signal_connect_swapped(G_OBJECT(ui->window), "delete-event",
G_CALLBACK(x49gp_ui_quit), x49gp);
g_signal_connect_swapped(G_OBJECT(ui->window), "destroy",
G_CALLBACK(x49gp_ui_quit), x49gp);
g_signal_connect(G_OBJECT(ui->window), "focus-out-event",
G_CALLBACK(x49gp_ui_focus_lost), x49gp);
g_signal_connect(G_OBJECT(ui->window), "key-press-event",
G_CALLBACK(x49gp_ui_key_event), x49gp);
g_signal_connect(G_OBJECT(ui->window), "key-release-event",
G_CALLBACK(x49gp_ui_key_event), x49gp);
g_signal_connect(G_OBJECT(ui->window), "button-press-event",
G_CALLBACK(x49gp_window_button_press), x49gp);
gtk_widget_add_events(ui->window,
GDK_FOCUS_CHANGE_MASK |
GDK_BUTTON_PRESS_MASK |
GDK_KEY_PRESS_MASK |
GDK_KEY_RELEASE_MASK);
gtk_widget_show_all(ui->window);
return 0;
}
static int
gui_save(x49gp_module_t *module, GKeyFile *keyfile)
{
x49gp_ui_t *ui = module->user_data;
x49gp_module_set_string(module, keyfile, "type",
ui->calculator == UI_CALCULATOR_HP49GP ?
"hp49g+" : "hp50g");
x49gp_module_set_string(module, keyfile, "name", ui->name);
return 0;
}
int
x49gp_ui_init(x49gp_t *x49gp)
{
x49gp_module_t *module;
if (x49gp_module_init(x49gp, "gui", gui_init, gui_exit,
gui_reset, gui_load, gui_save, NULL,
&module)) {
return -1;
}
return x49gp_module_register(module);
}