/*********************************************************************** * calculator.cpp - A simple calculator with trigonometric functions * * * * This file is part of the FINAL CUT widget toolkit * * * * Copyright 2016-2021 Markus Gans * * * * 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. * * * * 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 #include using FKey = finalcut::FKey; using finalcut::FColorPair; using finalcut::FColor; using finalcut::FPoint; using finalcut::FRect; using finalcut::FSize; constexpr lDouble pi_value{3.141592653589793238L}; //---------------------------------------------------------------------- // class Button //---------------------------------------------------------------------- class Button final : public finalcut::FButton { public: // Constructor explicit Button (FWidget* = nullptr); // Method void setChecked(bool); // Event handler void onKeyPress (finalcut::FKeyEvent*) override; private: // Data member bool checked{false}; }; //---------------------------------------------------------------------- Button::Button (finalcut::FWidget* parent) : finalcut::FButton{parent} { } //---------------------------------------------------------------------- void Button::setChecked (bool enable) { if ( checked == enable ) return; checked = enable; if ( checked ) { setBackgroundColor(FColor::Cyan); setFocusForegroundColor(FColor::White); setFocusBackgroundColor(FColor::Cyan); } else { const auto& wc = getColorTheme(); setBackgroundColor(wc->button_active_bg); setFocusForegroundColor(wc->button_active_focus_fg); setFocusBackgroundColor(wc->button_active_focus_bg); } redraw(); } //---------------------------------------------------------------------- void Button::onKeyPress (finalcut::FKeyEvent* ev) { const FKey key = ev->key(); // catch the enter key if ( key == FKey::Return || key == FKey::Enter ) return; finalcut::FButton::onKeyPress(ev); } //---------------------------------------------------------------------- // class Calc //---------------------------------------------------------------------- class Calc final : public finalcut::FDialog { public: // Constructor explicit Calc (finalcut::FWidget* parent = nullptr); // Destructor ~Calc() override = default; private: // Typedef and Enumeration using keyFunction = std::function; // Member function enum class ButtonName { 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(); void draw() override; void sendOnButtonAccelerator(); void clear (const lDouble&); void zero (const lDouble&); void one (const lDouble&); void two (const lDouble&); void three (const lDouble&); void four (const lDouble&); void five (const lDouble&); void six (const lDouble&); void seven (const lDouble&); void eight (const lDouble&); void nine (const lDouble&); void add (const lDouble&); void subtract (const lDouble&); void multiply (const lDouble&); void divide (const lDouble&); void equals (const lDouble&); void change_sign (lDouble&); void radix_point(const lDouble&); void reciprocal (lDouble&); void percent (lDouble&); void pi (lDouble&); void open_bracket (const lDouble&); void close_bracket (const lDouble&); void log_e (lDouble&); void power_e (lDouble&); void log_10 (lDouble&); void power_10 (lDouble&); void power (const lDouble&); void square_root (lDouble&); void hyperbolic (const lDouble&); void arcus (const lDouble&); void sine (lDouble&); void cosine (lDouble&); void tangent (lDouble&); bool isDataEntryKey (const ButtonName&) const; bool isOperatorKey (const ButtonName&) const; lDouble& getValue(); void setDisplay (lDouble); void setInfixOperator (char); void clearInfixOperator(); void calcInfixOperator(); void initLayout() override; void adjustSize() override; const wchar_t* getButtonText (const ButtonName&) const; void mapKeyFunctions(); // Event handlers void onKeyPress (finalcut::FKeyEvent*) override; void onShow (finalcut::FShowEvent*) override; void onClose (finalcut::FCloseEvent*) override; // Callback method void cb_buttonClicked (ButtonName); // Overloaded operators friend bool operator < (const ButtonName& c, const int n) noexcept; friend bool operator <= (const ButtonName& c, const int n) noexcept; friend ButtonName operator + (const ButtonName& c, const int n) noexcept; friend ButtonName& operator ++ (ButtonName& c) noexcept; // prefix friend ButtonName operator ++ (ButtonName& c, int) noexcept; // postfix // 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}; ButtonName last_key{ButtonName(-1)}; char infix_operator{'\0'}; char last_infix_operator{'\0'}; finalcut::FString input{""}; std::array button_no{}; struct StackData { lDouble term; char infix_operator; }; std::stack bracket_stack{}; std::map > calculator_buttons{}; std::map key_map{}; }; //---------------------------------------------------------------------- Calc::Calc (FWidget* parent) : finalcut::FDialog{parent} { mapKeyFunctions(); clearInfixOperator(); for (ButtonName key{ButtonName::Sine}; key < ButtonName::NUM_OF_BUTTONS; key++) { auto btn = std::make_shared