adding DeskCalc by Timothy Wayper

huge cleanup of the DeskCalc code:
* applied style guide
* fixed any TODOs from timmy
* slightly nicer looking options window
* new way to store settings
* code should be more robust
* includes parser kindly donated by Daniel Wallner


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17737 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus 2006-06-06 16:07:47 +00:00
parent 1bba1e12c6
commit 7cb395c433
16 changed files with 2915 additions and 0 deletions

View File

@ -8,6 +8,7 @@ SubInclude HAIKU_TOP src apps clock ;
SubInclude HAIKU_TOP src apps codycam ;
SubInclude HAIKU_TOP src apps cortex ;
SubInclude HAIKU_TOP src apps deskbar ;
SubInclude HAIKU_TOP src apps deskcalc ;
SubInclude HAIKU_TOP src apps diskprobe ;
SubInclude HAIKU_TOP src apps expander ;
SubInclude HAIKU_TOP src apps glteapot ;

View File

@ -0,0 +1,157 @@
/*
* Copyright 2006 Haiku, Inc. All Rights Reserved.
* Copyright 1997, 1998 R3 Software Ltd. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Timothy Wayper <timmy@wunderbear.com>
* Stephan Aßmus <superstippi@gmx.de>
*/
#include "CalcApplication.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <Directory.h>
#include <File.h>
#include <FindDirectory.h>
#include <Path.h>
#include "CalcWindow.h"
static const char* kSettingsFileName = "DeskCalc_settings";
extern const char* kAppSig = "application/x-vnd.Haiku-DeskCalc";
static const float kDefaultWindowWidth = 220.0;
static const float kDefaultWindowHeight = 140.0;
CalcApplication::CalcApplication()
: BApplication(kAppSig),
fCalcWindow(NULL)
{
}
CalcApplication::~CalcApplication()
{
}
void
CalcApplication::ReadyToRun()
{
BRect frame(0, 0, kDefaultWindowWidth - 1, kDefaultWindowHeight - 1);
fCalcWindow = new CalcWindow(frame);
if (!_LoadSettings())
fCalcWindow->SetFrame(frame, true);
// reveal window
fCalcWindow->Show();
}
void
CalcApplication::AboutRequested()
{
// TODO: implement me!
return BApplication::AboutRequested();
}
bool
CalcApplication::QuitRequested()
{
// save current user preferences
_SaveSettings();
return true;
}
// #pragma mark -
bool
CalcApplication::_LoadSettings()
{
// locate preferences file
BFile prefsFile;
if (_InitSettingsFile(&prefsFile, false) < B_OK) {
printf("no preference file found.\n");
return false;
}
// unflatten settings data
BMessage archive;
if (archive.Unflatten(&prefsFile) < B_OK) {
printf("error unflattening settings.\n");
return false;
}
// apply settings
return fCalcWindow->LoadSettings(&archive);
}
void
CalcApplication::_SaveSettings()
{
if (!fCalcWindow->Lock())
return;
// archive the current state of the calculator
BMessage archive;
status_t ret = fCalcWindow->SaveSettings(&archive);
fCalcWindow->Unlock();
if (ret < B_OK) {
fprintf(stderr, "CalcApplication::_SaveSettings() - "
"error from window: %s\n", strerror(ret));
return;
}
// flatten entire acrhive and write to settings file
BFile prefsFile;
ret = _InitSettingsFile(&prefsFile, true);
if (ret < B_OK) {
fprintf(stderr, "CalcApplication::_SaveSettings() - "
"error creating file: %s\n", strerror(ret));
return;
}
ret = archive.Flatten(&prefsFile);
if (ret < B_OK) {
fprintf(stderr, "CalcApplication::_SaveSettings() - "
"error flattening to file: %s\n", strerror(ret));
return;
}
}
status_t
CalcApplication::_InitSettingsFile(BFile* file, bool write)
{
// find user settings directory
BPath prefsPath;
status_t ret = find_directory(B_USER_SETTINGS_DIRECTORY, &prefsPath);
if (ret < B_OK)
return ret;
ret = prefsPath.Append(kSettingsFileName);
if (ret < B_OK)
return ret;
if (write)
ret = file->SetTo(prefsPath.Path(), B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
else
ret = file->SetTo(prefsPath.Path(), B_READ_ONLY);
return ret;
}

View File

@ -0,0 +1,37 @@
/*
* Copyright 2006 Haiku, Inc. All Rights Reserved.
* Copyright 1997, 1998 R3 Software Ltd. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Timothy Wayper <timmy@wunderbear.com>
* Stephan Aßmus <superstippi@gmx.de>
*/
#ifndef _CALC_APPLICATION_H
#define _CALC_APPLICATION_H
#include <Application.h>
extern const char* kAppSig;
class CalcWindow;
class CalcApplication : public BApplication {
public:
CalcApplication();
virtual ~CalcApplication();
virtual void ReadyToRun();
virtual void AboutRequested();
virtual bool QuitRequested();
private:
bool _LoadSettings();
void _SaveSettings();
status_t _InitSettingsFile(BFile* file, bool write);
CalcWindow* fCalcWindow;
};
#endif // _CALC_APPLICATION_H

View File

@ -0,0 +1,101 @@
/*
* Copyright 2006 Haiku, Inc. All Rights Reserved.
* Copyright 1997, 1998 R3 Software Ltd. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Timothy Wayper <timmy@wunderbear.com>
* Stephan Aßmus <superstippi@gmx.de>
*/
#include "CalcOptionsWindow.h"
#include <stdlib.h>
#include <stdio.h>
#include <Box.h>
#include <Button.h>
#include <CheckBox.h>
CalcOptions::CalcOptions()
: mAutoNumLock(true),
mAudioFeedback(false)
{
}
CalcOptionsWindow::CalcOptionsWindow(BRect frame, CalcOptions *options)
: BWindow(frame, "Options", B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS),
fOptions(options)
{
// TODO: revisit when Ingo has created his layout framework...
frame.OffsetTo(B_ORIGIN);
BBox* bg = new BBox(frame, "bg", B_FOLLOW_ALL);
bg->SetBorder(B_PLAIN_BORDER);
AddChild(bg);
frame.InsetBy(5.0f, 5.0f);
// create interface components
float y = 16.0f, vw, vh;
BRect viewframe(4.0f, y, frame.right, y + 16.0f);
fAutoNumLockCheckBox = new BCheckBox(viewframe,
"autoNumLockCheckBox", "Auto Num Lock", NULL);
if (fOptions->mAutoNumLock) {
fAutoNumLockCheckBox->SetValue(B_CONTROL_ON);
}
bg->AddChild(fAutoNumLockCheckBox);
fAutoNumLockCheckBox->ResizeToPreferred();
y += fAutoNumLockCheckBox->Frame().Height();
viewframe.Set(4.0f, y, frame.right, y + 16.0f);
fAudioFeedbackCheckBox = new BCheckBox(viewframe,
"audioFeedbackCheckBox", "Audio Feedback", NULL);
if (fOptions->mAudioFeedback) {
fAudioFeedbackCheckBox->SetValue(B_CONTROL_ON);
}
bg->AddChild(fAudioFeedbackCheckBox);
fAudioFeedbackCheckBox->ResizeToPreferred();
y += fAudioFeedbackCheckBox->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);
float cw, ch;
fCancelButton = new BButton(viewframe, "cancelButton", "Cancel",
new BMessage(B_QUIT_REQUESTED));
fCancelButton->GetPreferredSize(&cw, &ch);
fCancelButton->ResizeTo(cw, ch);
fCancelButton->MoveTo(frame.right - vw - 16.0f - cw,
frame.bottom - ch - 8.0f);
bg->AddChild(fCancelButton);
}
CalcOptionsWindow::~CalcOptionsWindow()
{
// auto num-lock
if (fAutoNumLockCheckBox->Value() == B_CONTROL_ON)
fOptions->mAutoNumLock = true;
else
fOptions->mAutoNumLock = false;
// audio feedback
if (fAudioFeedbackCheckBox->Value() == B_CONTROL_ON)
fOptions->mAudioFeedback = true;
else
fOptions->mAudioFeedback = false;
}

View File

@ -0,0 +1,42 @@
/*
* Copyright 2006 Haiku, Inc. All Rights Reserved.
* Copyright 1997, 1998 R3 Software Ltd. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Timothy Wayper <timmy@wunderbear.com>
* Stephan Aßmus <superstippi@gmx.de>
*/
#ifndef _CALC_OPTIONS_WINDOW_H
#define _CALC_OPTIONS_WINDOW_H
#include <Window.h>
struct CalcOptions {
bool mAutoNumLock; // automatically activate numlock
bool mAudioFeedback; // provide audio feedback
CalcOptions();
};
class BCheckBox;
class BButton;
class CalcOptionsWindow : public BWindow {
public:
CalcOptionsWindow(BRect frame,
CalcOptions* options);
virtual ~CalcOptionsWindow();
private:
CalcOptions* fOptions;
BCheckBox* fAutoNumLockCheckBox;
BCheckBox* fAudioFeedbackCheckBox;
BButton* fOkButton;
BButton* fCancelButton;
};
#endif // _CALC_OPTIONS_WINDOW_H

View File

@ -0,0 +1,878 @@
/*
* Copyright 2006 Haiku, Inc. All Rights Reserved.
* Copyright 1997, 1998 R3 Software Ltd. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Timothy Wayper <timmy@wunderbear.com>
* Stephan Aßmus <superstippi@gmx.de>
*/
#include "CalcView.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <Beep.h>
#include <Clipboard.h>
#include <Font.h>
#include <MenuItem.h>
#include <Message.h>
#include <PlaySound.h>
#include <Point.h>
#include <PopUpMenu.h>
#include "CalcApplication.h"
#include "CalcOptionsWindow.h"
#include "Parser.h"
const uint8 K_COLOR_OFFSET = 32;
const float K_FONT_YPROP = 0.6f;
const float K_DISPLAY_YPROP = 0.2;
enum {
K_OPTIONS_REQUESTED = 'opts'
};
// default calculator key pad layout
const char *kDefaultKeypadDescription =
"7 8 9 ( ) \n"
"4 5 6 * / \n"
"1 2 3 + - \n"
"0 . BS = C \n";
struct CalcView::CalcKey {
char label[8];
char code[8];
char keymap[4];
uint32 flags;
float width;
};
CalcView *CalcView::Instantiate(BMessage *archive)
{
if (!validate_instantiation(archive, "CalcView"))
return NULL;
return new CalcView(archive);
}
CalcView::CalcView(BRect frame, rgb_color rgbBaseColor)
: BView(frame, "calc-view", B_FOLLOW_ALL_SIDES,
B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS),
fColums(5),
fRows(4),
fBaseColor(rgbBaseColor),
fExpressionBGColor((rgb_color){ 0, 0, 0, 255 }),
fWidth(frame.Width()),
fHeight(frame.Height()),
fKeypadDescription(strdup(kDefaultKeypadDescription)),
fKeypad(NULL),
fExpression(""),
fAboutItem(NULL),
fOptionsItem(NULL),
fPopUpMenu(NULL),
fOptions(new CalcOptions()),
fOptionsWindow(NULL)
{
// tell the app server not to erase our b/g
SetViewColor(B_TRANSPARENT_32_BIT);
// parse calculator description
_ParseCalcDesc(fKeypadDescription);
// colorize based on base color.
_Colorize();
// create pop-up menu system
_CreatePopUpMenu();
}
CalcView::CalcView(BMessage* archive)
: BView(archive),
fColums(5),
fRows(4),
fBaseColor((rgb_color){ 128, 128, 128, 255 }),
fExpressionBGColor((rgb_color){ 0, 0, 0, 255 }),
fKeypadDescription(strdup(kDefaultKeypadDescription)),
fKeypad(NULL),
fExpression(""),
fAboutItem(NULL),
fOptionsItem(NULL),
fPopUpMenu(NULL),
fOptions(new CalcOptions()),
fOptionsWindow(NULL)
{
// read data from archive
LoadSettings(archive);
// load frame dimensions
BRect frame = Frame();
fWidth = frame.Width();
fHeight = frame.Height();
// create pop-up menu system
_CreatePopUpMenu();
}
CalcView::~CalcView()
{
delete fKeypad;
delete fOptions;
free(fKeypadDescription);
}
void
CalcView::MessageReceived(BMessage* message)
{
//message->PrintToStream();
// check if message was dropped
if (message->WasDropped()) {
// pass message on to paste
if (message->IsSourceRemote())
Paste(message);
} else {
// act on posted message type
switch (message->what) {
// handle "cut"
case B_CUT:
Cut();
break;
// handle copy
case B_COPY:
Copy();
break;
// handle paste
case B_PASTE:
// access system clipboard
if (be_clipboard->Lock()){
BMessage *clipper = be_clipboard->Data();
//clipper->PrintToStream();
Paste(clipper);
be_clipboard->Unlock();
} // end if
break;
// (replicant) about box requested
case B_ABOUT_REQUESTED:
AboutRequested();
break;
// calculator options window requested
case K_OPTIONS_REQUESTED: {
BRect frame(30.0f, 50.0f, 230.0, 200.0);
fOptionsWindow = new CalcOptionsWindow(frame, fOptions);
fOptionsWindow->Show();
break;
}
default:
BView::MessageReceived(message);
break;
}
}
}
void
CalcView::Draw(BRect updateRect)
{
rgb_color rgbWhite = { 255, 255, 255, 0 };
// calculate grid sizes
float sizeDisp = fHeight * K_DISPLAY_YPROP;
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));
} // end if
// ****** KEYPAD Area
if (updateRect.Intersects(keypadRect)){
// paint keypad b/g
SetHighColor(fBaseColor);
FillRect(updateRect & keypadRect);
// render key main grid
BeginLineArray((fColums + fRows) << 1 + 1);
// render cols
AddLine(BPoint(0.0, sizeDisp),
BPoint(0.0, fHeight),
fLightColor);
for (int col = 1; col < fColums; col++){
AddLine(BPoint(col * sizeCol - 1.0, sizeDisp),
BPoint(col * sizeCol - 1.0, fHeight),
fDarkColor);
AddLine(BPoint(col * sizeCol, sizeDisp),
BPoint(col * sizeCol, fHeight),
fLightColor);
} // end for
AddLine(BPoint(fColums * sizeCol, sizeDisp),
BPoint(fColums * sizeCol, fHeight),
fDarkColor);
// render rows
for (int row = 0; row < fRows; row++){
AddLine(BPoint(0.0, sizeDisp + row * sizeRow - 1.0),
BPoint(fWidth, sizeDisp + row * sizeRow - 1.0),
fDarkColor);
AddLine(BPoint(0.0, sizeDisp + row * sizeRow),
BPoint(fWidth, sizeDisp + row * sizeRow),
fLightColor);
} // end for
AddLine(BPoint(0.0, sizeDisp + fRows * sizeRow),
BPoint(fWidth, sizeDisp + fRows * sizeRow),
fDarkColor);
// main grid complete
EndLineArray();
// render key symbols
float halfSizeCol = sizeCol * 0.5f;
SetHighColor(rgbWhite);
SetLowColor(fBaseColor);
SetDrawingMode(B_OP_COPY);
SetFontSize(((fHeight - sizeDisp)/(float)fRows) * K_FONT_YPROP);
float baselineOffset = ((fHeight - sizeDisp)/(float)fRows)
* (1.0 - K_FONT_YPROP) * 0.5;
CalcKey *key = fKeypad;
for (int row = 0; row < fRows; row++){
for (int col = 0; col < fColums; col++){
float halfSymbolWidth = StringWidth(key->label) * 0.5f;
DrawString(key->label,
BPoint(col * sizeCol + halfSizeCol - halfSymbolWidth,
sizeDisp + (row + 1) * sizeRow - baselineOffset));
key++;
} // end for
} // end for
} // end if
}
void
CalcView::MouseDown(BPoint point)
{
// ensure this view is the current focus
MakeFocus();
// read mouse buttons state
int32 buttons = 0;
Window()->CurrentMessage()->FindInt32("buttons", &buttons);
// display popup menu if not primary mouse button
if ((B_PRIMARY_MOUSE_BUTTON & buttons) == 0) {
BMenuItem* selected;
if ((selected = fPopUpMenu->Go(ConvertToScreen(point))) != NULL)
MessageReceived(selected->Message());
return;
}
// calculate grid sizes
float sizeDisp = fHeight * K_DISPLAY_YPROP;
float sizeCol = fWidth / (float)fColums;
float sizeRow = (fHeight - sizeDisp) / (float)fRows;
// 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);
}
} else {
// click on keypad
// calculate location within grid
int gridCol = (int)(point.x / sizeCol);
int gridRow = (int)((point.y - sizeDisp) / sizeRow);
// check limits
if ((gridCol >= 0) && (gridCol < fColums) &&
(gridRow >= 0) && (gridRow < fRows)) {
// process key press
_PressKey(gridRow * fColums + gridCol);
}
}
}
void
CalcView::KeyDown(const char *bytes, int32 numBytes)
{
// if single byte character...
if (numBytes == 1) {
//printf("Key pressed: %c\n", bytes[0]);
switch (bytes[0]) {
case B_ENTER:
// translate to evaluate key
_PressKey("=");
break;
case B_LEFT_ARROW:
case B_BACKSPACE:
// translate to backspace key
_PressKey("BS");
break;
case B_SPACE:
case B_ESCAPE:
case 'c': // hack!
// translate to clear key
_PressKey("C");
break;
// bracket translation
case '[':
case '{':
_PressKey("(");
break;
case ']':
case '}':
_PressKey(")");
break;
default: {
// scan the keymap array for match
int keys = fRows * fColums;
for (int i=0; i<keys; i++) {
if (fKeypad[i].keymap[0] == bytes[0]) {
_PressKey(i);
return;
}
}
break;
}
}
}
}
void
CalcView::MakeFocus(bool focused)
{
if (focused) {
// set num lock
if (fOptions->mAutoNumLock) {
set_keyboard_locks(B_NUM_LOCK |
(modifiers() & (B_CAPS_LOCK | B_SCROLL_LOCK)));
}
}
// pass on request to parent
BView::MakeFocus(focused);
}
void
CalcView::FrameResized(float width, float height)
{
fWidth = width;
fHeight = height;
}
void
CalcView::AboutRequested()
{
/*
BRect frame(100.0, 100.0, 300.0, 280.0);
new RAboutBox(frame, "DeskCalc v1.3.0", "code: timmy\nqa: rosalie\n\n"
B_UTF8_COPYRIGHT"1997 R3 Software Ltd.\nAll Rights Reserved.",
RAboutBox::R_SHOW_ON_OPEN);
*/
}
status_t
CalcView::Archive(BMessage* archive, bool deep) const
{
// passed on request to parent
status_t ret = BView::Archive(archive, deep);
// save app signature for replicant add-on loading
if (ret == B_OK)
ret = archive->AddString("add_on", kAppSig);
// save all the options
if (ret == B_OK)
ret = SaveSettings(archive);
// add class info last
if (ret == B_OK)
ret = archive->AddString("class", "CalcView");
return ret;
}
void
CalcView::Cut()
{
Copy(); // copy data to clipboard
fExpression.SetTo(""); // remove data
_InvalidateExpression();
}
void
CalcView::Copy()
{
// access system clipboard
if (be_clipboard->Lock()) {
be_clipboard->Clear();
BMessage *clipper = be_clipboard->Data();
clipper->what = B_MIME_DATA;
// TODO: should check return for errors!
clipper->AddData("text/plain",
B_MIME_TYPE,
fExpression.String(),
fExpression.Length());
//clipper->PrintToStream();
be_clipboard->Commit();
be_clipboard->Unlock();
}
}
void
CalcView::Paste(BMessage *message)
{
// handle color drops first
// read incoming color
const rgb_color* dropColor = NULL;
ssize_t dataSize;
if (message->FindData("RGBColor",
B_RGB_COLOR_TYPE,
(const void**)&dropColor,
&dataSize) == B_OK
&& dataSize == sizeof(rgb_color)) {
// calculate view relative drop point
BPoint dropPoint = ConvertFromScreen(message->DropPoint());
// calculate current keypad area
float sizeDisp = fHeight * K_DISPLAY_YPROP;
BRect keypadRect(0.0, sizeDisp, fWidth, fHeight);
// check location of color drop
if (keypadRect.Contains(dropPoint) && dropColor) {
fBaseColor = *dropColor;
_Colorize();
// redraw keypad
Invalidate(keypadRect);
}
} else {
// look for text/plain MIME data
const char* text;
ssize_t numBytes;
if (message->FindData("text/plain",
B_MIME_TYPE,
(const void**)&text,
&numBytes) == B_OK) {
fExpression.Append(text, numBytes);
_InvalidateExpression();
}
}
}
status_t
CalcView::LoadSettings(BMessage* archive)
{
if (!archive)
return B_BAD_VALUE;
// record calculator description
const char* calcDesc;
if (archive->FindString("calcDesc", &calcDesc) < B_OK)
calcDesc = kDefaultKeypadDescription;
// save calculator description for reference
free(fKeypadDescription);
fKeypadDescription = strdup(calcDesc);
// read grid dimensions
if (archive->FindInt16("cols", &fColums) < B_OK)
fColums = 5;
if (archive->FindInt16("rows", &fRows) < B_OK)
fRows = 4;
// read color scheme
const rgb_color* color;
ssize_t size;
if (archive->FindData("rgbBaseColor", B_RGB_COLOR_TYPE,
(const void**)&color, &size) < B_OK
|| size != sizeof(rgb_color)) {
fBaseColor = (rgb_color){ 128, 128, 128, 255 };
puts("Missing rgbBaseColor from CalcView archive!\n");
} else {
fBaseColor = *color;
}
if (archive->FindData("rgbDisplay", B_RGB_COLOR_TYPE,
(const void**)&color, &size) < B_OK
|| size != sizeof(rgb_color)) {
fExpressionBGColor = (rgb_color){ 0, 0, 0, 255 };
puts("Missing rgbBaseColor from CalcView archive!\n");
} else {
fExpressionBGColor = *color;
}
// 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");
}
// load display text
const char* display;
if (archive->FindString("displayText", &display) < B_OK) {
puts("Missing display text from CalcView archive.\n");
} else {
// init expression text
fExpression = display;
}
// parse calculator description
_ParseCalcDesc(fKeypadDescription);
// colorize based on base color.
_Colorize();
return B_OK;
}
status_t
CalcView::SaveSettings(BMessage* archive) const
{
status_t ret = archive ? B_OK : B_BAD_VALUE;
// record grid dimensions
if (ret == B_OK)
ret = archive->AddInt16("cols", fColums);
if (ret == B_OK)
ret = archive->AddInt16("rows", fRows);
// record color scheme
if (ret == B_OK)
ret = archive->AddData("rgbBaseColor", B_RGB_COLOR_TYPE,
&fBaseColor, sizeof(rgb_color));
if (ret == B_OK)
ret = archive->AddData("rgbDisplay", B_RGB_COLOR_TYPE,
&fExpressionBGColor, sizeof(rgb_color));
// record current options
if (ret == B_OK)
ret = archive->AddData("options", B_RAW_TYPE,
fOptions, sizeof(CalcOptions));
// record display text
if (ret == B_OK)
ret = archive->AddString("displayText", fExpression.String());
// record calculator description
if (ret == B_OK)
ret = archive->AddString("calcDesc", fKeypadDescription);
return ret;
}
// #pragma mark -
void
CalcView::_ParseCalcDesc(const char* keypadDescription)
{
// TODO: should calculate dimensions from desc here!
fKeypad = new CalcKey[fRows * fColums];
// scan through calculator description and assemble keypad
bool scanFlag = true;
CalcKey *key = fKeypad;
const char *p = keypadDescription;
while (scanFlag) {
// 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) {
strcpy(key->keymap, key->label);
} else {
*key->keymap = '\0';
} // end if
// advance
while (isspace(*p))
++p;
key++;
// check desc termination
if (*p == '\0')
scanFlag = false;
}
}
void
CalcView::_PressKey(int key)
{
assert(key < (fRows * fColums));
assert(key >= 0);
// 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
}
} else if (strcmp(fKeypad[key].label, "C") == 0) {
// C means clear
fExpression.SetTo("");
} else {
// append to display text
fExpression.Append(fKeypad[key].code);
// check for evaluation order
if (fKeypad[key].code[0] == '\n') {
_Evaluate();
} else {
// audio feedback
if (fOptions->mAudioFeedback) {
BEntry zimp("key.AIFF");
entry_ref zimp_ref;
zimp.GetRef(&zimp_ref);
play_sound(&zimp_ref, true, false, true);
}
}
}
// redraw display
_InvalidateExpression();
}
void
CalcView::_PressKey(char *label)
{
int keys = fRows * fColums;
for (int i = 0; i < keys; i++) {
if (strcmp(fKeypad[i].label, label) == 0) {
_PressKey(i);
return;
}
}
}
void
CalcView::_Colorize()
{
// calculate light and dark color from base color
fLightColor.red = (uint8)(fBaseColor.red * 1.25);
fLightColor.green = (uint8)(fBaseColor.green * 1.25);
fLightColor.blue = (uint8)(fBaseColor.blue * 1.25);
fLightColor.alpha = 255;
fDarkColor.red = (uint8)(fBaseColor.red * 0.75);
fDarkColor.green = (uint8)(fBaseColor.green * 0.75);
fDarkColor.blue = (uint8)(fBaseColor.blue * 0.75);
fDarkColor.alpha = 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->mAudioFeedback) {
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();
}
void
CalcView::_CreatePopUpMenu()
{
// construct items
fAboutItem = new BMenuItem("About Calculator...",
new BMessage(B_ABOUT_REQUESTED));
fOptionsItem = new BMenuItem("Options...",
new BMessage(K_OPTIONS_REQUESTED));
// construct menu
fPopUpMenu = new BPopUpMenu("pop-up", false, false);
fPopUpMenu->AddItem(fAboutItem);
fPopUpMenu->AddItem(fOptionsItem);
}
void
CalcView::_InvalidateExpression()
{
float sizeDisp = fHeight * K_DISPLAY_YPROP;
BRect displayRect(0.0, 0.0, fWidth, sizeDisp);
Invalidate(displayRect);
}

View File

@ -0,0 +1,109 @@
/*
* Copyright 2006 Haiku, Inc. All Rights Reserved.
* Copyright 1997, 1998 R3 Software Ltd. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Timothy Wayper <timmy@wunderbear.com>
* Stephan Aßmus <superstippi@gmx.de>
*/
#ifndef _CALC_VIEW_H
#define _CALC_VIEW_H
#include <View.h>
#include <String.h>
class BString;
class BMenuItem;
class CalcOptions;
class CalcOptionsWindow;
_EXPORT
class CalcView : public BView {
public:
static CalcView* Instantiate(BMessage* archive);
CalcView(BRect frame,
rgb_color rgbBaseColor);
CalcView(BMessage* archive);
virtual ~CalcView();
virtual void MessageReceived(BMessage* message);
virtual void Draw(BRect updateRect);
virtual void MouseDown(BPoint point);
virtual void KeyDown(const char* bytes, int32 numBytes);
virtual void MakeFocus(bool focused = true);
virtual void FrameResized(float width, float height);
// Present about box for view (replicant).
virtual void AboutRequested();
// Archive this view.
virtual status_t Archive(BMessage* archive, bool deep) const;
// Cut contents of view to system clipboard.
void Cut();
// Copy contents of view to system clipboard.
void Copy();
// Paste contents of system clipboard to view.
void Paste(BMessage *message);
// Load/Save current settings
status_t LoadSettings(BMessage* archive);
status_t SaveSettings(BMessage* archive) const;
private:
void _ParseCalcDesc(const char* keypadDescription);
void _PressKey(int key);
void _PressKey(char* label);
void _Colorize();
void _Evaluate();
void _CreatePopUpMenu();
void _InvalidateExpression();
// grid dimensions
int16 fColums;
int16 fRows;
// color scheme
rgb_color fBaseColor;
rgb_color fLightColor;
rgb_color fDarkColor;
rgb_color fExpressionBGColor;
// view dimensions
float fWidth;
float fHeight;
// keypad grid
struct CalcKey;
char* fKeypadDescription;
CalcKey* fKeypad;
// display text
BString fExpression;
// pop-up context menu.
BMenuItem* fAboutItem;
BMenuItem* fOptionsItem;
BPopUpMenu* fPopUpMenu;
// calculator options.
CalcOptions* fOptions;
CalcOptionsWindow* fOptionsWindow;
};
#endif // _CALC_VIEW_H

View File

@ -0,0 +1,125 @@
/*
* Copyright 2006 Haiku, Inc. All Rights Reserved.
* Copyright 1997, 1998 R3 Software Ltd. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Timothy Wayper <timmy@wunderbear.com>
* Stephan Aßmus <superstippi@gmx.de>
*/
#include "CalcWindow.h"
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <Application.h>
#include <Dragger.h>
#include <Screen.h>
#include "CalcView.h"
static const char* kWindowTitle = "Desk Calculator";
CalcWindow::CalcWindow(BRect frame)
: BWindow(frame, kWindowTitle, B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS)
{
// create calculator view with calculator description and
// desktop background color
BScreen screen(this);
rgb_color baseColor = screen.DesktopColor();
frame.OffsetTo(B_ORIGIN);
fCalcView = new CalcView(frame, baseColor);
// create replicant dragger
frame.top = frame.bottom - 7.0f;
frame.left = frame.right - 7.0f;
BDragger* dragger = new BDragger(frame, fCalcView,
B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
// attach views
AddChild(fCalcView);
fCalcView->AddChild(dragger);
}
CalcWindow::~CalcWindow()
{
}
void
CalcWindow::Show()
{
// NOTE: done here because the CalcView
// turns on numlock if the options say so...
// so we want to call MakeFocus() after
// the options have been read for sure...
fCalcView->MakeFocus();
BWindow::Show();
}
bool
CalcWindow::QuitRequested()
{
be_app->PostMessage(B_QUIT_REQUESTED);
Hide();
// NOTE: don't quit, since the app needs us
// for saving settings yet...
return false;
}
bool
CalcWindow::LoadSettings(BMessage* archive)
{
status_t ret = fCalcView->LoadSettings(archive);
if (ret < B_OK)
return false;
BRect frame;
ret = archive->FindRect("window frame", &frame);
if (ret < B_OK)
return false;
SetFrame(frame);
return true;
}
status_t
CalcWindow::SaveSettings(BMessage* archive) const
{
status_t ret = archive->AddRect("window frame", Frame());
if (ret < B_OK)
return ret;
return fCalcView->SaveSettings(archive);
}
void
CalcWindow::SetFrame(BRect frame, bool forceCenter)
{
// make sure window frame is on screen (center, if not)
BScreen screen(this);
BRect screenFrame = screen.Frame();
if (forceCenter || !screenFrame.Contains(frame)) {
float left = (screenFrame.Width() - frame.Width()) / 2.0;
float top = (screenFrame.Height() - frame.Height()) / 2.0;
left += screenFrame.left;
top += screenFrame.top;
frame.OffsetTo(left, top);
}
MoveTo(frame.left, frame.top);
ResizeTo(frame.Width(), frame.Height());
}

View File

@ -0,0 +1,37 @@
/*
* Copyright 2006 Haiku, Inc. All Rights Reserved.
* Copyright 1997, 1998 R3 Software Ltd. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Timothy Wayper <timmy@wunderbear.com>
* Stephan Aßmus <superstippi@gmx.de>
*/
#ifndef _CALC_WINDOW_H
#define _CALC_WINDOW_H
#include <Window.h>
class CalcView;
class CalcWindow : public BWindow {
public:
CalcWindow(BRect frame);
virtual ~CalcWindow();
virtual void Show();
virtual bool QuitRequested();
bool LoadSettings(BMessage* archive);
status_t SaveSettings(BMessage* archive) const;
void SetFrame(BRect frame,
bool forceCenter = false);
private:
CalcView* fCalcView;
};
#endif // _CALC_WINDOW_H

View File

@ -0,0 +1,22 @@
/*
* Copyright 2006 Haiku, Inc. All Rights Reserved.
* Copyright 1997, 1998 R3 Software Ltd. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Timothy Wayper <timmy@wunderbear.com>
* Stephan Aßmus <superstippi@gmx.de>
*/
#include "CalcApplication.h"
int
main(int argc, char* argv[])
{
CalcApplication* app = new CalcApplication();
app->Run();
delete app;
return 0;
}

View File

@ -0,0 +1,281 @@
/*
* Copyright 2006 Haiku, Inc. All Rights Reserved.
* Copyright 2004 Daniel Wallner. All Rights Reserved.
* Copyright 1997, 1998 R3 Software Ltd. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Daniel Wallner <daniel.wallner@bredband.net>
* Timothy Wayper <timmy@wunderbear.com>
* Stephan Aßmus <superstippi@gmx.de>
*/
#include <iostream.h>
#include <fstream.h>
#include <complex>
#include <vector>
#include <math.h>
#include <string>
//#include <libxlds/xlds.h>
//#include <libdsph/getopt.h>
//#include <libdsph/const.h>
#include "CalcApplication.h"
using namespace std;
//using namespace xlds;
void Usage()
{
cerr << "Expression calculator" << endl << endl;
cerr << " usage: expcalc [expression] ... [options and arguments]" << endl << endl;
cerr << " -h print this message" << endl;
cerr << " -e even thousands exponent output" << endl;
cerr << " -p SI prefix output" << endl;
cerr << " -n newline after output" << endl << endl;
cerr << " If no arguments are given, expcalc enters interactive mode." << endl;
cerr << " You can combine short flags, so `-e -n' means the same as -en or -ne." << endl;
}
int GetString(string &instring)
{
instring.assign("");
char cchar;
cchar = getc(stdin);
while (cchar != EOF && cchar != 10)
{
instring.append(1, cchar);
cchar = getc(stdin);
}
return 0;
}
int main(int argc, char *argv[])
{
if (argc == 1) {
CalcApplication* app = new CalcApplication();
app->Run();
delete app;
return 0;
}
try
{
char *expression = NULL;
char outputMode = 0;
bool newline = false;
while (doptind < argc)
{
if (argv[doptind][0] != '-' || strlen(argv[doptind]) <= 1)
{
// File argument
if (expression)
throw "Multiple expressions not supported";
expression = argv[doptind];
doptind++;
}
else
{
// Option
int opt = dgetopt(argc, argv, ":hepn");
if (opt != -1)
{
switch (opt)
{
case 'h':
Usage();
return 1;
break;
case 'e':
outputMode = 1;
break;
case 'p':
outputMode = 2;
break;
case 'n':
newline = true;
break;
case ':': // No argument
cerr << "Option -" << (char)doptopt << " requires an argument" << endl;
throw "";
case '?':
default:
cerr << "Unknown option -" << (char)doptopt << endl;
throw "";
}
}
}
}
string instring;
string laststring;
string stored;
Expression exp;
if (expression)
{
double temp = exp.Eval(expression, expression + strlen(expression));
if (!exp.Error())
{
cout << exp.dtostr(temp, 14, outputMode).c_str();
if (newline)
cout << endl;
}
else
{
char *i;
cout << expression << endl;
for (i = expression; i < exp.Error(); i++)
cout << " ";
cout << "^\nError in input\n\n";
}
}
else
{
cout << "Expression Calculator\n";
cout << "Copyright (c) Daniel Wallner 2004.\n";
cout << "Type exit to end program or ? for help.\n\n";
cout << "ec> ";
if (GetString(instring))
return 0;
bool rec = false;
while (strcmp(instring.c_str(), "exit"))
{
if (!strcmp(instring.c_str(), "?"))
{
cout << "\nCommands l : repeat last calculation (used with ans)\n";
cout << " sto : store last expression\n";
cout << " rec : recall stored expression\n";
cout << " d : set trigonometric functions to degrees\n";
cout << " r : set trigonometric functions to radians (default)\n";
cout << " e : toggle exponent output mode\n";
cout << " p : set prefix output mode\n";
cout << " exit : exit program\n";
cout << "\nFunctions sin( : sinus\n";
cout << " cos( : cosinus\n";
cout << " tan( : tangens\n";
cout << " asin( : arcsin\n";
cout << " acos( : arccos\n";
cout << " atan( : arctan\n";
cout << " lg( : logarithm with base 10\n";
cout << " ln( : logarithm with base e\n";
cout << " sqrt( : sqare root\n";
cout << " ans : last answer\n";
cout << " ^,*,+,-,/ : as usual :-)\n";
cout << "\nConstants e : the constant e\n";
cout << " pi : the constant pi\n\n";
rec=1;
instring = laststring;
}
if (!strcmp(instring.c_str(), "l"))
{
instring = laststring;
}
if (!strcmp(instring.c_str(), "sto"))
{
stored = laststring;
cout << "\nLast expression stored!\n\n";
rec = 1;
instring = laststring;
}
if (!strcmp(instring.c_str(), "rec"))
{
instring = stored;
}
if (!strcmp(instring.c_str(), "d"))
{
exp.SetAglf(M_PI / 180.);
rec = 1;
cout << "\nDegree mode!\n\n";
instring = laststring;
}
if (!strcmp(instring.c_str(), "r"))
{
exp.SetAglf(1.);
rec = 1;
cout << "\nRadian mode!\n\n";
instring = laststring;
}
if (!strcmp(instring.c_str(), "e"))
{
outputMode = (outputMode + 1) % 2;
cout << "\nExponent output mode" << outputMode << "!\n\n";
instring = laststring;
}
if (!strcmp(instring.c_str(), "p"))
{
outputMode = 2;
cout << "\nPrefix output mode!\n\n";
instring = laststring;
}
if (!instring.size())
rec = 1;
if (rec == 0)
{
double temp = exp.Eval(instring.c_str(), instring.c_str() + instring.size());
if (!exp.Error())
{
cout << "\n" << instring << " = ";
cout << exp.dtostr(temp, 14, outputMode).c_str();
cout << "\n\n";
exp.SetConstant("ans", temp);
}
else
{
const char *i;
for (i = instring.c_str(); i < exp.Error(); i++)
cout << " ";
cout << " ";
cout << "^\nError in input\n\n";
}
}
cout << "ec> ";
laststring = instring;
if (GetString(instring))
return 0;
rec = 0;
}
}
}
catch (const char * str)
{
cerr << str << endl;
return 1;
}
return 0;
}

View File

@ -0,0 +1,8 @@
/*
** /boot/home/projects/develop/ThirdParty/Haiku/src/apps/deskcalc/DeskCalc.h
**
** Automatically generated by BResourceParser on
** Tuesday, June 06, 2006 at 17:38:14.
**
*/

View File

@ -0,0 +1,74 @@
resource(1, "BEOS:APP_SIG") #'MIMS' "application/x-vnd.Haiku-DeskCalc";
resource app_version
{
major = 2,
middle = 1,
minor = 0,
/* 0 = development 1 = alpha 2 = beta
3 = gamma 4 = golden master 5 = final */
variety = 1,
internal = 1,
short_info = "DeskCalc",
long_info = "DeskCalc 2.1.0 ©2006 Haiku"
};
resource(101, "BEOS:L:STD_ICON") #'ICON' array {
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0013130000FFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFF0013060613130000FFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFF0013060808080613130000FFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFF0013080808083408060613130000FFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFF0013080808083408083408060613130000FFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFF00140F1313080808083408343408060613130000FFFF"
$"FFFFFFFFFFFFFFFFFF001413140F0F131308080808340808340808130000FFFF"
$"FFFFFFFFFFFFFFFF00130F13130F140F0F13130808083434080813000800FFFF"
$"FFFFFFFFFFFFFF001414140F0F1413140F0F0F13130808080813000808000808"
$"FFFFFFFFFFFF000F1313130F140F0F0F1313130F0F1313081300080800080808"
$"FFFFFFFFFF0014140F0F0F1413130F0F0F130F14140F0F1300080800080808FF"
$"FFFFFFFF00141313140F0F0F130F1413130F0F1313131300080800080808FFFF"
$"FFFFFF00140F13130F1413130F0F13130F14140F0F1300080800080808FFFFFF"
$"FFFF001413140F0F1413130F13130F0F131413131300080800080808FFFFFFFF"
$"FF00001313130F140F0F0F1313130F140F0F131300080800080808FFFFFFFFFF"
$"FF000E04040F1413130F0F0F130F141314130F00080800080808FFFFFFFFFFFF"
$"FF000E0E0E0404130F1313130F0F1313131300080800080808FFFFFFFFFFFFFF"
$"FFFF000E0E0E0E040413130F14140F0F1300080800080808FFFFFFFFFFFFFFFF"
$"FFFFFF00000E0E0E0E0404141313131300080800080808FFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFF00000E0E0E0E0404131300080800080808FFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFF00000E0E0E0E0400080800080808FFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFF00000E0E0E000800080808FFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFF00000E0000080808FFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFF0000080808FFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
};
resource(101, "BEOS:M:STD_ICON") #'MICN' array {
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFF0000FFFFFFFFFFFF"
$"FFFFFFFFFFFFFF0008080000FFFFFFFF"
$"FFFFFFFFFFFF0008080834060000FFFF"
$"FFFFFFFFFF00140F13080808340800FF"
$"FFFFFFFF00140F130F0F130808000808"
$"FFFFFF000F0F130F0F0F140F00080808"
$"FFFF00130F130F130F140F00080808FF"
$"FF00130F0F0F130F0F1300080808FFFF"
$"FF000E040F130F131300080808FFFFFF"
$"FFFF000E0E04131300080808FFFFFFFF"
$"FFFFFF00000E0E00080808FFFFFFFFFF"
$"FFFFFFFFFF0000000808FFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
};
resource(1, "BEOS:APP_FLAGS") (#'APPF') $"01000000";

21
src/apps/deskcalc/Jamfile Normal file
View File

@ -0,0 +1,21 @@
SubDir HAIKU_TOP src apps deskcalc ;
SetSubDirSupportedPlatformsBeOSCompatible ;
AddSubDirSupportedPlatforms libbe_test ;
Application DeskCalc :
CalcApplication.cpp
CalcOptionsWindow.cpp
CalcView.cpp
CalcWindow.cpp
DeskCalc.cpp
Parser.cpp
: be $(TARGET_LIBSTDC++) media
: DeskCalc.rdef
;
if $(TARGET_PLATFORM) = libbe_test {
HaikuInstall install-test-apps : $(HAIKU_APP_TEST_DIR) : DeskCalc
: tests!apps ;
}

View File

@ -0,0 +1,952 @@
/*
* Copyright 2006 Haiku, Inc. All Rights Reserved.
* Copyright 2004 Daniel Wallner. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Daniel Wallner <daniel.wallner@bredband.net>
*/
#include "Parser.h"
#include <iostream.h>
#include <stdio.h>
#include <math.h>
#include <stdarg.h>
#define NOLLF 5e-16
using namespace std;
//LineParser::LineParser(istream *stream):
// m_stream(stream),
// m_currentLine(0)
//{
//}
//
//void LineParser::AddSeparator(const char c)
//{
// m_separators.push_back(c);
//}
//
//size_t LineParser::SetToNext(bool toUpperCase)
//{
// m_line.erase(m_line.begin(), m_line.end());
// m_unparsed.assign("");
//
// // Skip newlines
// while (m_stream->peek() == 0xA || m_stream->peek() == 0xD)
// m_stream->get();
//
// while (!m_stream->eof() && !m_stream->fail() && m_stream->peek() != 0xA && m_stream->peek() != 0xD)
// {
// string param;
//
// // Skip whitespaces
// while (m_stream->peek() == ' ' || m_stream->peek() == '\t')
// m_unparsed.append(1, char(m_stream->get()));
//// m_separators.push_back(c); add check for separators !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// if (m_stream->peek() == '"')
// {
// // Skip first "
// m_unparsed.append(1, char(m_stream->get()));
//
// int c;
// // Read until "
// while (!m_stream->fail() && m_stream->peek() != 0xA && m_stream->peek() != 0xD &&
// (c = m_stream->get()) != '"' && !m_stream->eof())
// {
// m_unparsed.append(1, char(c));
// if (toUpperCase)
// param.append(1, char(toupper(c)));
// else
// param.append(1, char(c));
// }
// if (c == '"')
// m_unparsed.append(1, char(c));
// }
// else
// {
// int c;
// // Read until whitespace
//// m_separators.push_back(c); add check for separators !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// while (!m_stream->fail() && m_stream->peek() != 0xA && m_stream->peek() != 0xD &&
// (c = m_stream->get()) != ' ' && c != '\t' && !m_stream->eof())
// {
// m_unparsed.append(1, char(c));
// if (toUpperCase)
// param.append(1, char(toupper(c)));
// else
// param.append(1, char(c));
// }
// if (c == ' ')
// m_unparsed.append(1, char(c));
// }
//
// // Store parameter
// if (param.size())
// m_line.push_back(param);
// }
//
// // Skip newlines
// while (m_stream->peek() == 0xA || m_stream->peek() == 0xD)
// m_stream->get();
//
// return m_line.size();
//}
//
//void LineParser::WriteCompressed(string *s) const
//{
// size_t i;
// for (i = 0; i < m_line.size(); i++)
// {
// if (i != 0)
// {
// *s += " ";
// }
// *s += m_line[i];
// }
//}
//
//void LineParser::WriteCompressed(ostream *stream) const
//{
// size_t i;
// for (i = 0; i < m_line.size(); i++)
// {
// if (i != 0)
// {
// *stream << " ";
// }
// *stream << m_line[i];
// }
// *stream << endl;
//}
//
//size_t LineParser::ParsedLines() const
//{
// return m_currentLine;
//}
//
//const char *LineParser::Param(const size_t param) const
//{
// return m_line[param].c_str();
//}
//
//const char *LineParser::Line() const
//{
// return m_unparsed.c_str();
//}
// Expression
double Expression::valtod(const char *exp, const char **end)
{
// http://en.wikipedia.org/wiki/SI_prefix
char *endptr;
double temp = strtod(exp, &endptr);
if (endptr == exp || !*endptr)
{
if (end) *end = endptr;
return temp;
}
if (end) *end = endptr + 1;
switch(*endptr)
{
/* case 'Y': // yotta
return temp * 1.E24;
break;
case 'Z': // zetta
return temp * 1.E21;
break;
case 'E': // exa, incompatible with exponent!
return temp * 1.E18;
break;*/
case 'P': // peta
return temp * 1.E15;
break;
case 'T': // tera
return temp * 1.E12;
break;
case 'G': // giga
return temp * 1.E9;
break;
case 'M': // mega
return temp * 1.E6;
break;
case 'k': // kilo
return temp * 1.E3;
break;
case 'h': // hecto
return temp * 1.E2;
break;
case 'd':
if (endptr[1] == 'a')
{
if (end) *end = endptr + 2;
return temp * 1.E1; // deca
}
else
return temp * 1.E-1; // deci
break;
case 'c': // centi
return temp * 1.E-2;
break;
case 'm': // milli
return temp * 1.E-3;
break;
case 'u': // micro
return temp * 1.E-6;
break;
case 'n': // nano
return temp * 1.E-9;
break;
case 'p': // pico
return temp * 1.E-12;
break;
case 'f': // femto
return temp * 1.E-15;
break;
case 'a': // atto
return temp * 1.E-18;
break;
case 'z': // zepto
return temp * 1.E-21;
break;
case 'y': // yocto
return temp * 1.E-24;
break;
}
if (end) *end = endptr;
return temp;
}
double Expression::exptod(const char *str, const char **end)
{
Expression exp;
const char *evalEnd = str + strlen(str);
double temp = exp.Eval(str, evalEnd);
const char *err = exp.Error();
if (end) *end = err ? err : evalEnd;
return temp;
}
string Expression::dtostr(const double value, const unsigned int precision, const char mode)
{
if (value == 0.0)
return "0";
string str;
char prefix[2];
prefix[0] = 0;
prefix[1] = 0;
if (mode == 1) // exp3
{
double exp = floor(log10(fabs(value)) / 3.) * 3;
string format;
strprintf(format, "%%.%dGE%%ld", precision);
strprintf(str, format.c_str(), value / pow(10., exp), exp);
}
else if (mode == 2) // prefix
{
double exp = floor(log10(fabs(value)) / 3.) * 3;
string format;
strprintf(format, "%%.%dG", precision);
strprintf(str, format.c_str(), value / pow(10., exp));
switch(int(exp))
{
case 24: // yotta
prefix[0] = 'Y';
break;
case 21: // zetta
prefix[0] = 'Z';
break;
case 18: // exa
prefix[0] = 'E';
break;
case 15: // peta
prefix[0] = 'P';
break;
case 12: // tera
prefix[0] = 'T';
break;
case 9: // giga
prefix[0] = 'G';
break;
case 6: // mega
prefix[0] = 'M';
break;
case 3: // kilo
prefix[0] = 'k';
break;
case -3: // milli
prefix[0] = 'm';
break;
case -6: // micro
prefix[0] = 'u';
break;
case -9: // nano
prefix[0] = 'n';
break;
case -12: // pico
prefix[0] = 'p';
break;
case -15: // femto
prefix[0] = 'f';
break;
case -18: // atto
prefix[0] = 'a';
break;
case -21: // zepto
prefix[0] = 'z';
break;
case -24: // yocto
prefix[0] = 'y';
break;
default:
if (exp)
{
strprintf(format, "%%.%dGE%%ld", precision);
strprintf(str, format.c_str(), value / pow(10., exp), exp);
}
else
{
strprintf(format, "%%.%dG", precision);
strprintf(str, format.c_str(), value);
}
break;
}
}
else // exp
{
string format;
strprintf(format, "%%.%dG", precision);
strprintf(str, format.c_str(), value);
}
return string(str) + prefix;
}
template<class T>
class MemBlock
{
public:
MemBlock()
: m_bSize(0),
m_buf(0){}
MemBlock(const MemBlock<T>& src)
: m_bSize(0),
m_buf(0)
{
SetSize(src.m_bSize);
memcpy(m_buf, src.m_buf, src.m_bSize);
}
MemBlock<T>& operator=(const MemBlock<T>& src)
{
if (this != &src)
{
SetSize(src.m_bSize);
memcpy(m_buf, src.m_buf, src.m_bSize);
}
return (*this);
}
~MemBlock ()
{
if (m_buf)
{
free(m_buf);
}
}
void SetSize(const size_t size)
{
size_t oldsize = Size();
if (oldsize != size)
{
if (!m_buf && size)
{
m_buf = malloc(size);
if (!m_buf)
throw "Out of memory";
}
if (m_buf && size)
{
void *newBuf = realloc(m_buf, size);
if (newBuf)
m_buf = newBuf;
else
throw "Out of memory";
}
if (m_buf && !size)
{
free(m_buf);
m_buf = 0;
}
m_bSize = size;
}
}
void * Buffer() const { return m_buf; }
T * Access() const { return (T *)m_buf; }
T & operator[](size_t i) const
{
return Access()[i];
}
size_t Size() const { return m_bSize; }
protected:
size_t m_bSize;
void *m_buf;
};
int Expression::strprintf(string &str, const char * format, ...)
{
va_list argptr;
char strfix[128];
va_start(argptr, format);
int ret = vsnprintf(strfix, 128, format, argptr);
va_end(argptr);
if (ret == -1)
{
MemBlock<char> strbuf;
strbuf.SetSize(128);
while (ret == -1)
{
strbuf.SetSize(strbuf.Size() * 2);
va_start(argptr, format);
ret = vsnprintf(strbuf.Access(), strbuf.Size(), format, argptr);
va_end(argptr);
}
str.assign(strbuf.Access());
}
else if (ret >= 128)
{
MemBlock<char> strbuf;
strbuf.SetSize(ret + 1);
va_start(argptr, format);
ret = vsnprintf(strbuf.Access(), ret + 1, format, argptr);
va_end(argptr);
str.assign(strbuf.Access());
}
else
{
str.assign(strfix);
}
return ret;
}
Expression::Expression():
m_aglf(1.),
m_errorPtr(NULL),
m_trig(false)
{
m_functionNames.push_back("sin("); // 0
m_functionTypes.push_back(1);
m_functionNames.push_back("asin("); // 1
m_functionTypes.push_back(2);
m_functionNames.push_back("cos("); // 2
m_functionTypes.push_back(1);
m_functionNames.push_back("acos("); // 3
m_functionTypes.push_back(2);
m_functionNames.push_back("tan("); // 4
m_functionTypes.push_back(1);
m_functionNames.push_back("atan("); // 5
m_functionTypes.push_back(2);
m_functionNames.push_back("ln("); // 6
m_functionTypes.push_back(0);
m_functionNames.push_back("lg("); // 7
m_functionTypes.push_back(0);
m_functionNames.push_back("sqrt("); // 8
m_functionTypes.push_back(0);
m_functionNames.push_back("("); // 9
m_functionTypes.push_back(0);
SetConstant("e", M_E);
SetConstant("pi", M_PI);
}
double Expression::func(const double x, const size_t number) const
{
switch (number)
{
case 0:
return sin(x);
case 1:
return asin(x);
case 2:
return cos(x);
case 3:
return acos(x);
case 4:
return tan(x);
case 5:
return atan(x);
case 6:
return log(x);
case 7:
return log10(x);
case 8:
return sqrt(x);
default:
return x;
}
}
void Expression::SetAglf(const double value)
{
m_aglf = value;
}
bool Expression::SetConstant(const char *name, const double value)
{
size_t i;
for (i = 0; name[i]; i++)
{
if (!isalnum(name[i]))
{
throw "Illegal character in constant name";
}
}
for (i = 0; i < m_constantNames.size(); i++)
{
if (!strcmp(name, m_constantNames[i].c_str()))
{
m_constantValues[i] = value;
return true;
}
}
m_constantNames.push_back(name);
m_constantValues.push_back(value);
return false;
}
double Expression::Eval(const char *exp)
{
const char *evalEnd = exp + strlen(exp);
return Eval(exp, evalEnd);
}
double Expression::Eval(const char *begin, const char *end, const bool allowWhiteSpaces)
{
const char *curptr = begin;
int state = 1;
double operand;
double sum = 0.;
double prod = 0.0;
double power = 0.0;
if (begin[0] == 0)
{
m_errorPtr = begin;
return 0.;
}
if (m_errorPtr)
{
return 0.;
}
for (;;)
{
const char *operandEnd;
bool minusBeforeOperand = false;
bool numberOperand = true;
if (allowWhiteSpaces)
{
// TODO: Remove white spaces
}
if (curptr[0] == '-')
minusBeforeOperand = true;
operand = valtod(curptr, &operandEnd);
if (operandEnd == curptr)
{ // operand not a number
const char *operandStart = curptr;
double operandSign = 1.;
numberOperand = false;
if (curptr[0] == '+')
{
++operandStart;
}
else if (curptr[0] == '-')
{
++operandStart;
operandSign = -1.;
}
// Iterate through functions
size_t i;
for (i = 0; i < m_functionNames.size(); i++)
{
if (!strncmp(operandStart, m_functionNames[i].c_str(), m_functionNames[i].size()))
{
const char *functionArg = operandStart + m_functionNames[i].size();
const char *chptr = functionArg - 1;
const char *prptr = functionArg - 1;
if (m_functionTypes[i])
m_trig = true;
// Find closing paranthesis
while (prptr)
{
chptr = strchr(chptr + 1, ')');
prptr = strchr(prptr + 1, '(');
if (prptr > chptr)
break;
}
if (chptr)
{ // Closing paranthesis
if (m_functionTypes[i] == 1) // Trig
{
operand = operandSign * func(m_aglf * Eval(functionArg, chptr), i);
if (fabs(operand) < NOLLF)
operand = 0;
}
else if (m_functionTypes[i] == 2) // Inv trig
{
operand = operandSign / m_aglf * func(Eval(functionArg, chptr), i);
}
else // Normal
{
operand = operandSign * func(Eval(functionArg, chptr), i);
}
operandEnd = chptr + 1;
}
else
{ // No closing paranthesis
if (m_functionTypes[i] == 1)
{
operand = operandSign * func(m_aglf * Eval(functionArg, end), i);
if (fabs(operand) < NOLLF)
operand = 0;
}
else if (m_functionTypes[i] == 2)
{
operand = operandSign / m_aglf * func(Eval(functionArg, end), i);
}
else
{
operand = operandSign * func(Eval(functionArg, end), i);
}
operandEnd = end;
}
if (m_errorPtr)
{
return 0.;
}
break;
}
}
// Iterate through constants
if (i == m_functionNames.size()) // Only search if no function found
for (i = 0; i < m_constantNames.size(); i++)
{
if (!strncmp(operandStart, m_constantNames[i].c_str(), m_constantNames[i].size()) && !isalnum(operandStart[m_constantNames[i].size()]))
{
operandEnd = operandStart + m_constantNames[i].size();
operand = operandSign * m_constantValues[i];
break;
}
}
}
if (operandEnd > end)
{
m_errorPtr = end;
return 0.;
}
// Calculate expression in correct order
// state == 1 => term => sum + operand
// state == 2 => product => sum + prod * operand
// state == 3 => quotient => sum + prod / operand
// state == 4 => plus & power => sum + power ^ operand
// state == 5 => minus & power => sum - power ^ operand
// state == 6 => product & power => sum + prod * power ^ operand
// state == 7 => quotient & power => sum + prod / power ^ operand
if (curptr != operandEnd) // number?
{
switch (state)
{
case 1: // term
if (operandEnd == end)
{
return sum + operand;
}
switch (operandEnd[0])
{ // Check next
case '+':
case '-':
curptr = operandEnd;
sum = sum + operand;
break;
case '*':
curptr = operandEnd + 1;
prod = operand;
state = 2;
break;
case '/':
curptr = operandEnd + 1;
prod = operand;
state = 3;
break;
case '^':
curptr = operandEnd + 1;
power = operand;
if (minusBeforeOperand)
{
power = power * -1.;
state = 5;
}
else
{
state = 4;
}
break;
default:
if (numberOperand && isalpha(operandEnd[0]))
{ // Assume multiplication of function/constant without *
curptr = operandEnd;
prod = operand;
state = 2;
}
else
{
m_errorPtr = operandEnd;
return 0.;
}
}
break;
case 2: // product
if (operandEnd == end)
{
return sum + prod * operand;
}
switch (operandEnd[0])
{ // Check next
case '+':
case '-':
curptr = operandEnd;
sum = sum + prod * operand;
state = 1;
break;
case '*':
curptr = operandEnd + 1;
prod = prod * operand;
break;
case '/':
curptr = operandEnd + 1;
prod = prod * operand;
state = 3;
break;
case '^':
curptr = operandEnd + 1;
power = operand;
state = 6;
break;
default:
m_errorPtr = operandEnd;
return 0.;
}
break;
case 3: // quotient
if (operandEnd == end)
{
return sum + prod / operand;
}
switch (operandEnd[0])
{ // Check next
case '+':
case '-':
curptr = operandEnd;
sum = sum + prod / operand;
state = 1;
break;
case '*':
curptr = operandEnd + 1;
prod = prod / operand;
state = 2;
break;
case '/':
curptr = operandEnd + 1;
prod = prod / operand;
break;
case '^':
curptr = operandEnd + 1;
power = operand;
state = 7;
break;
default:
m_errorPtr = operandEnd;
return 0.;
}
break;
case 4: // plus&power
if (operandEnd == end)
{
return sum + pow(power, operand);
}
switch (operandEnd[0])
{ // Check next
case '+':
case '-':
curptr = operandEnd;
sum = sum + pow(power, operand);
state = 1;
break;
case '*':
curptr = operandEnd + 1;
prod = pow(power, operand);
state = 2;
break;
case '/':
curptr = operandEnd + 1;
prod = pow(power, operand);
state = 3;
break;
case '^':
curptr = operandEnd + 1;
power = pow(power, operand);
break;
default:
m_errorPtr = operandEnd;
return 0.;
}
break;
case 5: // minus&power
if (operandEnd == end)
{
return sum - pow(power, operand);
}
switch (operandEnd[0])
{ // Check next
case '+':
case '-':
curptr = operandEnd;
sum = sum - pow(power, operand);
state = 1;
break;
case '*':
curptr = operandEnd + 1;
prod = pow(power, operand);
state = 2;
break;
case '/':
curptr = operandEnd + 1;
prod = pow(power, operand);
state = 3;
break;
case '^':
curptr = operandEnd + 1;
power = pow(power, operand);
break;
default:
m_errorPtr = operandEnd;
return 0.;
}
break;
case 6: // product&power
if (operandEnd == end)
{
return sum + prod * pow(power, operand);
}
switch (operandEnd[0])
{ // Check next
case '+':
case '-':
curptr = operandEnd;
sum = sum + prod * pow(power, operand);
state = 1;
break;
case '*':
curptr = operandEnd + 1;
prod = prod * pow(power, operand);
state = 2;
break;
case '/':
curptr = operandEnd + 1;
prod = prod * pow(power, operand);
state = 3;
break;
case '^':
curptr = operandEnd + 1;
power = pow(power, operand);
break;
default:
m_errorPtr = operandEnd;
return 0.;
}
break;
case 7: // quotient&power
if (operandEnd == end)
{
return sum + prod / pow(power, operand);
}
switch (operandEnd[0])
{ // Check next
case '+':
case '-':
curptr = operandEnd;
sum = sum + prod / pow(power, operand);
state = 1;
break;
case '*':
curptr = operandEnd + 1;
prod = prod / pow(power, operand);
state = 2;
break;
case '/':
curptr = operandEnd + 1;
prod = prod / pow(power, operand);
state = 3;
break;
case '^':
curptr = operandEnd + 1;
power = pow(power, operand);
break;
default:
m_errorPtr = operandEnd;
return 0.;
}
break;
default:
m_errorPtr = operandEnd;
return 0.;
}
}
else
{
m_errorPtr = curptr;
return 0.;
}
}
}
const char *Expression::Error()
{
const char *retval = m_errorPtr;
m_errorPtr = NULL;
m_trig = false;
return retval;
}

View File

@ -0,0 +1,70 @@
/*
* Copyright 2006 Haiku, Inc. All Rights Reserved.
* Copyright 2004 Daniel Wallner. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Daniel Wallner <daniel.wallner@bredband.net>
*/
#ifndef PARSER_H
#define PARSER_H
#include <vector.h>
#include <string>
#include <stdio.h>
//class LineParser {
// public:
// LineParser(std::istream *stream);
//
// void AddSeparator(const char c);
//
// size_t SetToNext(bool toUpperCase = false);
// void WriteCompressed(std::string *s) const;
// void WriteCompressed(std::ostream *stream) const;
//
// size_t ParsedLines() const;
// const char *Param(const size_t param) const;
// const char *Line() const;
//
// private:
// LineParser();
//
// std::istream *m_stream;
// size_t m_currentLine;
// std::string m_unparsed;
// std::vector<std::string> m_line;
// std::vector<char> m_separators;
//};
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();
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();
private:
double m_aglf;
const char *m_errorPtr;
bool m_trig;
double func(const double x, const size_t number) const;
std::vector<std::string> m_functionNames;
std::vector<char> m_functionTypes;
std::vector<std::string> m_constantNames;
std::vector<double> m_constantValues;
};
#endif // PARSER_H