/*********************************************************************** * calculator.cpp - A simple calculator with trigonometric functions * * * * This file is part of the Final Cut widget toolkit * * * * Copyright 2016-2018 Markus Gans * * * * The Final Cut is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public License * * as published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * The Final Cut is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this program. If not, see * * . * ***********************************************************************/ #include #include #include #include #include #include #include #include constexpr lDouble PI = 3.141592653589793238L; //---------------------------------------------------------------------- // class Button //---------------------------------------------------------------------- #pragma pack(push) #pragma pack(1) class Button : public finalcut::FButton { public: // Constructor explicit Button (FWidget* = nullptr); // Method void setChecked(bool); // Event handler virtual void onKeyPress (finalcut::FKeyEvent*) override; private: // Data Member bool checked{false}; }; #pragma pack(pop) //---------------------------------------------------------------------- Button::Button (finalcut::FWidget* parent) : finalcut::FButton(parent) { } //---------------------------------------------------------------------- void Button::setChecked (bool enable) { if ( checked == enable ) return; checked = enable; if ( checked ) { setBackgroundColor(finalcut::fc::Cyan); setFocusForegroundColor(finalcut::fc::White); setFocusBackgroundColor(finalcut::fc::Cyan); } else { setBackgroundColor(wc.button_active_bg); setFocusForegroundColor(wc.button_active_focus_fg); setFocusBackgroundColor(wc.button_active_focus_bg); } redraw(); } //---------------------------------------------------------------------- void Button::onKeyPress (finalcut::FKeyEvent* ev) { FKey key = ev->key(); // catch the enter key if ( key == finalcut::fc::Fkey_return || key == finalcut::fc::Fkey_enter ) return; finalcut::FButton::onKeyPress(ev); } //---------------------------------------------------------------------- // class Calc //---------------------------------------------------------------------- #pragma pack(push) #pragma pack(1) class Calc : public finalcut::FDialog { public: // Constructor explicit Calc (finalcut::FWidget* parent = nullptr); // Destructor ~Calc(); // Event handlers virtual void onKeyPress (finalcut::FKeyEvent*) override; virtual void onAccel (finalcut::FAccelEvent*) override; virtual void onClose (finalcut::FCloseEvent*) override; // Callback method void cb_buttonClicked (finalcut::FWidget*, FDataPtr); private: // Typedef and Enumeration typedef void (Calc::*keyFunction)(lDouble&); // Method pointer enum button { Sine, Cosine, Tangent, Reciprocal, On, Natural_logarithm, Powers_of_e, Power, Square_root, Divide, Common_logarithm, Powers_of_ten, Parenthese_l, Parenthese_r, Multiply, Hyperbolic, Seven, Eight, Nine, Subtract, Arcus, Four, Five, Six, Add, Pi, One, Two, Three, Percent, Zero, Decimal_point, Change_sign, Equals, NUM_OF_BUTTONS }; // Methods void drawDispay(); virtual void draw() override; void clear (lDouble&); void zero (lDouble&); void one (lDouble&); void two (lDouble&); void three (lDouble&); void four (lDouble&); void five (lDouble&); void six (lDouble&); void seven (lDouble&); void eight (lDouble&); void nine (lDouble&); void add (lDouble&); void subtract (lDouble&); void multiply (lDouble&); void divide (lDouble&); void equals (lDouble&); void change_sign (lDouble&); void radix_point(lDouble&); void reciprocal (lDouble&); void percent (lDouble&); void pi (lDouble&); void open_bracket (lDouble&); void close_bracket (lDouble&); void log_e (lDouble&); void power_e (lDouble&); void log_10 (lDouble&); void power_10 (lDouble&); void power (lDouble&); void square_root (lDouble&); void hyperbolic (lDouble&); void arcus (lDouble&); void sine (lDouble&); void cosine (lDouble&); void tangent (lDouble&); bool isDataEntryKey (int); bool isOperatorKey (int); lDouble& getValue(); void setDisplay (lDouble); void setInfixOperator (char); void clearInfixOperator(); void calcInfixOperator(); virtual void adjustSize() override; const wchar_t* getButtonText (std::size_t); void mapKeyFunctions(); // Data Members bool error{false}; bool arcus_mode{false}; bool hyperbolic_mode{false}; lDouble a{0.0L}; lDouble b{0.0L}; lDouble infinity{std::numeric_limits::infinity()}; uInt max_char{33}; int last_key{-1}; char infix_operator{'\0'}; char last_infix_operator{'\0'}; finalcut::FString input{""}; std::size_t button_no[Calc::NUM_OF_BUTTONS]{}; struct stack_data { lDouble term; char infix_operator; }; std::stack bracket_stack{}; std::map > calculator_buttons{}; std::map key_map{}; }; #pragma pack(pop) //---------------------------------------------------------------------- Calc::Calc (FWidget* parent) : finalcut::FDialog(parent) { mapKeyFunctions(); clearInfixOperator(); std::setlocale(LC_NUMERIC, "C"); setText ("Calculator"); setGeometry (19, 6, 37, 18); addAccelerator('q'); // Press 'q' to quit for (std::size_t key = 0; key < Calc::NUM_OF_BUTTONS; key++) { auto btn = std::make_shared