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:
parent
1bba1e12c6
commit
7cb395c433
@ -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 ;
|
||||
|
157
src/apps/deskcalc/CalcApplication.cpp
Normal file
157
src/apps/deskcalc/CalcApplication.cpp
Normal 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;
|
||||
}
|
||||
|
||||
|
37
src/apps/deskcalc/CalcApplication.h
Normal file
37
src/apps/deskcalc/CalcApplication.h
Normal 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
|
101
src/apps/deskcalc/CalcOptionsWindow.cpp
Normal file
101
src/apps/deskcalc/CalcOptionsWindow.cpp
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
42
src/apps/deskcalc/CalcOptionsWindow.h
Normal file
42
src/apps/deskcalc/CalcOptionsWindow.h
Normal 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
|
878
src/apps/deskcalc/CalcView.cpp
Normal file
878
src/apps/deskcalc/CalcView.cpp
Normal 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);
|
||||
}
|
||||
|
109
src/apps/deskcalc/CalcView.h
Normal file
109
src/apps/deskcalc/CalcView.h
Normal 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
|
125
src/apps/deskcalc/CalcWindow.cpp
Normal file
125
src/apps/deskcalc/CalcWindow.cpp
Normal 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());
|
||||
}
|
37
src/apps/deskcalc/CalcWindow.h
Normal file
37
src/apps/deskcalc/CalcWindow.h
Normal 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
|
22
src/apps/deskcalc/DeskCalc.cpp
Normal file
22
src/apps/deskcalc/DeskCalc.cpp
Normal 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;
|
||||
}
|
281
src/apps/deskcalc/DeskCalc.cpp_cli
Normal file
281
src/apps/deskcalc/DeskCalc.cpp_cli
Normal 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;
|
||||
}
|
8
src/apps/deskcalc/DeskCalc.h
Normal file
8
src/apps/deskcalc/DeskCalc.h
Normal 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.
|
||||
**
|
||||
*/
|
||||
|
74
src/apps/deskcalc/DeskCalc.rdef
Normal file
74
src/apps/deskcalc/DeskCalc.rdef
Normal 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
21
src/apps/deskcalc/Jamfile
Normal 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 ;
|
||||
}
|
952
src/apps/deskcalc/Parser.cpp
Normal file
952
src/apps/deskcalc/Parser.cpp
Normal 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;
|
||||
}
|
||||
|
70
src/apps/deskcalc/Parser.h
Normal file
70
src/apps/deskcalc/Parser.h
Normal 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
|
Loading…
Reference in New Issue
Block a user