/* $Id: CALC.CPP 2.4 1995/07/20 11:24:33 leon Exp $
*------------------------------------------------------------*
* *
* Calc.cpp: TCalcDisplay member functions and TCalculator *
* constructor *
* *
*------------------------------------------------------------*/
/*
* Turbo Vision - Version 2.0
*
* Copyright (c) 1994 by Borland International
* All Rights Reserved.
*
*/
#define Uses_TRect
#define Uses_TEvent
#define Uses_TButton
#define Uses_TKeys
#define Uses_TDrawBuffer
#define Uses_TStreamableClass
#define Uses_TStreamable
#define Uses_TView
#define Uses_TDialog
#include <tvision\tv.h>
__link( RView )
__link( RDialog )
__link( RButton )
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <strstrea.h>
#include <iomanip.h>
#include "calc.h"
#define cpCalcPalette "\x13"
//
// TCalcDisplay functions
//
const char * const TCalcDisplay::name = "TCalcDisplay";
/**
** Streamable write function for saving window int the stream
**/
void TCalcDisplay::write( opstream& os )
{
TView::write( os );
os.writeBytes(&status, sizeof(status));
os.writeString(number);
os.writeByte(sign);
os.writeByte(operate);
os.writeBytes(&operand, sizeof(operand));
}
/**
** Reads window from input stream
**/
void *TCalcDisplay::read( ipstream& is )
{
TView::read( is );
number = new char[DISPLAYLEN];
is.readBytes(&status, sizeof(status));
is.readString(number, DISPLAYLEN);
sign = is.readByte();
operate = is.readByte();
is.readBytes(&operand, sizeof(operand));
return this;
}
/**
** Builds window from streamabmle data
**/
TStreamable *TCalcDisplay::build()
{
return new TCalcDisplay( streamableInit );
}
TStreamableClass RCalcDisplay( TCalcDisplay::name,
TCalcDisplay::build,
__DELTA(TCalcDisplay)
);
/**
** Creates TCalculator display window
**/
TCalcDisplay::TCalcDisplay(TRect& r) : TView ( r )
{
options |= ofSelectable;
eventMask = (evKeyboard | evBroadcast);
number = new char[DISPLAYLEN];
clear();
}
/** {duh} **/
TCalcDisplay::~TCalcDisplay()
{
delete number;
}
/** Retrieves palete **/
TPalette& TCalcDisplay::getPalette() const
{
static TPalette palette( cpCalcPalette, sizeof(cpCalcPalette)-1 );
return palette;
}
/**
** Handles calculator events
**/
void TCalcDisplay::handleEvent(TEvent& event)
{
TView::handleEvent(event);
switch(event.what)
{
case evKeyboard:
calcKey(event.keyDown.charScan.charCode);
clearEvent(event);
break;
case evBroadcast:
if(event.message.command == cmCalcButton)
{
calcKey( ((TButton *) event.message.infoPtr)->title[0]);
clearEvent(event);
}
break;
}
}
/**
** Draws calculator
**/
void TCalcDisplay::draw()
{
char color = getColor(1);
short i;
TDrawBuffer buf;
i = (short)(size.x - strlen(number) - 2);
buf.moveChar(0, ' ', color, (short)size.x);
buf.moveChar(i, sign, color, (short)1 );
buf.moveStr((short)(i+1), number, color);
writeLine(0, 0, (short)size.x, 1, buf);
}
/**
** Writes error to the display window
**/
void TCalcDisplay::error()
{
status = csError;
strcpy(number, "Error");
sign = ' ';
}
/**
** Clears display
**/
void TCalcDisplay::clear()
{
status = csFirst;
strcpy(number, "0");
sign = ' ';
operate = '=';
}
/**
** Sets display double value
**/
void TCalcDisplay::setDisplay(double r)
{
int len;
char str[64];
ostrstream displayStr( str, sizeof str );
if(r < 0.0)
{
sign = '-';
displayStr << -r << ends;
}
else
{
displayStr << r << ends;
sign = ' ';
}
len = strlen(str) - 1; // Minus one so we can use as an index.
if(len > DISPLAYLEN)
error();
else
strcpy(number, str);
}
/**
** Checks if the value is valid
**/
void TCalcDisplay::checkFirst()
{
if( status == csFirst)
{
status = csValid;
strcpy(number, "0");
sign = ' ';
}
}
/**
** Translates key into command
**/
void TCalcDisplay::calcKey(unsigned char key)
{
char stub[2] = " ";
double r;
key = (unsigned char)toupper(key);
if( status == csError && key != 'C')
key = ' ';
switch(key)
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
checkFirst();
if (strlen(number) < 15)
{ // 15 is max visible display length
if (strcmp(number, "0") == NULL)
number[0] = '\0';
stub[0] = key;
strcat(number, stub);
}
break;
case '.':
checkFirst();
if(strchr(number, '.') == NULL)
{
stub[0] = '.';
strcat(number, stub);
}
break;
case 8:
case 27:
int len;
checkFirst();
if( (len = strlen(number)) == 1 )
strcpy(number, "0");
else
number[len-1] = '\0';
break;
case '_': // underscore (keyboard version of +/-)
case 241: // +/- extended character.
if (sign==' ')
sign='-';
else
sign=' ';
break;
case '+': case '-': case '*': case '/':
case '=': case '%': case 13:
if(status == csValid)
{
status = csFirst;
r = getDisplay() * ((sign == '-') ? -1.0 : 1.0);
if( key == '%' )
{
if(operate == '+' || operate == '-')
r = (operand * r) / 100;
else
r /= 100;
}
switch( operate )
{
case '+':
setDisplay(operand + r);
break;
case '-':
setDisplay(operand - r);
break;
case '*':
setDisplay(operand * r);
break;
case '/':
if(r == 0)
error();
else
setDisplay(operand / r);
break;
}
}
operate = key;
operand = getDisplay() * ((sign == '-') ? -1.0 : 1.0);
break;
case 'C':
clear();
break;
}
drawView();
}
static char *keyChar[20] =
{ "C", "\x1B", "%", "\xF1", // 0x1B is escape, 0xF1 is +/- char.
"7", "8", "9", "/",
"4", "5", "6", "*",
"1", "2", "3", "-",
"0", ".", "=", "+"
};
//
// TCalculator functions
//
const char * const TCalculator::name = "TCalculator";
/**
** Builds window from streamabmle data
**/
TStreamable *TCalculator::build()
{
return new TCalculator( streamableInit );
}
TStreamableClass RCalculator( TCalculator::name,
TCalculator::build,
__DELTA(TCalculator)
);
/**
** Main calculator constrictor
**/
TCalculator::TCalculator() :
TDialog( TRect(5, 3, 29, 18), "Calculator" ),
TWindowInit( &TCalculator::initFrame )
{
TView *tv;
TRect r;
options |= ofFirstClick;
for(int i = 0; i <= 19; i++)
{
int x = (i%4)*5+2;
int y = (i/4)*2+4;
r = TRect( x, y, x+5, y+2 );
tv = new TButton( r, keyChar[i], cmCalcButton, bfNormal | bfBroadcast );
tv->options &= ~ofSelectable;
insert( tv );
}
r = TRect( 3, 2, 21, 3 );
insert( new TCalcDisplay(r) );
}
syntax highlighted by Code2HTML, v. 0.9.1