/*********************************************************************** * calculator.cpp - A simple calculator with trigonometric functions * * * * This file is part of the Final Cut widget toolkit * * * * Copyright 2016-2020 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 namespace fc = finalcut::fc; using finalcut::FPoint; using finalcut::FRect; using finalcut::FSize; using finalcut::FColorPair; constexpr lDouble PI{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(fc::Cyan); setFocusForegroundColor(fc::White); setFocusBackgroundColor(fc::Cyan); } else { const auto& wc = getFWidgetColors(); 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 == fc::Fkey_return || key == fc::Fkey_enter ) return; finalcut::FButton::onKeyPress(ev); } //---------------------------------------------------------------------- // class Calc //---------------------------------------------------------------------- class Calc final : public finalcut::FDialog { public: // Using-declaration using FDialog::setGeometry; // Constructor explicit Calc (finalcut::FWidget* parent = nullptr); // Destructor ~Calc() override; // Event handlers void onKeyPress (finalcut::FKeyEvent*) override; void onClose (finalcut::FCloseEvent*) override; // Callback method void cb_buttonClicked (const finalcut::FWidget*, FDataPtr); private: // Typedef and Enumeration typedef std::function keyFunction; // Member function 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(); 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 (int); bool isOperatorKey (int); lDouble& getValue(); void setDisplay (lDouble); void setInfixOperator (char); void clearInfixOperator(); void calcInfixOperator(); void adjustSize() override; const wchar_t* getButtonText (const 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{}; }; //---------------------------------------------------------------------- Calc::Calc (FWidget* parent) : finalcut::FDialog(parent) { // Dialog settings // Avoids calling a virtual function from the constructor // (CERT, OOP50-CPP) FDialog::setText ("Calculator"); FDialog::setGeometry (FPoint(19, 6), FSize(37, 18)); mapKeyFunctions(); clearInfixOperator(); std::setlocale(LC_NUMERIC, "C"); for (std::size_t key{0}; key < Calc::NUM_OF_BUTTONS; key++) { auto btn = std::make_shared