blob: 38f353a2835cbb86197a6825738af8b408a7e1a1 [file] [log] [blame]
/*
* Twin - A Tiny Window System
* Copyright © 2004 Keith Packard <keithp@keithp.com>
* All rights reserved.
*
* This Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with the Gnome Library; see the file COPYING.LIB. If not,
* write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "twin_calc.h"
#include <stdio.h>
#define TWIN_CALC_STACK 5
#define TWIN_CALC_ZERO 0
#define TWIN_CALC_ONE 1
#define TWIN_CALC_TWO 2
#define TWIN_CALC_THREE 3
#define TWIN_CALC_FOUR 4
#define TWIN_CALC_FIVE 5
#define TWIN_CALC_SIX 6
#define TWIN_CALC_SEVEN 7
#define TWIN_CALC_EIGHT 8
#define TWIN_CALC_NINE 9
#define TWIN_CALC_PLUS 10
#define TWIN_CALC_MINUS 11
#define TWIN_CALC_TIMES 12
#define TWIN_CALC_DIVIDE 13
#define TWIN_CALC_EQUAL 14
#define TWIN_CALC_CLEAR 15
#define TWIN_CALC_NBUTTON 16
/*
* Layout:
*
* display
*
* 7 8 9 +
* 4 5 6 -
* 1 2 3 *
* 0 clr = ÷
*/
#define TWIN_CALC_COLS 4
#define TWIN_CALC_ROWS 4
static const int calc_layout[TWIN_CALC_ROWS][TWIN_CALC_COLS] = {
{ TWIN_CALC_SEVEN, TWIN_CALC_EIGHT, TWIN_CALC_NINE, TWIN_CALC_PLUS },
{ TWIN_CALC_FOUR, TWIN_CALC_FIVE, TWIN_CALC_SIX, TWIN_CALC_MINUS },
{ TWIN_CALC_ONE, TWIN_CALC_TWO, TWIN_CALC_THREE, TWIN_CALC_TIMES },
{ TWIN_CALC_ZERO, TWIN_CALC_CLEAR, TWIN_CALC_EQUAL, TWIN_CALC_DIVIDE },
};
typedef struct _twin_calc {
int stack[TWIN_CALC_STACK];
int pending_op;
twin_bool_t pending_delete;
twin_window_t *window;
twin_toplevel_t *toplevel;
twin_box_t *keys;
twin_box_t *cols[4];
twin_label_t *display;
twin_button_t *buttons[TWIN_CALC_NBUTTON];
} twin_calc_t;
static const char *twin_calc_labels[] = {
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"+", "-", "*", "/", "=", "CLR"
};
#define TWIN_CALC_VALUE_SIZE twin_int_to_fixed(29)
#define TWIN_CALC_VALUE_STYLE TWIN_TEXT_ROMAN
#define TWIN_CALC_VALUE_FG 0xff000000
#define TWIN_CALC_VALUE_BG 0x80808080
#define TWIN_CALC_BUTTON_SIZE twin_int_to_fixed(15)
#define TWIN_CALC_BUTTON_STYLE TWIN_TEXT_BOLD
#define TWIN_CALC_BUTTON_FG 0xff000000
#define TWIN_CALC_BUTTON_BG 0xc0808080
static int
_twin_calc_button_to_id (twin_calc_t *calc, twin_button_t *button)
{
int i;
for (i = 0; i < TWIN_CALC_NBUTTON; i++)
if (calc->buttons[i] == button)
return i;
return -1;
}
static void
_twin_calc_update_value (twin_calc_t *calc)
{
char v[20];
sprintf (v, "%d", calc->stack[0]);
twin_label_set (calc->display, v, TWIN_CALC_VALUE_FG,
TWIN_CALC_VALUE_SIZE, TWIN_CALC_VALUE_STYLE);
}
static void
_twin_calc_push (twin_calc_t *calc)
{
int i;
for (i = 0; i < TWIN_CALC_STACK - 1; i++)
calc->stack[i+1] = calc->stack[i];
calc->pending_delete = TWIN_TRUE;
}
static int
_twin_calc_pop (twin_calc_t *calc)
{
int i;
int v = calc->stack[0];
for (i = 0; i < TWIN_CALC_STACK - 1; i++)
calc->stack[i] = calc->stack[i+1];
return v;
}
static void
_twin_calc_digit (twin_calc_t *calc, int digit)
{
if (calc->pending_delete)
{
calc->stack[0] = 0;
calc->pending_delete = TWIN_FALSE;
}
calc->stack[0] = calc->stack[0] * 10 + digit;
_twin_calc_update_value (calc);
}
static void
_twin_calc_button_signal (twin_button_t *button,
twin_button_signal_t signal,
void *closure)
{
twin_calc_t *calc = closure;
int i;
int a, b;
if (signal != TwinButtonSignalDown) return;
i = _twin_calc_button_to_id (calc, button);
if (i < 0) return;
switch (i) {
case TWIN_CALC_PLUS:
case TWIN_CALC_MINUS:
case TWIN_CALC_TIMES:
case TWIN_CALC_DIVIDE:
calc->pending_op = i;
_twin_calc_push (calc);
break;
case TWIN_CALC_EQUAL:
if (calc->pending_op != 0)
{
b = _twin_calc_pop (calc);
a = _twin_calc_pop (calc);
switch (calc->pending_op) {
case TWIN_CALC_PLUS: a = a + b; break;
case TWIN_CALC_MINUS: a = a - b; break;
case TWIN_CALC_TIMES: a = a * b; break;
case TWIN_CALC_DIVIDE: if (!b) a = 0; else a = a / b; break;
}
_twin_calc_push (calc);
calc->stack[0] = a;
_twin_calc_update_value (calc);
calc->pending_op = 0;
}
calc->pending_delete = TWIN_TRUE;
break;
case TWIN_CALC_CLEAR:
for (i = 0; i < TWIN_CALC_STACK; i++)
calc->stack[i] = 0;
calc->pending_op = 0;
calc->pending_delete = TWIN_TRUE;
_twin_calc_update_value (calc);
break;
default:
_twin_calc_digit (calc, i);
break;
}
}
void
twin_calc_start (twin_screen_t *screen, const char *name, int x, int y, int w, int h)
{
twin_calc_t *calc = malloc (sizeof (twin_calc_t));
int i, j;
calc->toplevel = twin_toplevel_create (screen,
TWIN_ARGB32,
TwinWindowApplication,
x, y, w, h, name);
calc->display = twin_label_create (&calc->toplevel->box,
"0",
TWIN_CALC_VALUE_FG,
TWIN_CALC_VALUE_SIZE,
TWIN_CALC_VALUE_STYLE);
twin_widget_set (&calc->display->widget, TWIN_CALC_VALUE_BG);
calc->display->align = TwinAlignRight;
calc->display->widget.shape = TwinShapeLozenge;
calc->keys = twin_box_create (&calc->toplevel->box, TwinBoxHorz);
for (i = 0; i < TWIN_CALC_COLS; i++)
{
calc->cols[i] = twin_box_create (calc->keys, TwinBoxVert);
for (j = 0; j < TWIN_CALC_ROWS; j++)
{
int b = calc_layout[j][i];
calc->buttons[b] = twin_button_create (calc->cols[i],
twin_calc_labels[b],
TWIN_CALC_BUTTON_FG,
TWIN_CALC_BUTTON_SIZE,
TWIN_CALC_BUTTON_STYLE);
twin_widget_set (&calc->buttons[b]->label.widget,
TWIN_CALC_BUTTON_BG);
calc->buttons[b]->signal = _twin_calc_button_signal;
calc->buttons[b]->closure = calc;
/* calc->buttons[b]->label.widget.shape = TwinShapeLozenge; */
if (i || j)
calc->buttons[b]->label.widget.copy_geom = &calc->buttons[calc_layout[0][0]]->label.widget;
}
}
for (i = 0; i < TWIN_CALC_STACK; i++)
calc->stack[i] = 0;
calc->pending_delete = TWIN_TRUE;
calc->pending_op = 0;
twin_toplevel_show (calc->toplevel);
}