Quite a bunch of changes... but it doesn't work perfectly yet.

I ran into an obscure Pe bug which resulted in me overwriting
the wrong file... but then the machine KDLd, which it almost
never does... and I got lucky and the file was there again...
But this teaches me to commit more often.
* replaced expression area with a custom text view
* added expression string history (a bit dumb yet)
* added option to hide the keypad


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17767 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus 2006-06-07 18:14:55 +00:00
parent c13a4ddf0f
commit b4d21c8325
11 changed files with 1624 additions and 1073 deletions

View File

@ -20,11 +20,46 @@
CalcOptions::CalcOptions()
: auto_num_lock(true),
audio_feedback(false)
audio_feedback(false),
show_keypad(true)
{
}
void
CalcOptions::LoadSettings(const BMessage* archive)
{
bool option;
if (archive->FindBool("auto num lock", &option) == B_OK)
auto_num_lock = option;
if (archive->FindBool("audio feedback", &option) == B_OK)
audio_feedback = option;
if (archive->FindBool("show keypad", &option) == B_OK)
show_keypad = option;
}
status_t
CalcOptions::SaveSettings(BMessage* archive) const
{
status_t ret = archive->AddBool("auto num lock", auto_num_lock);
if (ret == B_OK)
ret = archive->AddBool("audio feedback", audio_feedback);
if (ret == B_OK)
ret = archive->AddBool("show keypad", show_keypad);
return ret;
}
// #pragma mark -
CalcOptionsWindow::CalcOptionsWindow(BRect frame, CalcOptions *options,
BMessage* quitMessage,
BHandler* target)
@ -44,6 +79,8 @@ CalcOptionsWindow::CalcOptionsWindow(BRect frame, CalcOptions *options,
// create interface components
float y = 16.0f, vw, vh;
// auto numlock
BRect viewframe(4.0f, y, frame.right, y + 16.0f);
fAutoNumLockCheckBox = new BCheckBox(viewframe,
"autoNumLockCheckBox", "Auto Num Lock", NULL);
@ -53,7 +90,8 @@ CalcOptionsWindow::CalcOptionsWindow(BRect frame, CalcOptions *options,
bg->AddChild(fAutoNumLockCheckBox);
fAutoNumLockCheckBox->ResizeToPreferred();
y += fAutoNumLockCheckBox->Frame().Height();
// audio feedback
viewframe.Set(4.0f, y, frame.right, y + 16.0f);
fAudioFeedbackCheckBox = new BCheckBox(viewframe,
"audioFeedbackCheckBox", "Audio Feedback", NULL);
@ -63,17 +101,29 @@ CalcOptionsWindow::CalcOptionsWindow(BRect frame, CalcOptions *options,
bg->AddChild(fAudioFeedbackCheckBox);
fAudioFeedbackCheckBox->ResizeToPreferred();
y += fAudioFeedbackCheckBox->Frame().Height();
// show keypad
viewframe.Set(4.0f, y, frame.right, y + 16.0f);
fShowKeypadCheckBox = new BCheckBox(viewframe,
"showKeypadCheckBox", "Show Keypad", NULL);
if (fOptions->show_keypad) {
fShowKeypadCheckBox->SetValue(B_CONTROL_ON);
}
bg->AddChild(fShowKeypadCheckBox);
fShowKeypadCheckBox->ResizeToPreferred();
y += fShowKeypadCheckBox->Frame().Height();
// create buttons
viewframe.Set(0.0f, 0.0f, 40.0f, 40.0f);
fOkButton = new BButton(viewframe, "okButton", "OK",
new BMessage(B_QUIT_REQUESTED));
fOkButton->MakeDefault(true);
fOkButton->GetPreferredSize(&vw, &vh);
fOkButton->ResizeTo(vw, vh);
fOkButton->MoveTo(frame.right - vw - 8.0f,
frame.bottom - vh - 8.0f);
bg->AddChild(fOkButton);
fOkButton->MakeDefault(true);
float cw, ch;
fCancelButton = new BButton(viewframe, "cancelButton", "Cancel",
@ -101,6 +151,9 @@ CalcOptionsWindow::QuitRequested()
// audio feedback
fOptions->audio_feedback = fAudioFeedbackCheckBox->Value() == B_CONTROL_ON;
// show keypad
fOptions->show_keypad = fShowKeypadCheckBox->Value() == B_CONTROL_ON;
// notify target of our demise
if (fQuitMessage && fTarget && fTarget->Looper()) {
fQuitMessage->AddRect("window frame", Frame());

View File

@ -16,8 +16,12 @@
struct CalcOptions {
bool auto_num_lock; // automatically activate numlock
bool audio_feedback; // provide audio feedback
bool show_keypad; // show or hide the buttons
CalcOptions();
CalcOptions();
void LoadSettings(const BMessage* archive);
status_t SaveSettings(BMessage* archive) const;
};
class BCheckBox;
@ -41,6 +45,8 @@ class CalcOptionsWindow : public BWindow {
BCheckBox* fAutoNumLockCheckBox;
BCheckBox* fAudioFeedbackCheckBox;
BCheckBox* fShowKeypadCheckBox;
BButton* fOkButton;
BButton* fCancelButton;
};

View File

@ -27,6 +27,7 @@
#include "CalcApplication.h"
#include "CalcOptionsWindow.h"
#include "ExpressionTextView.h"
#include "Parser.h"
@ -66,7 +67,7 @@ CalcView *CalcView::Instantiate(BMessage *archive)
CalcView::CalcView(BRect frame, rgb_color rgbBaseColor)
: BView(frame, "calc-view", B_FOLLOW_ALL_SIDES,
: BView(frame, "DeskCalc", B_FOLLOW_ALL_SIDES,
B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS),
fColums(5),
fRows(4),
@ -74,22 +75,25 @@ CalcView::CalcView(BRect frame, rgb_color rgbBaseColor)
fBaseColor(rgbBaseColor),
fExpressionBGColor((rgb_color){ 0, 0, 0, 255 }),
fWidth(frame.Width()),
fHeight(frame.Height()),
fWidth(1),
fHeight(1),
fKeypadDescription(strdup(kDefaultKeypadDescription)),
fKeypad(NULL),
fExpression(""),
fAboutItem(NULL),
fOptionsItem(NULL),
fPopUpMenu(NULL),
fOptions(new CalcOptions()),
fOptionsWindow(NULL),
fOptionsWindowFrame(30.0, 50.0, 230.0, 200.0)
fOptionsWindowFrame(30.0, 50.0, 230.0, 200.0),
fShowKeypad(true)
{
// create expression text view
fExpressionTextView = new ExpressionTextView(_ExpressionRect(), this);
AddChild(fExpressionTextView);
// tell the app server not to erase our b/g
SetViewColor(B_TRANSPARENT_32_BIT);
@ -112,27 +116,28 @@ CalcView::CalcView(BMessage* archive)
fBaseColor((rgb_color){ 128, 128, 128, 255 }),
fExpressionBGColor((rgb_color){ 0, 0, 0, 255 }),
fWidth(1),
fHeight(1),
fKeypadDescription(strdup(kDefaultKeypadDescription)),
fKeypad(NULL),
fExpression(""),
fAboutItem(NULL),
fOptionsItem(NULL),
fPopUpMenu(NULL),
fOptions(new CalcOptions()),
fOptionsWindow(NULL),
fOptionsWindowFrame(30.0, 50.0, 230.0, 200.0)
fOptionsWindowFrame(30.0, 50.0, 230.0, 200.0),
fShowKeypad(true)
{
// create expression text view
fExpressionTextView = new ExpressionTextView(_ExpressionRect(), this);
AddChild(fExpressionTextView);
// read data from archive
LoadSettings(archive);
// load frame dimensions
BRect frame = Frame();
fWidth = frame.Width();
fHeight = frame.Height();
// create pop-up menu system
_CreatePopUpMenu();
}
@ -146,6 +151,16 @@ CalcView::~CalcView()
}
void
CalcView::AttachedToWindow()
{
SetFont(be_bold_font);
BRect frame(Frame());
FrameResized(frame.Width(), frame.Height());
}
void
CalcView::MessageReceived(BMessage* message)
{
@ -211,6 +226,8 @@ CalcView::MessageReceived(BMessage* message)
BRect frame;
if (message->FindRect("window frame", &frame) == B_OK)
fOptionsWindowFrame = frame;
_ShowKeypad(fOptions->show_keypad);
break;
}
@ -225,38 +242,15 @@ CalcView::MessageReceived(BMessage* message)
void
CalcView::Draw(BRect updateRect)
{
rgb_color rgbWhite = { 255, 255, 255, 0 };
if (!fShowKeypad)
return;
// calculate grid sizes
float sizeDisp = fHeight * K_DISPLAY_YPROP;
BRect keypadRect(_KeypadRect());
float sizeDisp = keypadRect.top;
float sizeCol = fWidth / (float)fColums;
float sizeRow = (fHeight - sizeDisp) / (float)fRows;
// setup areas
BRect displayRect(0.0, 0.0, fWidth, sizeDisp);
BRect keypadRect(0.0, sizeDisp, fWidth, fHeight);
SetFont(be_bold_font);
// ****** DISPLAY Area
if (updateRect.Intersects(displayRect)) {
// paint display b/g
SetHighColor(fExpressionBGColor);
FillRect(updateRect & displayRect);
// render display text
SetHighColor(rgbWhite);
SetLowColor(fExpressionBGColor);
SetDrawingMode(B_OP_COPY);
SetFontSize(sizeDisp * K_FONT_YPROP);
float baselineOffset = sizeDisp * (1.0 - K_FONT_YPROP) * 0.5;
DrawString(fExpression.String(),
BPoint(fWidth - StringWidth(fExpression.String()),
sizeDisp - baselineOffset));
}
// ****** KEYPAD Area
if (updateRect.Intersects(keypadRect)) {
// TODO: support pressed keys
@ -301,10 +295,10 @@ CalcView::Draw(BRect updateRect)
// render key symbols
float halfSizeCol = sizeCol * 0.5f;
SetHighColor(rgbWhite);
SetHighColor(fButtonTextColor);
SetLowColor(fBaseColor);
SetDrawingMode(B_OP_COPY);
SetFontSize(((fHeight - sizeDisp)/(float)fRows) * K_FONT_YPROP);
SetFontSize(((fHeight - sizeDisp) / (float)fRows) * K_FONT_YPROP);
float baselineOffset = ((fHeight - sizeDisp) / (float)fRows)
* (1.0 - K_FONT_YPROP) * 0.5;
CalcKey *key = fKeypad;
@ -347,25 +341,25 @@ CalcView::MouseDown(BPoint point)
// click on display, initiate drag if appropriate
if ((point.y - sizeDisp) < 0.0) {
// only drag if there's some text
if (fExpression.Length() > 0) {
// assemble drag message
BMessage dragmsg(B_MIME_DATA);
dragmsg.AddData("text/plain",
B_MIME_TYPE,
fExpression.String(),
fExpression.Length());
// initiate drag & drop
SetFontSize(sizeDisp * K_FONT_YPROP);
float left = fWidth;
float textWidth = StringWidth(fExpression.String());
if (textWidth < fWidth)
left -= textWidth;
else
left = 0;
BRect displayRect(left, 0.0, fWidth, sizeDisp);
DragMessage(&dragmsg, displayRect);
}
// if (fExpression.Length() > 0) {
// // assemble drag message
// BMessage dragmsg(B_MIME_DATA);
// dragmsg.AddData("text/plain",
// B_MIME_TYPE,
// fExpression.String(),
// fExpression.Length());
//
// // initiate drag & drop
// SetFontSize(sizeDisp * K_FONT_YPROP);
// float left = fWidth;
// float textWidth = StringWidth(fExpression.String());
// if (textWidth < fWidth)
// left -= textWidth;
// else
// left = 0;
// BRect displayRect(left, 0.0, fWidth, sizeDisp);
// DragMessage(&dragmsg, displayRect);
// }
} else {
// click on keypad
@ -407,7 +401,7 @@ CalcView::KeyDown(const char *bytes, int32 numBytes)
case B_SPACE:
case B_ESCAPE:
case 'c': // hack!
case 'c':
// translate to clear key
_PressKey("C");
break;
@ -426,7 +420,7 @@ CalcView::KeyDown(const char *bytes, int32 numBytes)
default: {
// scan the keymap array for match
int keys = fRows * fColums;
for (int i=0; i<keys; i++) {
for (int i = 0; i < keys; i++) {
if (fKeypad[i].keymap[0] == bytes[0]) {
_PressKey(i);
return;
@ -450,8 +444,8 @@ CalcView::MakeFocus(bool focused)
}
}
// pass on request to parent
BView::MakeFocus(focused);
// pass on request to text view
fExpressionTextView->MakeFocus(focused);
}
@ -460,6 +454,24 @@ CalcView::FrameResized(float width, float height)
{
fWidth = width;
fHeight = height;
// layout expression text view
BRect frame = _ExpressionRect();
fExpressionTextView->MoveTo(frame.LeftTop());
fExpressionTextView->ResizeTo(frame.Width(), frame.Height());
frame.OffsetTo(B_ORIGIN);
frame.InsetBy(2, 2);
fExpressionTextView->SetTextRect(frame);
// configure expression text view font size and color
float sizeDisp = fShowKeypad ? fHeight * K_DISPLAY_YPROP : fHeight;
BFont font(be_bold_font);
font.SetSize(sizeDisp * K_FONT_YPROP);
fExpressionTextView->SetViewColor(fExpressionBGColor);
fExpressionTextView->SetLowColor(fExpressionBGColor);
fExpressionTextView->SetFontAndColor(&font, B_FONT_ALL, &fExpressionTextColor);
// fExpressionTextView->SetAlignment(B_ALIGN_RIGHT);
}
@ -478,9 +490,12 @@ CalcView::AboutRequested()
status_t
CalcView::Archive(BMessage* archive, bool deep) const
{
fExpressionTextView->RemoveSelf();
// passed on request to parent
status_t ret = BView::Archive(archive, deep);
const_cast<CalcView*>(this)->AddChild(fExpressionTextView);
// save app signature for replicant add-on loading
if (ret == B_OK)
@ -502,9 +517,7 @@ void
CalcView::Cut()
{
Copy(); // copy data to clipboard
fExpression.SetTo(""); // remove data
_InvalidateExpression();
fExpressionTextView->Clear(); // remove data
}
@ -517,10 +530,11 @@ CalcView::Copy()
BMessage *clipper = be_clipboard->Data();
clipper->what = B_MIME_DATA;
// TODO: should check return for errors!
BString expression = fExpressionTextView->Text();
clipper->AddData("text/plain",
B_MIME_TYPE,
fExpression.String(),
fExpression.Length());
expression.String(),
expression.Length());
//clipper->PrintToStream();
be_clipboard->Commit();
be_clipboard->Unlock();
@ -564,8 +578,9 @@ CalcView::Paste(BMessage *message)
B_MIME_TYPE,
(const void**)&text,
&numBytes) == B_OK) {
fExpression.Append(text, numBytes);
_InvalidateExpression();
BString temp;
temp.Append(text, numBytes);
fExpressionTextView->Insert(temp.String());
}
}
}
@ -614,14 +629,7 @@ CalcView::LoadSettings(BMessage* archive)
}
// load options
const CalcOptions* options;
if (archive->FindData("options", B_RAW_TYPE,
(const void**)&options, &size) == B_OK
&& size == sizeof(CalcOptions)) {
memcpy(fOptions, options, size);
} else {
puts("Missing options from CalcView archive.\n");
}
fOptions->LoadSettings(archive);
// load option window frame
BRect frame;
@ -634,7 +642,7 @@ CalcView::LoadSettings(BMessage* archive)
puts("Missing display text from CalcView archive.\n");
} else {
// init expression text
fExpression = display;
fExpressionTextView->SetText(display);
}
// parse calculator description
@ -668,8 +676,7 @@ CalcView::SaveSettings(BMessage* archive) const
// record current options
if (ret == B_OK)
ret = archive->AddData("options", B_RAW_TYPE,
fOptions, sizeof(CalcOptions));
ret = fOptions->SaveSettings(archive);
// record option window frame
if (ret == B_OK)
@ -677,7 +684,7 @@ CalcView::SaveSettings(BMessage* archive) const
// record display text
if (ret == B_OK)
ret = archive->AddString("displayText", fExpression.String());
ret = archive->AddString("displayText", fExpressionTextView->Text());
// record calculator description
if (ret == B_OK)
@ -687,6 +694,92 @@ CalcView::SaveSettings(BMessage* archive) const
}
void
CalcView::Evaluate()
{
const double EXP_SWITCH_HI = 1e12; // # digits to switch from std->exp form
const double EXP_SWITCH_LO = 1e-12;
BString expression = fExpressionTextView->Text();
expression << "\n";
if (expression.Length() == 0) {
beep();
return;
}
// audio feedback
if (fOptions->audio_feedback) {
BEntry zimp("zimp.AIFF");
entry_ref zimp_ref;
zimp.GetRef(&zimp_ref);
play_sound(&zimp_ref, true, false, false);
}
//printf("evaluate: %s\n", expression.String());
// evaluate expression
Expression parser;
char* tmpstr = strdup(expression.String());
char* start = tmpstr;
char* end = start + expression.Length() - 1;
double value = 0.0;
try {
value = parser.Evaluate(start, end, true);
} catch (const char* error) {
fExpressionTextView->SetText(error);
return;
}
free(tmpstr);
//printf(" -> value: %f\n", value);
// beautify the expression
// TODO: see if this is necessary at all
char buf[64];
if (value == 0) {
strcpy(buf, "0");
} else if (((value < EXP_SWITCH_HI) && (value > EXP_SWITCH_LO)) ||
((value > -EXP_SWITCH_HI) && (value < -EXP_SWITCH_LO))) {
// print in std form
sprintf(buf, "%9f", value);
// hack to remove surplus zeros!
if (strchr(buf, '.')) {
int32 i = strlen(buf) - 1;
for (; i > 0; i--) {
if (buf[i] == '0')
buf[i] = '\0';
else
break;
}
if (buf[i] == '.')
buf[i] = '\0';
}
} else {
// print in exponential form
sprintf(buf, "%e", value);
}
// render new result to display
fExpressionTextView->SetExpression(buf);
}
void
CalcView::FlashKey(const char* bytes, int32 numBytes)
{
BString temp;
temp.Append(bytes, numBytes);
int32 key = _KeyForLabel(temp.String());
if (key >= 0)
_FlashKey(key);
}
// #pragma mark -
@ -697,37 +790,37 @@ CalcView::_ParseCalcDesc(const char* keypadDescription)
fKeypad = new CalcKey[fRows * fColums];
// scan through calculator description and assemble keypad
bool scanFlag = true;
CalcKey *key = fKeypad;
const char *p = keypadDescription;
while (scanFlag) {
while (*p != 0) {
// copy label
char *l = key->label;
while (!isspace(*p))
*l++ = *p++;
*l = '\0';
// set code
if (strcmp(key->label, "=") == 0)
strcpy(key->code, "\n");
else
strcpy(key->code, key->label);
// set keymap
if (strlen(key->label)==1) {
if (strlen(key->label) == 1) {
strcpy(key->keymap, key->label);
} else {
*key->keymap = '\0';
} // end if
// add this to the expression text view, so that it
// will forward the respective KeyDown event to us
fExpressionTextView->AddKeypadLabel(key->label);
// advance
while (isspace(*p))
++p;
key++;
// check desc termination
if (*p == '\0')
scanFlag = false;
}
}
@ -740,24 +833,18 @@ CalcView::_PressKey(int key)
// check for backspace
if (strcmp(fKeypad[key].label, "BS") == 0) {
int32 length = fExpression.Length();
if (length > 0) {
fExpression.Remove(length - 1, 1);
} else {
beep();
return; // no need to redraw
}
fExpressionTextView->BackSpace();
} else if (strcmp(fKeypad[key].label, "C") == 0) {
// C means clear
fExpression.SetTo("");
fExpressionTextView->Clear();
} else {
// append to display text
fExpression.Append(fKeypad[key].code);
// check for evaluation order
if (fKeypad[key].code[0] == '\n') {
_Evaluate();
Evaluate();
} else {
// insert into expression text
fExpressionTextView->Insert(fKeypad[key].code);
// audio feedback
if (fOptions->audio_feedback) {
BEntry zimp("key.AIFF");
@ -769,20 +856,36 @@ CalcView::_PressKey(int key)
}
// redraw display
_InvalidateExpression();
// _InvalidateExpression();
}
void
CalcView::_PressKey(char *label)
CalcView::_PressKey(const char *label)
{
int32 key = _KeyForLabel(label);
if (key >= 0)
_PressKey(key);
}
int32
CalcView::_KeyForLabel(const char *label) const
{
int keys = fRows * fColums;
for (int i = 0; i < keys; i++) {
if (strcmp(fKeypad[i].label, label) == 0) {
_PressKey(i);
return;
return i;
}
}
return -1;
}
void
CalcView::_FlashKey(int32 key)
{
// TODO ...
}
@ -799,83 +902,21 @@ CalcView::_Colorize()
fDarkColor.green = (uint8)(fBaseColor.green * 0.75);
fDarkColor.blue = (uint8)(fBaseColor.blue * 0.75);
fDarkColor.alpha = 255;
}
// keypad text color
uint8 lightness = (fBaseColor.red + fBaseColor.green + fBaseColor.blue) / 3;
if (lightness > 200)
fButtonTextColor = (rgb_color){ 0, 0, 0, 255 };
else
fButtonTextColor = (rgb_color){ 255, 255, 255, 255 };
void
CalcView::_Evaluate()
{
const double EXP_SWITCH_HI = 1e12; // # digits to switch from std->exp form
const double EXP_SWITCH_LO = 1e-12;
if (fExpression.Length() == 0) {
beep();
return;
}
// audio feedback
if (fOptions->audio_feedback) {
BEntry zimp("zimp.AIFF");
entry_ref zimp_ref;
zimp.GetRef(&zimp_ref);
play_sound(&zimp_ref, true, false, false);
}
//printf("evaluate: %s\n", fExpression.String());
// evaluate expression
Expression parser;
char* tmpstr = strdup(fExpression.String());
char* start = tmpstr;
char* end = start + fExpression.Length() - 1;
double value = 0.0;
try {
value = parser.Eval(start, end, true);
} catch (const char* error) {
fExpression = error;
_InvalidateExpression();
return;
}
free(tmpstr);
//printf(" -> value: %f\n", value);
// beautify the expression
// TODO: see if this is necessary at all
char buf[64];
if (value == 0) {
strcpy(buf, "0");
} else if (((value < EXP_SWITCH_HI) && (value > EXP_SWITCH_LO)) ||
((value > -EXP_SWITCH_HI) && (value < -EXP_SWITCH_LO))) {
// print in std form
sprintf(buf, "%9lf", value);
// hack to remove surplus zeros!
if (strchr(buf, '.')) {
int32 i = strlen(buf) - 1;
for (; i > 0; i--) {
if (buf[i] == '0')
buf[i] = '\0';
else
break;
}
if (buf[i] == '.')
buf[i] = '\0';
}
} else {
// print in exponential form
sprintf(buf, "%le", value);
}
// render new result to display
fExpression = buf;
// redraw display
_InvalidateExpression();
// expression text color
lightness = (fExpressionBGColor.red +
fExpressionBGColor.green + fExpressionBGColor.blue) / 3;
if (lightness > 200)
fExpressionTextColor = (rgb_color){ 0, 0, 0, 255 };
else
fExpressionTextColor = (rgb_color){ 255, 255, 255, 255 };
}
@ -895,11 +936,47 @@ CalcView::_CreatePopUpMenu()
}
void
CalcView::_InvalidateExpression()
BRect
CalcView::_ExpressionRect() const
{
float sizeDisp = fHeight * K_DISPLAY_YPROP;
BRect displayRect(0.0, 0.0, fWidth, sizeDisp);
Invalidate(displayRect);
BRect r(0.0, 0.0, fWidth, fHeight);
if (fShowKeypad) {
r.bottom = floorf(fHeight * K_DISPLAY_YPROP);
}
return r;
}
BRect
CalcView::_KeypadRect() const
{
BRect r(0.0, 0.0, -1.0, -1.0);
if (fShowKeypad) {
r.right = fWidth;
r.bottom = fHeight;
r.top = floorf(fHeight * K_DISPLAY_YPROP) + 1;
}
return r;
}
void
CalcView::_ShowKeypad(bool show)
{
if (fShowKeypad == show)
return;
fShowKeypad = show;
float height = fShowKeypad ? fHeight / K_DISPLAY_YPROP
: fHeight * K_DISPLAY_YPROP;
BWindow* window = Window();
if (window->Bounds() == Frame())
window->ResizeTo(fWidth, height);
else
ResizeTo(fWidth, height);
}

View File

@ -12,12 +12,12 @@
#define _CALC_VIEW_H
#include <View.h>
#include <String.h>
class BString;
class BMenuItem;
class CalcOptions;
class CalcOptionsWindow;
class ExpressionTextView;
_EXPORT
class CalcView : public BView {
@ -33,7 +33,7 @@ class CalcView : public BView {
virtual ~CalcView();
virtual void AttachedToWindow();
virtual void MessageReceived(BMessage* message);
virtual void Draw(BRect updateRect);
virtual void MouseDown(BPoint point);
@ -60,18 +60,30 @@ class CalcView : public BView {
status_t LoadSettings(BMessage* archive);
status_t SaveSettings(BMessage* archive) const;
void Evaluate();
void FlashKey(const char* bytes, int32 numBytes);
void AddExpressionToHistory(const char* expression);
void PreviousExpression();
void NextExpression();
private:
void _ParseCalcDesc(const char* keypadDescription);
void _PressKey(int key);
void _PressKey(char* label);
void _PressKey(const char* label);
int32 _KeyForLabel(const char* label) const;
void _FlashKey(int32 key);
void _Colorize();
void _Evaluate();
void _CreatePopUpMenu();
void _InvalidateExpression();
BRect _ExpressionRect() const;
BRect _KeypadRect() const;
void _ShowKeypad(bool show);
// grid dimensions
int16 fColums;
@ -81,7 +93,9 @@ class CalcView : public BView {
rgb_color fBaseColor;
rgb_color fLightColor;
rgb_color fDarkColor;
rgb_color fButtonTextColor;
rgb_color fExpressionBGColor;
rgb_color fExpressionTextColor;
// view dimensions
float fWidth;
@ -93,8 +107,8 @@ class CalcView : public BView {
char* fKeypadDescription;
CalcKey* fKeypad;
// display text
BString fExpression;
// expression
ExpressionTextView* fExpressionTextView;
// pop-up context menu.
BMenuItem* fAboutItem;
@ -105,6 +119,7 @@ class CalcView : public BView {
CalcOptions* fOptions;
CalcOptionsWindow* fOptionsWindow;
BRect fOptionsWindowFrame;
bool fShowKeypad;
};
#endif // _CALC_VIEW_H

View File

@ -0,0 +1,212 @@
/*
* Copyright 2006 Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/
#include "ExpressionTextView.h"
#include <new>
#include <Beep.h>
#include <Window.h>
#include "CalcView.h"
using std::nothrow;
static const int32 kMaxPreviousExpressions = 20;
ExpressionTextView::ExpressionTextView(BRect frame, CalcView* calcView)
: InputTextView(frame, "expression text view",
(frame.OffsetToCopy(B_ORIGIN)).InsetByCopy(2, 2),
B_FOLLOW_NONE, B_WILL_DRAW),
fCalcView(calcView),
fKeypadLabels(""),
fPreviousExpressions(20)
{
SetFont(be_bold_font);
// SetAlignment(B_ALIGN_RIGHT);
SetStylable(false);
SetDoesUndo(true);
SetColorSpace(B_RGB32);
}
ExpressionTextView::~ExpressionTextView()
{
int32 count = fPreviousExpressions.CountItems();
for (int32 i = 0; i < count; i++)
delete (BString*)fPreviousExpressions.ItemAtFast(i);
}
void
ExpressionTextView::MakeFocus(bool focused = true)
{
if (focused == IsFocus()) {
// stop endless loop when CalcView calls us again
return;
}
// NOTE: order of lines important!
InputTextView::MakeFocus(focused);
fCalcView->MakeFocus(focused);
}
void
ExpressionTextView::KeyDown(const char* bytes, int32 numBytes)
{
// handle expression history
if (bytes[0] == B_UP_ARROW) {
PreviousExpression();
return;
}
if (bytes[0] == B_DOWN_ARROW) {
NextExpression();
return;
}
// handle in InputTextView, except B_TAB
if (bytes[0] != B_TAB)
InputTextView::KeyDown(bytes, numBytes);
// pass on to CalcView if this was a label on a key
if (fKeypadLabels.FindFirst(bytes[0]) >= 0)
fCalcView->FlashKey(bytes, numBytes);
// as soon as something is typed, we are at the
// end of the expression history
fHistoryPos = fPreviousExpressions.CountItems();
}
void
ExpressionTextView::MouseDown(BPoint where)
{
uint32 buttons;
Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons);
if (buttons & B_PRIMARY_MOUSE_BUTTON) {
InputTextView::MouseDown(where);
return;
}
where = ConvertToParent(where);
fCalcView->MouseDown(where);
}
// #pragma mark -
void
ExpressionTextView::RevertChanges()
{
Clear();
}
void
ExpressionTextView::ApplyChanges()
{
AddExpressionToHistory(Text());
fCalcView->Evaluate();
}
void
ExpressionTextView::AddKeypadLabel(const char* label)
{
fKeypadLabels << label;
}
void
ExpressionTextView::SetExpression(const char* expression)
{
SetText(expression);
int32 lastPos = strlen(expression);
Select(lastPos, lastPos);
}
void
ExpressionTextView::BackSpace()
{
if (Window())
Window()->PostMessage(B_UNDO, this);
}
void
ExpressionTextView::Clear()
{
SetText("");
}
// #pragma mark -
void
ExpressionTextView::AddExpressionToHistory(const char* expression)
{
BString* item = new (nothrow) BString(expression);
if (!item)
return;
if (!fPreviousExpressions.AddItem(item)) {
delete item;
return;
}
while (fPreviousExpressions.CountItems() > kMaxPreviousExpressions)
delete (BString*)fPreviousExpressions.RemoveItem(0L);
fHistoryPos = fPreviousExpressions.CountItems();
}
void
ExpressionTextView::PreviousExpression()
{
int32 count = fPreviousExpressions.CountItems();
if (fHistoryPos == count) {
// save current expression
fCurrentExpression = Text();
}
fHistoryPos--;
if (fHistoryPos < 0) {
fHistoryPos = 0;
return;
}
BString* item = (BString*)fPreviousExpressions.ItemAt(fHistoryPos);
if (item)
SetExpression(item->String());
}
void
ExpressionTextView::NextExpression()
{
int32 count = fPreviousExpressions.CountItems();
fHistoryPos++;
if (fHistoryPos == count) {
SetExpression(fCurrentExpression.String());
return;
}
if (fHistoryPos > count) {
fHistoryPos = count;
return;
}
BString* item = (BString*)fPreviousExpressions.ItemAt(fHistoryPos);
if (item)
SetExpression(item->String());
}

Binary file not shown.

View File

@ -0,0 +1,163 @@
/*
* Copyright 2006 Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/
#include "InputTextView.h"
#include <stdio.h>
#include <stdlib.h>
#include <String.h>
// constructor
InputTextView::InputTextView(BRect frame, const char* name,
BRect textRect,
uint32 resizingMode,
uint32 flags)
: BTextView(frame, name, textRect, resizingMode, flags),
fWasFocus(false)
{
SetWordWrap(false);
}
// destructor
InputTextView::~InputTextView()
{
}
// MouseDown
void
InputTextView::MouseDown(BPoint where)
{
// enforce the behaviour of a typical BTextControl
// only let the BTextView handle mouse up/down when
// it already had focus
fWasFocus = IsFocus();
if (fWasFocus) {
BTextView::MouseDown(where);
} else {
// forward click
if (BView* view = Parent()) {
view->MouseDown(ConvertToParent(where));
}
}
}
// MouseUp
void
InputTextView::MouseUp(BPoint where)
{
// enforce the behaviour of a typical BTextControl
// only let the BTextView handle mouse up/down when
// it already had focus
if (fWasFocus)
BTextView::MouseUp(where);
}
// KeyDown
void
InputTextView::KeyDown(const char* bytes, int32 numBytes)
{
bool handled = true;
if (numBytes > 0) {
switch (bytes[0]) {
case B_ESCAPE:
// revert any typing changes
RevertChanges();
break;
case B_TAB:
// skip BTextView implementation
BView::KeyDown(bytes, numBytes);
// fall through
case B_RETURN:
ApplyChanges();
break;
default:
handled = false;
break;
}
}
if (!handled)
BTextView::KeyDown(bytes, numBytes);
}
// MakeFocus
void
InputTextView::MakeFocus(bool focus)
{
if (focus != IsFocus()) {
if (BView* view = Parent())
view->Invalidate();
BTextView::MakeFocus(focus);
if (focus)
SelectAll();
ApplyChanges();
}
}
// Invoke
status_t
InputTextView::Invoke(BMessage* message)
{
if (!message)
message = Message();
if (message) {
BMessage copy(*message);
copy.AddInt64("when", system_time());
copy.AddPointer("source", (BView*)this);
return BInvoker::Invoke(&copy);
}
return B_BAD_VALUE;
}
// #pragma mark -
// Select
void
InputTextView::Select(int32 start, int32 finish)
{
BTextView::Select(start, finish);
_CheckTextRect();
}
// InsertText
void
InputTextView::InsertText(const char* inText, int32 inLength, int32 inOffset,
const text_run_array* inRuns)
{
BTextView::InsertText(inText, inLength, inOffset, inRuns);
_CheckTextRect();
}
// DeleteText
void
InputTextView::DeleteText(int32 fromOffset, int32 toOffset)
{
BTextView::DeleteText(fromOffset, toOffset);
_CheckTextRect();
}
// #pragma mark -
// _CheckTextRect
void
InputTextView::_CheckTextRect()
{
// update text rect and make sure
// the cursor/selection is in view
BRect textRect(TextRect());
float width = ceilf(StringWidth(Text()) + 2.0);
if (textRect.Width() < width) {
textRect.right = textRect.left + width;
SetTextRect(textRect);
ScrollToSelection();
}
}

View File

@ -0,0 +1,57 @@
/*
* Copyright 2006 Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/
#ifndef INPUT_TEXT_VIEW_H
#define INPUT_TEXT_VIEW_H
#include <Invoker.h>
#include <TextView.h>
class InputTextView : public BTextView,
public BInvoker {
public:
InputTextView(BRect frame,
const char* name,
BRect textRect,
uint32 resizingMode,
uint32 flags);
virtual ~InputTextView();
// BTextView interface
virtual void MouseDown(BPoint where);
virtual void MouseUp(BPoint where);
virtual void KeyDown(const char* bytes, int32 numBytes);
virtual void MakeFocus(bool focus);
// BInvoker interface
virtual status_t Invoke(BMessage* message = NULL);
// InputTextView
virtual void RevertChanges() = 0;
virtual void ApplyChanges() = 0;
protected:
// BTextView
virtual void Select(int32 start, int32 finish);
virtual void InsertText(const char* inText,
int32 inLength,
int32 inOffset,
const text_run_array* inRuns);
virtual void DeleteText(int32 fromOffset,
int32 toOffset);
void _CheckTextRect();
bool fWasFocus;
};
#endif // INPUT_TEXT_VIEW_H

View File

@ -10,6 +10,8 @@ Application DeskCalc :
CalcView.cpp
CalcWindow.cpp
DeskCalc.cpp
ExpressionTextView.cpp
InputTextView.cpp
Parser.cpp
: be $(TARGET_LIBSTDC++) media
: DeskCalc.rdef

File diff suppressed because it is too large Load Diff

View File

@ -40,31 +40,30 @@
class Expression {
public:
static double valtod(const char *exp, const char **end);
static double exptod(const char *exp, const char **end);
static std::string dtostr(const double value, const unsigned int precision, const char mode); // 0 => exp, 1 => exp3, 2 => SI
static int strprintf(std::string &str, const char * format, ...);
Expression();
Expression();
void SetAglf(const double value);
bool SetConstant(const char* name,
const double value);
void SetAglf(const double value);
bool SetConstant(const char *name, const double value);
double Eval(const char *exp);
double Eval(const char *begin, const char *end, const bool allowWhiteSpaces = false);
const char *Error();
double Evaluate(const char* exp);
double Evaluate(const char* begin, const char* end,
const bool allowWhiteSpaces = false);
const char* Error();
private:
double m_aglf;
const char *m_errorPtr;
bool m_trig;
double _ApplyFunction(const double x,
const size_t number) const;
double func(const double x, const size_t number) const;
std::vector<std::string> m_functionNames;
std::vector<char> m_functionTypes;
double fAglf;
const char* fErrorPtr;
bool fTrig;
std::vector<std::string> m_constantNames;
std::vector<double> m_constantValues;
std::vector<std::string> fFunctionNames;
std::vector<char> fFunctionTypes;
std::vector<std::string> fConstantNames;
std::vector<double> fConstantValues;
};
#endif // PARSER_H