/*********************************************************************** * calculator.cpp - A simple calculator with trigonometric functions * * * * This file is part of the Final Cut widget toolkit * * * * Copyright 2016-2019 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::FSize; using finalcut::FColorPair; 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 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(fc::Cyan); setFocusForegroundColor(fc::White); setFocusBackgroundColor(fc::Cyan); } else { const finalcut::FWidgetColors& 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) { FKey key = ev->key(); // catch the enter key if ( key == fc::Fkey_return || key == 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 void onKeyPress (finalcut::FKeyEvent*) override; 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(); 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(); 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 (FPoint(19, 6), FSize(37, 18)); for (std::size_t key{0}; key < Calc::NUM_OF_BUTTONS; key++) { auto btn = std::make_shared