File: calc.c

package info (click to toggle)
grafix 1.6-5
  • links: PTS
  • area: main
  • in suites: woody
  • size: 1,156 kB
  • ctags: 1,962
  • sloc: ansic: 20,183; makefile: 186; sh: 3
file content (166 lines) | stat: -rw-r--r-- 5,041 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// calc.c : a very simple calculator, part of the grafix package
//    wolf 12/94, 
//          hex/dec/bin conversion 
//          works only with integers, no overflow check is performed
//          arithmetic and logical operations

#include "window.h"
#include <ctype.h>

static int mode = 0, // actual display mode : 0 = decimal, 1 = hex, 2 = bin
       base = 10;    // 10       or  16
char *modestr[3]= {"dec","hex","bin"};

typedef void (*OP) (int&, int); // operator function
void identity(int &x,int y) { x = y; };

class acc_disp : public window { // display and manipulate the accumulator
  int value, acc;
  OP op_st; // operation stack
  Bool init; // start entering a new number (is set after ops )
public:
  acc_disp(window & parent, int w, int h, int x, int y) :
    window (parent,w,h,x,y,2) { 
      value = 0; acc = 0; op_st = identity; init = True;
   } 
  virtual void redraw()  {
    char st[33]; 
    switch (mode) {
      case 0: 
      case 1: sprintf(st, (base == 10) ? "%20d" : "0x%18X",value); break;
      case 2: unsigned n = 32, x = value; // unsigned !!
	memset(st,' ',n); st[n] = 0; 
        do { st[--n] = (x & 1) ? '1' : '0'; x >>= 1; } while (x); 	
    }
    clear(); PlaceText(st); 
  }
  virtual void enter(char digit) { 
    if (init) { init = False; value = 0; }
    value = base*value + digit;
    redraw(); 
  }
  void ce() { value = 0; redraw(); }
  void ca() { value = 0; acc = 0; op_st = identity; redraw(); }
  void operate (OP opf) { // for operations
    (*op_st)(acc,value); value = acc; redraw();
    op_st = opf; init = True; // enter
  } 
};

acc_disp *disp;

class mode_button : public button {
public:
  mode_button(window & parent, int w, int h, int x, int y) :
  button(parent,modestr[mode],w,h,x,y) { }
  
  virtual void BPress_1_CB(XButtonEvent) { 
    mode++; mode %= 3; base = (mode == 0) ? 10 : 16;
    Name = modestr[mode]; 
    redraw(); disp->redraw();
  }
};

class digit_butt : public button {
  char digit;
  char nstr[2];
 public:
  digit_butt(window & parent, char dig, int w, int h, int x, int y) :
    button(parent,"",w,h,x,y) { 
      digit = dig; sprintf(nstr,"%X",digit);
      Name = nstr; 
    }
  virtual void BPress_1_CB(XButtonEvent) { 
    if (mode > 0 || digit < 10 ) disp->enter(digit); 
    else XBell(display,-80);
  }
};

static void plus(int &x, int y) { x += y; }
static void minus(int &x, int y) { x -= y; }
static void mult(int &x, int y) { x *= y; }
static void divi(int &x, int y) { if (y == 0) y = 1; x /= y; }
static void divq(int &x, int y) { if (y == 0) y = 1; x %= y; }
static void eq(int &x, int y) { x = y; }

static void and(int &x, int y) { x &= y; }
static void or(int &x, int y) { x |= y; }
static void xor(int &x, int y) { x ^= y; }
static void shl(int &x, int y) { x <<= y; }
static void shr(int &x, int y) { x >>= y; }

struct op_struct {char *Name; OP opf; };

op_struct arith[] = { {"+",plus}, {"-",minus}, {"*",mult}, 
		       {"/",divi}, {"%",divq}, {"=",eq} };

op_struct bitops[] = { {"&",and }, {"|",or   }, { "^", xor},
		       {"<<",shl}, {">>",shr} };

class operator_button : public button {
  op_struct *opp;
public:
  operator_button(window & parent, op_struct *op, int w, int h, int x, int y) :
  button(parent,op->Name,w,h,x,y) { opp = op; }
  
  virtual void BPress_1_CB(XButtonEvent) {  
    disp->operate(opp->opf);
  }
};

#include "calc.icon"

// derive to handle keypress events !
class calc_main : public main_window { 
public:
  calc_main(char *name, int w, int h) : main_window(name,w,h) { 
    set_icon(icon_bits,icon_width,icon_height);
    selection_mask |= KeyPressMask;
  }
  virtual void KeyPress_CB(XKeyEvent ev) {
    KeySym keysym = XLookupKeysym(&ev,ev.state & 1);
    if (isxdigit(keysym & 0xff)) { // 0..F
      char c2[] = { keysym, 0}; // keysym convert to string
      disp->enter(strtol(c2,0,16)); // and then to int
    } else 
      if (keysym == 0xff0d) disp->operate(eq); // return -> =
      else
	for (int op=0; op < 6; op++) { // operators +-*/=%
	  op_struct *opp = arith+op;
	  if (keysym == (unsigned) opp->Name[0]) disp->operate(opp->opf);
	}   
  }
};

int main(int , char *argv[]) 
{ 
  main_window *mainw = new calc_main(argv[0], 220, 300); 
  disp = new acc_disp(*mainw,200,20,10,10);

  // first column of operators
  new mode_button(*mainw,30,20,10,40); 
  new instance_button <acc_disp> 
                    (*mainw,"CA",&acc_disp::ca,disp,30,20,10,220);
  new instance_button <acc_disp> 
                    (*mainw,"CE",&acc_disp::ce,disp,30,20,10,250);
  digit_butt *db[16];
  int x = 50, y = 250, dig; 

  for (dig = 0; dig < 0x10; dig++) {
    db[dig] = new digit_butt(*mainw,dig,20,20,x,y); x+= 30;
    if (dig % 3 == 0) { x = 50; y -= 30; }
  }

  // colum with arithmetics
  new quit_button(*mainw,30,20, 145, 40);
  y = 70; int op;
  for (op=0; op < 6; op++) {
    new operator_button(*mainw,&arith[op],30,20,145,y); y+= 30;
  }  
  y = 70; 
  for (op=0; op < 5; op++) {
    new operator_button(*mainw,&bitops[op],30,20,180,y); y+= 30;
  }

  mainw->main_loop();
}