diff --git a/src/apps/calculator/CalcEngine.cpp b/src/apps/calculator/CalcEngine.cpp new file mode 100644 index 0000000000..6ace8e0acb --- /dev/null +++ b/src/apps/calculator/CalcEngine.cpp @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2006, Haiku, Inc. + * Distributed under the terms of the MIT license. + * + * Authors: + * Peter Wagner + */ +#include "CalcEngine.h" +#include +#include + +CalcEngine::CalcEngine(int max_digits_in) +{ + max_digits = max_digits_in; + Clear(); +} + + +void CalcEngine::Clear() +{ + trig_inverse_active = false; + trig_is_radians = false; + already_have_infix = false; + number_stack_index = 0; + symbol_stack_index = 0; + keyed_value = 0.0; + text[0] = '\0'; +} + + +CalcEngine::~CalcEngine() +{ +} + + +double CalcEngine::GetValue(char *str) +{ + if (strlen(text) == 0) + { + if (str != NULL) + { + int precision = max_digits+1; + char format[10]; + do + { + precision--; + sprintf(format, "%%.%dg", precision); + sprintf(str, format, keyed_value); + } while (!TextWidthOK(str)); + } + return keyed_value; + } + else + { + if (str != NULL) + strcpy(str, text); + return atof(text); + } +} + + +bool CalcEngine::TextWidthOK(const char *str) +{ + return (int)strlen(str) < max_digits+1 ? true : false; +} + + +void CalcEngine::DoCommand(ulong what) +{ + bool is_infix_symbol = false; + int i; + double d; + + switch (what) + { + case 'clr': + if (keyed_value == 0 && strlen(text)==0) + { + // Clear was just pressed before, so reset everything. + Clear(); + } + SetValue(0.0); + break; + case '¹': + case 'p': + case 'pi': + SetValue(M_PI); + break; + case 'e': + SetValue(M_E); + break; + case '-/+': + if (strlen(text)==0) keyed_value = -keyed_value; + else + { + // Must stick a minus sign in front of the text or + // after 'e' in exponential form. + char *p = strchr(text, 'e'); + if (p == NULL) p = text; + else p += 1; // one char after 'e' + + // p now points to insertion point + if (p[0] == '-') + p[0] = '+'; + else if (p[0] == '+') + p[0] = '-'; + else + { + memmove(p+1, p, strlen(p)+1); + p[0] = '-'; + } + } + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + Append(what); + break; + case 'exp': + if (strlen(text) > 0 && strchr(text,'e')==NULL) + Append('e'); + else + beep(); + break; + case '.': + if (strlen(text) == 0) + SetValue("0."); + else if (strchr(text,'.')==NULL && strchr(text,'e')==NULL) + Append('.'); + else beep(); + break; + case '(': + PushSymbol(what); + SetValue(0.0); + break; + case ')': + PushKeyedValue(); + while (symbol_stack_index > 0 + && symbol_stack[symbol_stack_index-1] != '(') // ) + { + d = DoStackedCalculation(); + } + if (symbol_stack_index > 0 + && symbol_stack[symbol_stack_index-1] == '(') // ) + symbol_stack_index--; + SetValue(number_stack[--number_stack_index]); + break; + case '+': + case '-': + is_infix_symbol = true; + if (already_have_infix) symbol_stack_index--; + else PushKeyedValue(); + d = GetValue(); + while (symbol_stack_index > 0 + && (symbol_stack[symbol_stack_index-1] == '+' + || symbol_stack[symbol_stack_index-1] == '-' + || symbol_stack[symbol_stack_index-1] == '*' + || symbol_stack[symbol_stack_index-1] == '/' + || symbol_stack[symbol_stack_index-1] == '^' + || symbol_stack[symbol_stack_index-1] == '^1/y')) + { + d = DoStackedCalculation(); + } + SetValue(d); + PushSymbol(what); + break; + case '*': + case '/': + is_infix_symbol = true; + if (already_have_infix) symbol_stack_index--; + else PushKeyedValue(); + d = GetValue(); + while (symbol_stack_index > 0 + && (symbol_stack[symbol_stack_index-1] == '*' + || symbol_stack[symbol_stack_index-1] == '/' + || symbol_stack[symbol_stack_index-1] == '^' + || symbol_stack[symbol_stack_index-1] == '^1/y')) + { + d = DoStackedCalculation(); + } + SetValue(d); + PushSymbol(what); + break; + case '^': + case '^1/y': + is_infix_symbol = true; + if (already_have_infix) symbol_stack_index--; + else PushKeyedValue(); + d = GetValue(); + while (symbol_stack_index > 0 + && (symbol_stack[symbol_stack_index-1] == '^' + || symbol_stack[symbol_stack_index-1] == '^1/y')) + { + d = DoStackedCalculation(); + } + SetValue(d); + PushSymbol(what); + break; + case 'x^2': + d = GetValue(); + SetValue(d * d); + break; + case 'sqrt': + SetValue(sqrt(GetValue())); + break; + case '10^x': + SetValue(pow(10.0, GetValue())); + break; + case 'log': + SetValue(log10(GetValue())); + break; + case 'e^x': + SetValue(exp(GetValue())); + break; + case 'ln x': + SetValue(log(GetValue())); + break; + case '1/x': + SetValue(1.0 / GetValue()); + break; + case '!': + d = GetValue(); + if (d > 1000) d = 1000; + else if (d < -1000) d = -1000; + + if (d >= 0) + { + i = (int)(d + 0.0000000001); + d = 1.0; + } + else + { + i = (int)(-d + 0.0000000001); + d = -1.0; + } + while (i > 0) + { + d *= i; + i--; + } + SetValue(d); + break; + case 'sin': + if (trig_inverse_active) + SetValue(TrigAngleOutput(asin(GetValue()))); + else + SetValue(sin(TrigAngleInput(GetValue()))); + break; + case 'cos': + if (trig_inverse_active) + SetValue(TrigAngleOutput(acos(GetValue()))); + else + SetValue(cos(TrigAngleInput(GetValue()))); + break; + case 'tan': + if (trig_inverse_active) + SetValue(TrigAngleOutput(atan(GetValue()))); + else + SetValue(tan(TrigAngleInput(GetValue()))); + break; + case '=': + case 'entr': + if (already_have_infix) symbol_stack_index--; + else PushKeyedValue(); + while (symbol_stack_index > 0) + { + d = DoStackedCalculation(); + } + d = number_stack[--number_stack_index]; + number_stack_index = 0; + SetValue(d); + break; + case 'trgA': + trig_inverse_active = !trig_inverse_active; + break; + case 'trgM': + trig_is_radians = !trig_is_radians; + break; + } + + already_have_infix = is_infix_symbol; + + if (what != 'trgA' && trig_inverse_active) + { + trig_inverse_active = !trig_inverse_active; + } + +} + + +void CalcEngine::PushKeyedValue() +{ + double d = GetValue(); + number_stack[number_stack_index++] = d; + SetValue(d); +} + + +void CalcEngine::PushSymbol(ulong sym) +{ + symbol_stack[symbol_stack_index++] = sym; +} + + +double CalcEngine::DoStackedCalculation() +{ + ulong sym = symbol_stack[--symbol_stack_index]; + double right_number = number_stack[--number_stack_index]; + double left_number = number_stack[--number_stack_index]; + double result; + + switch (sym) + { + case '+': + result = left_number + right_number; + break; + case '-': + result = left_number - right_number; + break; + case '*': + result = left_number * right_number; + break; + case '/': + result = left_number / right_number; + break; + case '^': + result = pow(left_number, right_number); + break; + case '^1/y': + result = pow(left_number, 1.0/right_number); + break; + default: + // bogus ! + result = 0; + break; + } + + number_stack[number_stack_index++] = result; + + return result; +} + diff --git a/src/apps/calculator/CalcEngine.h b/src/apps/calculator/CalcEngine.h new file mode 100644 index 0000000000..a3b9a5f266 --- /dev/null +++ b/src/apps/calculator/CalcEngine.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2006, Haiku, Inc. + * Distributed under the terms of the MIT license. + * + * Authors: + * Peter Wagner + */ +#ifndef __CALC_ENGINE__ +#define __CALC_ENGINE__ + +#include +#include +#include + +typedef unsigned long ulong; + +class CalcEngine +{ +public: + CalcEngine(int max_digits = 12); + virtual ~CalcEngine(); + + void DoCommand(ulong key); + double GetValue(char *val=NULL); + void Clear(void); + + bool TrigInverseActive() { return trig_inverse_active; }; + bool TrigIsRadians() { return trig_is_radians; }; + + virtual bool TextWidthOK(const char *text); + +private: + + enum { max_stack_size = 20 }; + enum { mode_start=0, mode_input }; + + char text[64]; + double keyed_value; + + void SetValue(double d) { keyed_value=d; text[0]='\0'; }; + void SetValue(const char *str) { keyed_value=0; strcpy(text,str);}; + void Append(char c) { char *p=text+strlen(text); *p++=c; *p='\0'; }; + + double DoStackedCalculation(); + void PushKeyedValue(); + void PushSymbol(ulong sym); + + int max_digits; + bool trig_inverse_active; + bool trig_is_radians; + bool already_have_infix; + + int number_stack_index; + double number_stack[max_stack_size]; + int symbol_stack_index; + ulong symbol_stack[max_stack_size]; + + double TrigAngleInput(double d) { return trig_is_radians?d:M_PI/180*d; }; + double TrigAngleOutput(double d) { return trig_is_radians?d:180/M_PI*d; }; +}; + +#endif diff --git a/src/apps/calculator/CalcView.cpp b/src/apps/calculator/CalcView.cpp new file mode 100644 index 0000000000..25eb60703d --- /dev/null +++ b/src/apps/calculator/CalcView.cpp @@ -0,0 +1,589 @@ +/* + * Copyright (c) 2006, Haiku, Inc. + * Distributed under the terms of the MIT license. + * + * Authors: + * Peter Wagner + */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CalcView.h" +#include "FrameView.h" + + +const int border = 8; +const int key_border = 4; +const int key_height = 23; +const int key_width = 32; + + +void CalcView::MouseDown(BPoint where) +{ + BView::MouseDown(where); + MakeFocus(); + ChangeHighlight(); +} + + +void CalcView::ChangeHighlight() +{ + int state = state_unknown; + + BWindow *wind = Window(); + if (wind != NULL) + state = (wind->IsActive() && IsFocus()) ? state_active : state_inactive; + + if (state != current_highlight) { + rgb_color on = {204,204,255}; + rgb_color off = {204*9/10, 204*9/10, 255*9/10}; + + if (state == state_inactive) { + lcd_frame->SetViewColor(off); + lcd->SetLowColor(off); + lcd->SetViewColor(off); + // lcd->SetHighColor(102,102,102); + } + else { + lcd_frame->SetViewColor(on); + lcd->SetLowColor(on); + lcd->SetViewColor(on); + // lcd->SetHighColor(51,51,51); + } + lcd_frame->Invalidate(); + lcd->Invalidate(); + + current_highlight = state; + } +} + + +void CalcView::WindowActivated(bool state) +{ + BView::WindowActivated(state); + + ChangeHighlight(); +} + + +void CalcView::MakeFocus(bool focusState) +{ + BView::MakeFocus(focusState); + + ChangeHighlight(); +} + + +CalcView::CalcView(BRect rect) + : BView(rect, "Calculator", B_FOLLOW_NONE, B_WILL_DRAW), + calc(15) +{ + Init(); + + BDragger *dragger; + dragger = new BDragger(BRect(0,0,7,7), this, 0); + AddChild(dragger); + + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + BRect r; + r.left = border; + r.right = r.left + key_border*8 + key_width*7; + r.top = border-1; + r.bottom = r.top + 40; + r.InsetBy(-1,0); + lcd_frame = new FrameView(r, "lcd frame", B_FOLLOW_LEFT_RIGHT|B_FOLLOW_TOP, 1); + AddChild(lcd_frame); + + BRect r2; + r2 = lcd_frame->Bounds(); + r2.InsetBy(5,2); + r2.OffsetBy(3,1); + lcd = new BStringView(r2, "lcd", "0", B_FOLLOW_ALL_SIDES); + lcd->SetFont(be_plain_font/*"Arial MT"*/); + lcd->SetFontSize(30); + lcd->SetAlignment(B_ALIGN_RIGHT); + lcd_frame->AddChild(lcd); + + static FrameView::ClusterInfo trig_button_info[] = + { {"sin", 'sin'}, {"cos", 'cos'}, + {"tan", 'tan'}, {0}, {0}, + {"inv", 'trgA'}, {"deg", 'trgM'} + }; + FrameView *trig_frame + = new FrameView(BPoint(8,57), "trig area", B_FOLLOW_NONE, + 7,1, 1, key_border, key_height, key_width, + trig_button_info); + AddChild(trig_frame); + + static FrameView::ClusterInfo const_button_info[] = + { {"-/+", '-/+'}, {"exp", 'exp'}, + {"e", 'e'}, {"pi", 'pi'}, {0}, + {"(", '('}, {")", ')'} + }; + FrameView *const_frame + = new FrameView(BPoint(8,97), "const area", B_FOLLOW_NONE, + 7,1, 1, key_border, key_height, key_width, + const_button_info); + AddChild(const_frame); + + + + static FrameView::ClusterInfo keypad_button_info[] = + { {"C",'clr'}, {"=",'='}, {"/",'/'}, {"*",'*'}, + {"7",'7'}, {"8",'8'}, {"9",'9'}, {"-",'-'}, + {"4",'4'}, {"5",'5'}, {"6",'6'}, {"+",'+'}, + {"1",'1'}, {"2",'2'}, {"3",'3'}, {"=",'entr'}, + {"0",'0'}, {0}, {".",'.'}, {0} + }; + FrameView *keypad_frame + = new FrameView(BPoint(8,137), "keypad area", B_FOLLOW_NONE, + 4,5, 1, key_border, key_height, key_width, + keypad_button_info); + AddChild(keypad_frame); + keypad_frame->FindView("entr")->ResizeBy(0, key_height+key_border); + keypad_frame->FindView("0")->ResizeBy(key_width+key_border, 0); + + + static FrameView::ClusterInfo func_button_info[] = + { {"x^y", '^'}, {"x^1/y", '^1/y'}, + {"x^2", 'x^2'}, {"sqrt", 'sqrt'}, + {"10^x", '10^x'}, {"log", 'log'}, + {"e^x", 'e^x'}, {"ln x", 'ln x'}, + {"x!", '!'}, {"1/x", '1/x'} + }; + FrameView *func_frame + = new FrameView(BPoint(188,137), "func area", B_FOLLOW_NONE, + 2,5, 1, key_border, key_height, key_width, + func_button_info); + AddChild(func_frame); +} + + +CalcView::CalcView(BMessage *msg) + : BView(msg), + calc(15) +{ + Init(); + + is_replicant = true; + + lcd_frame = (FrameView *)FindView("lcd frame"); + lcd = (BStringView *)FindView("lcd"); + + lcd->SetText("0"); +} + + +void CalcView::Init() +{ + is_replicant = false; + current_highlight = state_unknown; + + binary_sign_view = NULL; + binary_exponent_view = NULL; + binary_number_view = NULL; +} + + +void CalcView::Draw(BRect updateRect) +{ + BView::Draw(updateRect); + + if (is_replicant) + { + const float bevel = 2; + BRect r = Bounds(); + r.right -= (bevel - 1); + r.bottom -= (bevel - 1); + SetPenSize(bevel); + StrokeRect(r); + SetPenSize(1); + } +} + + +BView * CalcView::AddExtra() +{ + BRect r2; + + BRect r = Frame(); + r.top = r.bottom; + r.bottom = r.top + ExtraHeight(); + BView *view = new BView(r, "Calculator Extra", 0, B_WILL_DRAW); + view->SetViewColor(153,153,153); + + r = view->Bounds(); + r.InsetBy(border, 1); + r.left -= 1; + r.bottom = r.top + 16; + r.right = r.left + 8+2; + FrameView *binary_frame = new FrameView(r, NULL, 0, 1); + view->AddChild(binary_frame); + r2 = binary_frame->Bounds(); + r2.InsetBy(2,2); + r2.OffsetBy(1,1); + binary_sign_view = new BStringView(r2, "binary sign view", "", 0); + binary_sign_view->SetAlignment(B_ALIGN_CENTER); + binary_sign_view->SetViewColor(binary_frame->ViewColor()); + binary_frame->AddChild(binary_sign_view); + + r.OffsetBy(r.Width()+3, 0); + r.right = r.left + 72; + binary_frame = new FrameView(r, NULL, 0, 1); + view->AddChild(binary_frame); + r2 = binary_frame->Bounds(); + r2.InsetBy(2,2); + r2.OffsetBy(1,1); + binary_exponent_view = new BStringView(r2, "binary exponent view", "", 0); + binary_exponent_view->SetAlignment(B_ALIGN_CENTER); + binary_exponent_view->SetViewColor(binary_frame->ViewColor()); + binary_frame->AddChild(binary_exponent_view); + + r.OffsetBy(r.Width()+3, 0); + r.right = Bounds().Width() - border + 1; + binary_frame = new FrameView(r, NULL, 0, 1); + view->AddChild(binary_frame); + r2 = binary_frame->Bounds(); + r2.InsetBy(2,2); + r2.OffsetBy(1,1); + binary_number_view = new BStringView(r2, "binary number view", "", 0); + binary_number_view->SetAlignment(B_ALIGN_CENTER); + binary_number_view->SetViewColor(binary_frame->ViewColor()); + binary_frame->AddChild(binary_number_view); + + + r = view->Bounds(); + r.InsetBy(border, 0); + r.top = binary_frame->Frame().bottom + 3; + r.bottom = r.top + 16; + r.InsetBy(-1,0); + FrameView *about_frame = new FrameView(r, NULL, 0, 1); + view->AddChild(about_frame); + r2 = about_frame->Bounds(); + r2.InsetBy(2,2); + r2.OffsetBy(0,1); + BStringView *peter = new BStringView(r2, NULL, + "Brought to you by Peter Wagner", 0); + peter->SetAlignment(B_ALIGN_CENTER); + peter->SetViewColor(about_frame->ViewColor()); + about_frame->AddChild(peter); + + return view; +} + + +status_t CalcView::Archive(BMessage *msg, bool deep) const +{ + BView::Archive(msg, deep); +// msg->AddString("class", "CalcView"); + msg->AddString("add_on", "application/x-vnd.Be-calculator"); + return B_OK; +} + + +BArchivable *CalcView::Instantiate(BMessage *msg) +{ + if (validate_instantiation(msg, "CalcView")) + return new CalcView(msg); + else + return NULL; +} + + +CalcView::~CalcView() +{ +} + + +static void ConnectButtonMessages(BView *target, const BView *which) +{ + BView *child = which->ChildAt(0); + while (child != NULL) + { + BControl * button = (BControl *)child; + button->SetTarget(target); + child = child->NextSibling(); + } +} + + +void CalcView::AllAttached() +{ + BView::AllAttached(); + + lcd->SetHighColor(51,51,51); + MakeFocus(); + ChangeHighlight(); +} + + +void CalcView::AttachedToWindow() +{ + BView::AttachedToWindow(); + + // Make buttons send their messages to this view instead of the + // [default] enclosing window. + ConnectButtonMessages(this, FindView("trig area")); + ConnectButtonMessages(this, FindView("const area")); + ConnectButtonMessages(this, FindView("keypad area")); + ConnectButtonMessages(this, FindView("func area")); +} + + +void CalcView::KeyDown(const char *bytes, int32 numBytes) +{ + for (int i=0; iSetValue(1); + snooze(100000); + button->SetValue(0); + snooze(20000); + BMessage msg(*button->Message()); + SendKeystroke(msg.what); + } + } + +} + + +static void DoubleToBinary(double *dPtr, char *str) +{ + unsigned char *p = (unsigned char *)dPtr; + str[sizeof(double)*8] = '\0'; + const int bits = sizeof(double) * 8; + + unsigned short endian_test = 1; + + if(((unsigned char *)&endian_test)[0] != 0) { + // little-endian + for (int i=0; i> (i&7))) ? '1' : '0'; + } + else { + // Big endian + for (int i=0; i> (i&7))) ? '1' : '0'; + } +} + + +static char * Mid(const char *str, int start, int stop, char *str_out) +{ + char *s = str_out; + + for (int i=start; iSetValue(calc.TrigInverseActive()?1:0); + + BButton *trig_mode = (BButton *)FindView("trgM"); + trig_mode->SetLabel(calc.TrigIsRadians()?"rad":"deg"); + + + // Update LCD display. + char engine_str[64]; + calc.GetValue(engine_str); + lcd->SetText(engine_str); + + + if (binary_sign_view && binary_exponent_view && binary_number_view) { + // Update binary representation of current display. + double d = calc.GetValue(); + char str[300], str2[300]; + DoubleToBinary(&d, str); + binary_sign_view->SetText(Mid(str, 0,1, str2)); + binary_exponent_view->SetText(Mid(str, 1,12, str2)); + + Mid(str, 13,sizeof(double)*8, str2); + while(binary_number_view->StringWidth(str2) >= binary_number_view->Bounds().Width() + && strlen(str2) > 24) { + str2[20] = str2[21] = str2[22] = '.'; + strcpy(str2+23, str2+24); + } + binary_number_view->SetText(str2); + } +} + + +static bool IsSystemCommand(unsigned long what) +{ + for (int zz=0; zz<4; zz++) { + char c = (char)(what >> (zz*8)); + if (!isupper(c) && c!='_') return false; + } + + return true; +} + + +void CalcView::About() +{ + (new BAlert("About Calculator", "Calculator (the Replicant version)\n\n Brought to you by Peter Wagner.\n Copyright 1998.","OK"))->Go(); +} + + +void CalcView::MessageReceived(BMessage *message) +{ + switch (message->what) { + case B_ABOUT_REQUESTED: + CalcView::About(); + break; + case B_COPY: { + double d; + char str[64]; + d = calc.GetValue(str); + if (be_clipboard->Lock()) + { + be_clipboard->Clear(); + BMessage *clipper = be_clipboard->Data(); + clipper->AddDouble("value", d); + clipper->AddData("text/plain", 'MIME', str, strlen(str)); + be_clipboard->Commit(); + be_clipboard->Unlock(); + } + } + break; + case B_PASTE: { + const void *data = NULL; + ssize_t sz; + if (be_clipboard->Lock()) { + BMessage *clipper = be_clipboard->Data(); + status_t status = clipper->FindData("text/plain", 'MIME', &data, &sz); + if (status == B_OK && data!=NULL) + KeyDown((const char *)data, (int32)sz); +/* + // What the heck was on the clipboard !??! + { + char *name; + uint32 type; + int32 count; + char typeS[5]; + for ( int32 i = 0; + clipper->GetInfo(B_ANY_TYPE, i, &name, &type, &count) == B_OK; + i++ ) + { + for (int z=0; z<4; z++) + { + typeS[z] = (char)(type >> 24); + type = type << 8; + } + cout << i << ": " << name << " " << typeS << "\n"; + } + } +*/ + be_clipboard->Unlock(); + } + } + break; + default: + if (IsSystemCommand(message->what)) + BView::MessageReceived(message); + else { + SendKeystroke(message->what); + MakeFocus(); + ChangeHighlight(); + } + break; + } + +/* + // What the heck was that message?!! + char str[5]; + str[4] = '\0'; + ulong msg = message->what; + for (int i=0; i<4; i++) + { + str[i] = (char)(msg>>24); + msg = msg << 8; + if (str[i] == '\0') str[i] = '-'; + } + lcd->SetText(str); +*/ + +} + + +bool CalcView::TextWidthOK(const char *str) +{ + return (lcd->StringWidth(str) < lcd->Bounds().Width()) ? true : false; +} diff --git a/src/apps/calculator/CalcView.h b/src/apps/calculator/CalcView.h new file mode 100644 index 0000000000..6c7e6542b2 --- /dev/null +++ b/src/apps/calculator/CalcView.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2006, Haiku, Inc. + * Distributed under the terms of the MIT license. + * + * Authors: + * Peter Wagner + */ +#ifndef __CALC_VIEW__ +#define __CALC_VIEW__ + +#include +#include +#include "FrameView.h" +#include "CalcEngine.h" + +class _EXPORT CalcView : public BView +{ +public: + static void About(void); + + + static float TheWidth() { return 272; } + static float TheHeight() { return 284; } + static BRect TheRect() { return TheRect(0,0); } + static BRect TheRect(const BPoint &pt) { return TheRect(pt.x,pt.y); } + static BRect TheRect(float x, float y) { return BRect(x,y,x+TheWidth(),y+TheHeight()); } + static float ExtraHeight() { return 43; } + + + CalcView(BRect frame); + virtual ~CalcView(); + + + // replicant + CalcView(BMessage *msg); + virtual status_t Archive(BMessage *msg, bool deep) const; + static BArchivable* Instantiate(BMessage *msg); + + virtual void AttachedToWindow(); + virtual void AllAttached(); + + virtual void Draw(BRect updateRect); + virtual void KeyDown(const char *bytes, int32 numBytes); + virtual void MouseDown(BPoint where); + virtual void WindowActivated(bool state); + virtual void MakeFocus(bool focusState = true); + + virtual void MessageReceived(BMessage *message); + + void SendKeystroke(ulong key); + + virtual bool TextWidthOK(const char *str); + + BView *AddExtra(); + +private: + void Init(void); + + CalcEngine calc; + bool is_replicant; + + int current_highlight; + enum { state_unknown=0, state_active, state_inactive }; + void ChangeHighlight(); + + + FrameView *lcd_frame; + BStringView *lcd; + BStringView *binary_sign_view; + BStringView *binary_exponent_view; + BStringView *binary_number_view; + +}; + +#endif diff --git a/src/apps/calculator/CalcWindow.cpp b/src/apps/calculator/CalcWindow.cpp new file mode 100644 index 0000000000..9540175d46 --- /dev/null +++ b/src/apps/calculator/CalcWindow.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2006, Haiku, Inc. + * Distributed under the terms of the MIT license. + * + * Authors: + * Peter Wagner + */ +#include "Calculator.h" +#include "CalcWindow.h" +#include "CalcView.h" +#include "Prefs.h" + +typedef struct +{ + int h; + int v; +} Prefs; + + +CalcWindow::CalcWindow(BPoint pt) + : BWindow(CalcView::TheRect(pt), "Calculator", B_TITLED_WINDOW, B_NOT_RESIZABLE) +{ + BRect r = CalcView::TheRect(); + + SetSizeLimits(r.right, r.right, r.bottom, r.bottom+CalcView::ExtraHeight()); + SetZoomLimits(r.right, r.bottom+CalcView::ExtraHeight()); + + calc_view = new CalcView(r); + AddChild(calc_view); + + BView *extraView = calc_view->AddExtra(); + AddChild(extraView); +} + + +bool CalcWindow::QuitRequested() +{ + Prefs prefs; + prefs.h = (int)(Frame().left); + prefs.v = (int)(Frame().top); + + WritePrefs("calculator.prefs", &prefs, sizeof(prefs)); + + be_app->PostMessage(B_QUIT_REQUESTED); + return true; +} diff --git a/src/apps/calculator/CalcWindow.h b/src/apps/calculator/CalcWindow.h new file mode 100644 index 0000000000..5c7844395c --- /dev/null +++ b/src/apps/calculator/CalcWindow.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2006, Haiku, Inc. + * Distributed under the terms of the MIT license. + * + * Authors: + * Peter Wagner + */ +#ifndef __CALC_WINDOW__ +#define __CALC_WINDOW__ + +#include +#include + +#include "CalcView.h" + +class CalcWindow : public BWindow +{ +public: + CalcWindow(BPoint pt); + virtual bool QuitRequested(); + +private: + CalcView *calc_view; + +}; + +#endif diff --git a/src/apps/calculator/Calculator.cpp b/src/apps/calculator/Calculator.cpp new file mode 100644 index 0000000000..34dafe785b --- /dev/null +++ b/src/apps/calculator/Calculator.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2006, Haiku, Inc. + * Distributed under the terms of the MIT license. + * + * Authors: + * Peter Wagner + */ +#include + +#include +#include +#include +#include +#include + +#include "Calculator.h" +#include "CalcWindow.h" +#include "Prefs.h" + +typedef struct +{ + int h; + int v; +} Prefs; + +int main(int argc, char **argv) +{ + // If we have command-line arguments, calculate and + // return. Otherwise, run the graphical interface. + if(argc > 1) { + for (int i=1; i + */ +#include +#include "FrameView.h" + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * + A FrameView is a subclass of a BView that draws a simple beveled + rectangle just inside the view's bounds. + + The bevel_style parameter is currently unused--the only style available + is a 1-pixel inset bevel. + + The contents of the view are erased to the "view color." The left and + top edges are drawn in the view's high color and the right and bottom + edges are drawn inthe view's low color. You may set the high, low, + and view colors after creation to customize the FrameView's look. + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +BArchivable *FrameView::Instantiate(BMessage *archive) +{ + if ( validate_instantiation(archive, "FrameView")) + return new FrameView(archive); + return NULL; +} + + +FrameView::FrameView(BRect frame, const char *name, + ulong resizeMask, int in_bevel_indent) + : BView(frame, name, resizeMask, B_WILL_DRAW|B_FRAME_EVENTS) +{ + static const rgb_color c = {215, 215, 215, 0}; + ColoringBasis(c); + bevel_indent = in_bevel_indent; +} + + +FrameView::FrameView(BMessage *data) + : BView(data) +{ + static const rgb_color c = {215, 215, 215, 0}; + ColoringBasis(c); + + int32 i; + if(data->FindInt32("bevel_indent", &i) != B_OK) + i = 1; + if(i < 0) + i = 0; + if(i > 10) + i = 10; + bevel_indent = i; +} + + +void FrameView::MouseDown(BPoint where) +{ + // Pass unused mouse clicks up the view hierarchy. + BView *view = Parent(); + if(view != NULL) + view->MouseDown(where); +} + + +FrameView::FrameView(const BPoint &where, const char *name, uint32 resizeMask, + int items_wide, int items_high, + int bevel, int key_border, int key_height, int key_width, + const ClusterInfo button_info[]) + : BView(BRect(where.x-bevel, where.y-bevel, + where.x+bevel+key_border+items_wide*(key_border+key_width)-1, + where.y+bevel+key_border+items_high*(key_border+key_height)-1), + name, resizeMask, B_WILL_DRAW|B_FRAME_EVENTS) +{ + static const rgb_color c = {215, 215, 215, 0}; + ColoringBasis(c); + bevel_indent = bevel; + + for (int y=0; ymessage >> (24-8*i)) & 0x00FF) != 0) + *p++ = (char)(info->message >> (24-8*i)); + *p = '\0'; + if (info->message != 0) { + BRect r; + r.left = bevel_indent + key_border + x*(key_border+key_width); + r.right = r.left + key_width; + r.top = bevel_indent + key_border + y*(key_border+key_height); + r.bottom = r.top + key_height; + BMessage *msg = new BMessage(info->message); + BButton *button = new BButton(r, name, info->label, msg); + AddChild(button); + } + } + } +} + + +status_t FrameView::Archive(BMessage *msg, bool deep) const +{ + BView::Archive(msg, deep); + msg->AddString("class", "FrameView"); + msg->AddInt32("bevel_indent", (int32)bevel_indent); + return B_OK; +} + + +#define min(x,y) ((xy)?x:y) + +void FrameView::ColoringBasis(rgb_color basis_color) +{ + rgb_color view_color = basis_color; + view_color.red = min(view_color.red+15, 255); + view_color.green = min(view_color.green+15, 255); + view_color.blue = min(view_color.blue+15, 255); + SetViewColor(view_color); + + rgb_color hi_color = basis_color; + hi_color.red = max(hi_color.red-45, 0); + hi_color.green = max(hi_color.green-45, 0); + hi_color.blue = max(hi_color.blue-45, 0); + SetHighColor(hi_color); + + rgb_color low_color = basis_color; + low_color.red = min(low_color.red+45, 255); + low_color.green = min(low_color.green+45, 255); + low_color.blue = min(low_color.blue+45, 255); + SetLowColor(low_color); +} + + +void FrameView::AttachedToWindow() +{ + BView *view = Parent(); + if (view != NULL) + ColoringBasis(view->ViewColor()); +} + + +void FrameView::Draw(BRect) +{ + BRect r = Bounds(); + +// r.InsetBy(bevel_indent/2, bevel_indent/2); +// SetPenSize(bevel_indent); + + for (int i=0; i + */ +#ifndef __FRAME_VIEW__ +#define __FRAME_VIEW__ + +#include + +class _EXPORT FrameView : public BView +{ +public: + FrameView(BRect frame, const char *name, + uint32 resizeMask, int bevel_indent=1); + FrameView(BMessage *data); + virtual status_t Archive(BMessage *msg, bool deep) const; + static BArchivable * Instantiate(BMessage *archive); + + virtual void Draw(BRect updateRect); + virtual void FrameResized(float new_width, float new_height); + virtual void AttachedToWindow(); + void MouseDown(BPoint where); + + void ColoringBasis(rgb_color view_color); + + + typedef struct + { + char *label; + uint32 message; + } ClusterInfo; + + FrameView(const BPoint &where, const char *name, + uint32 resizeMask, int items_wide, + int items_high, int bevel, int key_border, + int key_height, int key_width, + const ClusterInfo button_info[]); +private: + int bevel_indent; +}; + +#endif diff --git a/src/apps/calculator/Jamfile b/src/apps/calculator/Jamfile new file mode 100644 index 0000000000..9390f74816 --- /dev/null +++ b/src/apps/calculator/Jamfile @@ -0,0 +1,14 @@ +SubDir HAIKU_TOP src apps calculator ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +Application Calculator : + CalcEngine.cpp + Calculator.cpp + CalcView.cpp + CalcWindow.cpp + FrameView.cpp + Prefs.cpp + : be + : Calculator.rdef + ; diff --git a/src/apps/calculator/Prefs.cpp b/src/apps/calculator/Prefs.cpp new file mode 100644 index 0000000000..5e58a3178b --- /dev/null +++ b/src/apps/calculator/Prefs.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2006, Haiku, Inc. + * Distributed under the terms of the MIT license. + * + * Authors: + * Peter Wagner + */ +#include +#include +#include +#include "Prefs.h" + +bool ReadPrefs(const char *prefsname, void *prefs, size_t sz) +{ + BPath path; + find_directory(B_USER_SETTINGS_DIRECTORY, &path, true); + + BDirectory dir; + dir.SetTo(path.Path()); + + BEntry entry; + if (dir.FindEntry(prefsname, &entry) == B_OK) { + BFile file(&entry, O_RDONLY); + if (file.InitCheck() == B_OK) { + if ((size_t)file.Read(prefs, sz) == sz) + return true; + } + } + + memset(prefs, 0, sz); + return false; +} + + +bool WritePrefs(const char *prefsname, void *prefs, size_t sz) +{ + BPath path; + find_directory(B_USER_SETTINGS_DIRECTORY, &path, true); + + BDirectory dir; + dir.SetTo(path.Path()); + + BFile file; + if (dir.CreateFile(prefsname, &file, false) == B_OK) { + if ((size_t)file.Write(prefs, sz) == sz) + return true; + } + + return false; +} diff --git a/src/apps/calculator/Prefs.h b/src/apps/calculator/Prefs.h new file mode 100644 index 0000000000..3a93484f33 --- /dev/null +++ b/src/apps/calculator/Prefs.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2006, Haiku, Inc. + * Distributed under the terms of the MIT license. + * + * Authors: + * Peter Wagner + */ +#ifndef __PREFS__ +#define __PREFS__ + +bool ReadPrefs(const char *prefsname, void *prefs, size_t sz); +bool WritePrefs(const char *prefsname, void *prefs, size_t sz); + +#endif \ No newline at end of file