diff --git a/src/CalcManager/CEngine/CalcInput.cpp b/src/CalcManager/CEngine/CalcInput.cpp index 600f900..57cef5d 100644 --- a/src/CalcManager/CEngine/CalcInput.cpp +++ b/src/CalcManager/CEngine/CalcInput.cpp @@ -261,6 +261,11 @@ void CalcInput::SetDecimalSymbol(wchar_t decSymbol) } } +bool CalcInput::IsEmpty() +{ + return m_base.IsEmpty() && !m_hasExponent && m_exponent.IsEmpty() && !m_hasDecimal; +} + wstring CalcInput::ToString(uint32_t radix) { // In theory both the base and exponent could be C_NUM_MAX_DIGITS long. diff --git a/src/CalcManager/CEngine/CalcUtils.cpp b/src/CalcManager/CEngine/CalcUtils.cpp index 57510dc..8807627 100644 --- a/src/CalcManager/CEngine/CalcUtils.cpp +++ b/src/CalcManager/CEngine/CalcUtils.cpp @@ -11,14 +11,14 @@ bool IsOpInRange(OpCode op, uint32_t x, uint32_t y) bool IsBinOpCode(OpCode opCode) { - return IsOpInRange(opCode, IDC_AND, IDC_PWR); + return IsOpInRange(opCode, IDC_AND, IDC_PWR) || IsOpInRange(opCode, IDC_BINARYEXTENDEDFIRST, IDC_BINARYEXTENDEDLAST); } // WARNING: IDC_SIGN is a special unary op but still this doesn't catch this. Caller has to be aware // of it and catch it themselves or not needing this bool IsUnaryOpCode(OpCode opCode) { - return IsOpInRange(opCode, IDC_UNARYFIRST, IDC_UNARYLAST); + return (IsOpInRange(opCode, IDC_UNARYFIRST, IDC_UNARYLAST) || IsOpInRange(opCode, IDC_UNARYEXTENDEDFIRST, IDC_UNARYEXTENDEDLAST)); } bool IsDigitOpCode(OpCode opCode) diff --git a/src/CalcManager/CEngine/History.cpp b/src/CalcManager/CEngine/History.cpp index 37add76..85f31b4 100644 --- a/src/CalcManager/CEngine/History.cpp +++ b/src/CalcManager/CEngine/History.cpp @@ -120,12 +120,12 @@ void CHistoryCollector::RemoveLastOpndFromHistory() // This will not restore the m_lastBinOpStartIndex, as it isn't possible to remove that also later } -void CHistoryCollector::AddBinOpToHistory(int nOpCode, bool fNoRepetition) +void CHistoryCollector::AddBinOpToHistory(int nOpCode, bool isIntegerMode, bool fNoRepetition) { int iCommandEnd = AddCommand(std::make_shared(nOpCode)); m_lastBinOpStartIndex = IchAddSzToEquationSz(L" ", -1); - IchAddSzToEquationSz(CCalcEngine::OpCodeToString(nOpCode), iCommandEnd); + IchAddSzToEquationSz(CCalcEngine::OpCodeToBinaryString(nOpCode, isIntegerMode), iCommandEnd); IchAddSzToEquationSz(L" ", -1); if (fNoRepetition) @@ -138,14 +138,14 @@ void CHistoryCollector::AddBinOpToHistory(int nOpCode, bool fNoRepetition) // This is expected to be called when a binary op in the last say 1+2+ is changing to another one say 1+2* (+ changed to *) // It needs to know by this change a Precedence inversion happened. i.e. previous op was lower or equal to its previous op, but the new // one isn't. (Eg. 1*2* to 1*2^). It can add explicit brackets to ensure the precedence is inverted. (Eg. (1*2) ^) -void CHistoryCollector::ChangeLastBinOp(int nOpCode, bool fPrecInvToHigher) +void CHistoryCollector::ChangeLastBinOp(int nOpCode, bool fPrecInvToHigher, bool isIntgerMode) { TruncateEquationSzFromIch(m_lastBinOpStartIndex); if (fPrecInvToHigher) { EnclosePrecInversionBrackets(); } - AddBinOpToHistory(nOpCode); + AddBinOpToHistory(nOpCode, isIntgerMode); } void CHistoryCollector::PushLastOpndStart(int ichOpndStart) @@ -266,6 +266,30 @@ void CHistoryCollector::AddUnaryOpToHistory(int nOpCode, bool fInv, ANGLE_TYPE a command = fInv ? static_cast(CalculationManager::Command::CommandATANH) : IDC_TANH; spExpressionCommand = std::make_shared(command); break; + case IDC_SEC: + command = fInv ? static_cast(CalculationManager::Command::CommandASEC) : IDC_SEC; + spExpressionCommand = std::make_shared(static_cast(angleOpCode), command); + break; + case IDC_CSC: + command = fInv ? static_cast(CalculationManager::Command::CommandACSC) : IDC_CSC; + spExpressionCommand = std::make_shared(static_cast(angleOpCode), command); + break; + case IDC_COT: + command = fInv ? static_cast(CalculationManager::Command::CommandACOT) : IDC_COT; + spExpressionCommand = std::make_shared(static_cast(angleOpCode), command); + break; + case IDC_SECH: + command = fInv ? static_cast(CalculationManager::Command::CommandASECH) : IDC_SECH; + spExpressionCommand = std::make_shared(command); + break; + case IDC_CSCH: + command = fInv ? static_cast(CalculationManager::Command::CommandACSCH) : IDC_CSCH; + spExpressionCommand = std::make_shared(command); + break; + case IDC_COTH: + command = fInv ? static_cast(CalculationManager::Command::CommandACOTH) : IDC_COTH; + spExpressionCommand = std::make_shared(command); + break; case IDC_LN: command = fInv ? static_cast(CalculationManager::Command::CommandPOWE) : IDC_LN; spExpressionCommand = std::make_shared(command); diff --git a/src/CalcManager/CEngine/scicomm.cpp b/src/CalcManager/CEngine/scicomm.cpp index 4752ec9..29a79bb 100644 --- a/src/CalcManager/CEngine/scicomm.cpp +++ b/src/CalcManager/CEngine/scicomm.cpp @@ -16,6 +16,7 @@ #include #include "Header Files/CalcEngine.h" #include "Header Files/CalcUtils.h" +#include "NumberFormattingUtils.h" using namespace std; using namespace CalcEngine; @@ -28,8 +29,13 @@ namespace // 0 is returned. Higher the number, higher the precedence of the operator. int NPrecedenceOfOp(int nopCode) { - static uint8_t rgbPrec[] = { 0, 0, IDC_OR, 0, IDC_XOR, 0, IDC_AND, 1, IDC_ADD, 2, IDC_SUB, 2, IDC_RSHF, - 3, IDC_LSHF, 3, IDC_MOD, 3, IDC_DIV, 3, IDC_MUL, 3, IDC_PWR, 4, IDC_ROOT, 4 }; + static uint16_t rgbPrec[] = { + 0,0, IDC_OR,0, IDC_XOR,0, + IDC_AND,1, IDC_NAND,1, IDC_NOR,1, + IDC_ADD,2, IDC_SUB,2, + IDC_RSHF,3, IDC_LSHF,3, IDC_RSHFL,3, + IDC_MOD,3, IDC_DIV,3, IDC_MUL,3, + IDC_PWR,4, IDC_ROOT,4, IDC_LOGBASEX,4 }; unsigned int iPrec; iPrec = 0; @@ -124,9 +130,18 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam) // Toggle Record/Display mode if appropriate. if (m_bRecord) { - if (IsOpInRange(wParam, IDC_AND, IDC_MMINUS) || IsOpInRange(wParam, IDC_OPENP, IDC_CLOSEP) || IsOpInRange(wParam, IDM_HEX, IDM_BIN) - || IsOpInRange(wParam, IDM_QWORD, IDM_BYTE) || IsOpInRange(wParam, IDM_DEG, IDM_GRAD) - || IsOpInRange(wParam, IDC_BINEDITSTART, IDC_BINEDITSTART + 63) || (IDC_INV == wParam) || (IDC_SIGN == wParam && 10 != m_radix)) + if (IsBinOpCode(wParam) || + IsUnaryOpCode(wParam) || + IsOpInRange(wParam, IDC_FE, IDC_MMINUS) || + IsOpInRange(wParam, IDC_OPENP, IDC_CLOSEP) || + IsOpInRange(wParam, IDM_HEX, IDM_BIN) || + IsOpInRange(wParam, IDM_QWORD, IDM_BYTE) || + IsOpInRange(wParam, IDM_DEG, IDM_GRAD) || + IsOpInRange(wParam, IDC_BINEDITSTART, IDC_BINEDITEND) || + (IDC_INV == wParam) || + (IDC_SIGN == wParam && 10 != m_radix) || + (IDC_RAND == wParam) || + (IDC_EULER == wParam)) { m_bRecord = false; m_currentVal = m_input.ToRational(m_radix, m_precision); @@ -193,7 +208,7 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam) m_nPrevOpCode = 0; // Once the precedence inversion has put additional brackets, its no longer required } } - m_HistoryCollector.ChangeLastBinOp(m_nOpCode, fPrecInvToHigher); + m_HistoryCollector.ChangeLastBinOp(m_nOpCode, fPrecInvToHigher, m_fIntegerMode); DisplayAnnounceBinaryOperator(); return; } @@ -270,10 +285,9 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam) } DisplayAnnounceBinaryOperator(); - m_lastVal = m_currentVal; m_nOpCode = (int)wParam; - m_HistoryCollector.AddBinOpToHistory(m_nOpCode); + m_HistoryCollector.AddBinOpToHistory(m_nOpCode, m_fIntegerMode); m_bNoPrevEqu = m_bChangeOp = true; return; } @@ -303,7 +317,8 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam) m_HistoryCollector.AddUnaryOpToHistory((int)wParam, m_bInv, m_angletype); } - if ((wParam == IDC_SIN) || (wParam == IDC_COS) || (wParam == IDC_TAN) || (wParam == IDC_SINH) || (wParam == IDC_COSH) || (wParam == IDC_TANH)) + if ((wParam == IDC_SIN) || (wParam == IDC_COS) || (wParam == IDC_TAN) || (wParam == IDC_SINH) || (wParam == IDC_COSH) || (wParam == IDC_TANH) + || (wParam == IDC_SEC) || (wParam == IDC_CSC) || (wParam == IDC_COT) || (wParam == IDC_SECH) || (wParam == IDC_CSCH) || (wParam == IDC_COTH)) { if (IsCurrentTooBigForTrig()) { @@ -330,9 +345,13 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam) /* reset the m_bInv flag and indicators if it is set and have been used */ - if (m_bInv - && ((wParam == IDC_CHOP) || (wParam == IDC_SIN) || (wParam == IDC_COS) || (wParam == IDC_TAN) || (wParam == IDC_LN) || (wParam == IDC_DMS) - || (wParam == IDC_DEGREES) || (wParam == IDC_SINH) || (wParam == IDC_COSH) || (wParam == IDC_TANH))) + if (m_bInv && + ((wParam == IDC_CHOP) || (wParam == IDC_SIN) || (wParam == IDC_COS) || + (wParam == IDC_TAN) || (wParam == IDC_LN) || (wParam == IDC_DMS) || + (wParam == IDC_DEGREES) || (wParam == IDC_SINH) || (wParam == IDC_COSH) || + (wParam == IDC_TANH) || (wParam == IDC_SEC) || (wParam == IDC_CSC) || + (wParam == IDC_COT) || (wParam == IDC_SECH) || (wParam == IDC_CSCH) || + (wParam == IDC_COTH))) { m_bInv = false; } @@ -341,10 +360,10 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam) } // Tiny binary edit windows clicked. Toggle that bit and update display - if (IsOpInRange(wParam, IDC_BINEDITSTART, IDC_BINEDITSTART + 63)) + if (IsOpInRange(wParam, IDC_BINEDITSTART, IDC_BINEDITEND)) { // Same reasoning as for unary operators. We need to seed it previous number - if (m_nLastCom >= IDC_AND && m_nLastCom <= IDC_PWR) + if (IsBinOpCode(m_nLastCom)) { m_currentVal = m_lastVal; } @@ -377,6 +396,7 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam) m_precedenceOpCount = m_nTempCom = m_nLastCom = m_nOpCode = 0; m_nPrevOpCode = 0; m_bNoPrevEqu = true; + m_carryBit = 0; /* clear the parenthesis status box indicator, this will not be cleared for CENTR */ @@ -700,7 +720,6 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam) case IDC_MCLEAR: m_memoryValue = make_unique(wParam == IDC_STORE ? TruncateNumForIntMath(m_currentVal) : 0); break; - case IDC_PI: if (!m_fIntegerMode) { @@ -713,7 +732,43 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam) } HandleErrorCommand(wParam); break; + case IDC_RAND: + if (!m_fIntegerMode) + { + CheckAndAddLastBinOpToHistory(); // rand is like entering the number + wstringstream str; + str << fixed << setprecision(m_precision) << GenerateRandomNumber(); + + auto rat = StringToRat(false, str.str(), false, L"", m_radix, m_precision); + if (rat != nullptr) + { + m_currentVal = Rational{ rat }; + } + else + { + m_currentVal = Rational{ 0 }; + } + destroyrat(rat); + + DisplayNum(); + m_bInv = false; + break; + } + HandleErrorCommand(wParam); + break; + case IDC_EULER: + if (!m_fIntegerMode) + { + CheckAndAddLastBinOpToHistory(); // e is like entering the number + m_currentVal = Rational{ rat_exp }; + + DisplayNum(); + m_bInv = false; + break; + } + HandleErrorCommand(wParam); + break; case IDC_FE: // Toggle exponential notation display. m_nFE = NUMOBJ_FMT(!(int)m_nFE); @@ -761,7 +816,7 @@ void CCalcEngine::ResolveHighestPrecedenceOperation() { m_currentVal = m_holdVal; DisplayNum(); // to update the m_numberString - m_HistoryCollector.AddBinOpToHistory(m_nOpCode, false); + m_HistoryCollector.AddBinOpToHistory(m_nOpCode, m_fIntegerMode, false); m_HistoryCollector.AddOpndToHistory(m_numberString, m_currentVal); // Adding the repeated last op to history } @@ -863,11 +918,14 @@ struct FunctionNameElement wstring gradString; wstring inverseGradString; // Will fall back to gradString if empty + wstring programmerModeString; + bool hasAngleStrings = ((!radString.empty()) || (!inverseRadString.empty()) || (!gradString.empty()) || (!inverseGradString.empty())); }; // Table for each unary operator -static const std::unordered_map unaryOperatorStringTable = { +static const std::unordered_map operatorStringTable = +{ { IDC_CHOP, { L"", SIDS_FRAC } }, { IDC_SIN, { SIDS_SIND, SIDS_ASIND, SIDS_SINR, SIDS_ASINR, SIDS_SING, SIDS_ASING } }, @@ -878,6 +936,14 @@ static const std::unordered_map unaryOperatorStringTab { IDC_COSH, { L"", SIDS_ACOSH } }, { IDC_TANH, { L"", SIDS_ATANH } }, + { IDC_SEC, { SIDS_SECD, SIDS_ASECD, SIDS_SECR, SIDS_ASECR, SIDS_SECG, SIDS_ASECG } }, + { IDC_CSC, { SIDS_CSCD, SIDS_ACSCD, SIDS_CSCR, SIDS_ACSCR, SIDS_CSCG, SIDS_ACSCG } }, + { IDC_COT, { SIDS_COTD, SIDS_ACOTD, SIDS_COTR, SIDS_ACOTR, SIDS_COTG, SIDS_ACOTG } }, + + { IDC_SECH, { SIDS_SECH, SIDS_ASECH } }, + { IDC_CSCH, { SIDS_CSCH, SIDS_ACSCH } }, + { IDC_COTH, { SIDS_COTH, SIDS_ACOTH } }, + { IDC_LN, { L"", SIDS_POWE } }, { IDC_SQR, { SIDS_SQR } }, { IDC_CUB, { SIDS_CUBE } }, @@ -885,7 +951,19 @@ static const std::unordered_map unaryOperatorStringTab { IDC_REC, { SIDS_RECIPROC } }, { IDC_DMS, { L"", SIDS_DEGREES } }, { IDC_SIGN, { SIDS_NEGATE } }, - { IDC_DEGREES, { SIDS_DEGREES } } + { IDC_DEGREES, { SIDS_DEGREES } }, + { IDC_POW2, { SIDS_TWOPOWX } }, + { IDC_LOGBASEX, { SIDS_LOGBASEX } }, + { IDC_ABS, { SIDS_ABS } }, + { IDC_CEIL, { SIDS_CEIL } }, + { IDC_FLOOR, { SIDS_FLOOR } }, + { IDC_NAND, { SIDS_NAND } }, + { IDC_NOR, { SIDS_NOR } }, + { IDC_RSHFL, { SIDS_RSH } }, + { IDC_RORC, { SIDS_ROR } }, + { IDC_ROLC, { SIDS_ROL } }, + { IDC_CUBEROOT, {SIDS_CUBEROOT} }, + { IDC_MOD, {SIDS_MOD, L"", L"", L"", L"", L"", SIDS_PROGRAMMER_MOD} }, }; wstring_view CCalcEngine::OpCodeToUnaryString(int nOpCode, bool fInv, ANGLE_TYPE angletype) @@ -893,7 +971,7 @@ wstring_view CCalcEngine::OpCodeToUnaryString(int nOpCode, bool fInv, ANGLE_TYPE // Try to lookup the ID in the UFNE table wstring ids = L""; - if (auto pair = unaryOperatorStringTable.find(nOpCode); pair != unaryOperatorStringTable.end()) + if (auto pair = operatorStringTable.find(nOpCode); pair != operatorStringTable.end()) { const FunctionNameElement& element = pair->second; if (!element.hasAngleStrings || ANGLE_DEG == angletype) @@ -941,6 +1019,32 @@ wstring_view CCalcEngine::OpCodeToUnaryString(int nOpCode, bool fInv, ANGLE_TYPE return OpCodeToString(nOpCode); } +wstring_view CCalcEngine::OpCodeToBinaryString(int nOpCode, bool isIntegerMode) +{ + // Try to lookup the ID in the UFNE table + wstring ids = L""; + + if (auto pair = operatorStringTable.find(nOpCode); pair != operatorStringTable.end()) + { + if (isIntegerMode && !pair->second.programmerModeString.empty()) + { + ids = pair->second.programmerModeString; + } + else + { + ids = pair->second.degreeString; + } + } + + if (!ids.empty()) + { + return GetString(ids); + } + + // If we didn't find an ID in the table, use the op code. + return OpCodeToString(nOpCode); +} + bool CCalcEngine::IsCurrentTooBigForTrig() { return m_currentVal >= m_maxTrigonometricNum; @@ -1007,3 +1111,14 @@ wstring CCalcEngine::GetStringForDisplay(Rational const& rat, uint32_t radix) return result; } + +double CCalcEngine::GenerateRandomNumber() +{ + if (m_randomGeneratorEngine == nullptr) + { + random_device rd; + m_randomGeneratorEngine = std::make_unique(rd()); + m_distr = std::make_unique>(0, 1); + } + return (*m_distr.get())(*m_randomGeneratorEngine.get()); +} diff --git a/src/CalcManager/CEngine/scifunc.cpp b/src/CalcManager/CEngine/scifunc.cpp index 5684ce4..15ef164 100644 --- a/src/CalcManager/CEngine/scifunc.cpp +++ b/src/CalcManager/CEngine/scifunc.cpp @@ -46,8 +46,8 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r } break; - // Rotate Left with hi bit wrapped over to lo bit case IDC_ROL: + case IDC_ROLC: if (m_fIntegerMode) { result = Integer(rat); @@ -55,14 +55,23 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r uint64_t w64Bits = result.ToUInt64_t(); uint64_t msb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1; w64Bits <<= 1; // LShift by 1 - w64Bits |= msb; // Set the prev Msb as the current Lsb + + if (op == IDC_ROL) + { + w64Bits |= msb; // Set the prev Msb as the current Lsb + } + else + { + w64Bits |= m_carryBit; // Set the carry bit as the LSB + m_carryBit = msb; // Store the msb as the next carry bit + } result = w64Bits; } break; - // Rotate right with lo bit wrapped over to hi bit case IDC_ROR: + case IDC_RORC: if (m_fIntegerMode) { result = Integer(rat); @@ -70,7 +79,16 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r uint64_t w64Bits = result.ToUInt64_t(); uint64_t lsb = ((w64Bits & 0x01) == 1) ? 1 : 0; w64Bits >>= 1; // RShift by 1 - w64Bits |= (lsb << (m_dwWordBitWidth - 1)); + + if (op == IDC_ROR) + { + w64Bits |= (lsb << (m_dwWordBitWidth - 1)); + } + else + { + w64Bits |= (m_carryBit << (m_dwWordBitWidth - 1)); + m_carryBit = lsb; + } result = w64Bits; } @@ -133,6 +151,48 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r } break; + case IDC_SEC: + if (!m_fIntegerMode) + { + result = m_bInv ? ACos(Invert(rat), m_angletype) : Invert(Cos(rat, m_angletype)); + } + break; + + case IDC_CSC: + if (!m_fIntegerMode) + { + result = m_bInv ? ASin(Invert(rat), m_angletype) : Invert(Sin(rat, m_angletype)); + } + break; + + case IDC_COT: + if (!m_fIntegerMode) + { + result = m_bInv ? ATan(Invert(rat), m_angletype) : Invert(Tan(rat, m_angletype)); + } + break; + + case IDC_SECH: + if (!m_fIntegerMode) + { + result = m_bInv ? ACosh(Invert(rat)) : Invert(Cosh(rat)); + } + break; + + case IDC_CSCH: + if (!m_fIntegerMode) + { + result = m_bInv ? ASinh(Invert(rat)) : Invert(Sinh(rat)); + } + break; + + case IDC_COTH: + if (!m_fIntegerMode) + { + result = m_bInv ? ATanh(Invert(rat)) : Invert(Tanh(rat)); + } + break; + case IDC_REC: /* Reciprocal. */ result = Invert(rat); break; @@ -158,6 +218,10 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r result = Pow(10, rat); break; + case IDC_POW2: + result = Pow(2, rat); + break; + case IDC_LN: /* Functions for natural log. */ result = m_bInv ? Exp(rat) : Log(rat); break; @@ -202,6 +266,18 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r } break; } + case IDC_CEIL: + result = (Frac(rat) > 0) ? Integer(rat + 1) : Integer(rat); + break; + + case IDC_FLOOR: + result = (Frac(rat) < 0) ? Integer(rat - 1 ) : Integer(rat); + break; + + case IDC_ABS: + result = Abs(rat); + break; + } // end switch( op ) } catch (uint32_t nErrCode) diff --git a/src/CalcManager/CEngine/scioper.cpp b/src/CalcManager/CEngine/scioper.cpp index e41aee2..6ea3956 100644 --- a/src/CalcManager/CEngine/scioper.cpp +++ b/src/CalcManager/CEngine/scioper.cpp @@ -28,6 +28,14 @@ CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rationa result ^= rhs; break; + case IDC_NAND: + result = (result & rhs) ^ m_chopNumbers[m_numwidth]; + break; + + case IDC_NOR: + result = (result | rhs) ^ m_chopNumbers[m_numwidth]; + break; + case IDC_RSHF: { if (m_fIntegerMode && result >= m_dwWordBitWidth) // Lsh/Rsh >= than current word size is always 0 @@ -52,7 +60,16 @@ CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rationa } break; } + case IDC_RSHFL: + { + if (m_fIntegerMode && result >= m_dwWordBitWidth) // Lsh/Rsh >= than current word size is always 0 + { + throw CALC_E_NORESULT; + } + result = rhs >> result; + break; + } case IDC_LSHF: if (m_fIntegerMode && result >= m_dwWordBitWidth) // Lsh/Rsh >= than current word size is always 0 { @@ -140,6 +157,10 @@ CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rationa case IDC_ROOT: // Calculates rhs to the result(th) root. result = Root(rhs, result); break; + + case IDC_LOGBASEX: + result = (Log(result) / Log(rhs)); + break; } } catch (uint32_t dwErrCode) diff --git a/src/CalcManager/CalculatorManager.cpp b/src/CalcManager/CalculatorManager.cpp index 71eebd2..81c6628 100644 --- a/src/CalcManager/CalculatorManager.cpp +++ b/src/CalcManager/CalculatorManager.cpp @@ -75,6 +75,11 @@ namespace CalculationManager m_displayCallback->MemoryItemChanged(indexOfMemory); } + void CalculatorManager::InputChanged() + { + m_displayCallback->InputChanged(); + } + /// /// Call the callback function using passed in IDisplayHelper. /// Used to set the expression display value on ViewModel @@ -240,6 +245,7 @@ namespace CalculationManager m_savedCommands.push_back(MapCommandForSerialize(command)); } m_savedDegreeMode = m_currentDegreeMode; + InputChanged(); return; } @@ -283,6 +289,30 @@ namespace CalculationManager m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandTANH)); break; + case Command::CommandASEC: + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandSEC)); + break; + case Command::CommandACSC: + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandCSC)); + break; + case Command::CommandACOT: + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandCOT)); + break; + case Command::CommandASECH: + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandSECH)); + break; + case Command::CommandACSCH: + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandCSCH)); + break; + case Command::CommandACOTH: + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandCOTH)); + break; case Command::CommandFE: m_isExponentialFormat = !m_isExponentialFormat; [[fallthrough]]; @@ -290,6 +320,8 @@ namespace CalculationManager m_currentCalculatorEngine->ProcessCommand(static_cast(command)); break; } + + InputChanged(); } /// @@ -330,6 +362,7 @@ namespace CalculationManager { m_currentCalculatorEngine->PersistedMemObject(m_persistedPrimaryValue); m_currentCalculatorEngine->ProcessCommand(IDC_RECALL); + InputChanged(); } /// @@ -376,6 +409,7 @@ namespace CalculationManager this->MemorizedNumberSelect(indexOfMemory); m_currentCalculatorEngine->ProcessCommand(IDC_RECALL); + InputChanged(); } /// @@ -638,6 +672,11 @@ namespace CalculationManager return m_currentCalculatorEngine->FInRecordingState() ? true : false; } + bool CalculatorManager::IsInputEmpty() + { + return m_currentCalculatorEngine->IsInputEmpty(); + } + void CalculatorManager::SetInHistoryItemLoadMode(_In_ bool isHistoryItemLoadMode) { m_inHistoryItemLoadMode = isHistoryItemLoadMode; diff --git a/src/CalcManager/CalculatorManager.h b/src/CalcManager/CalculatorManager.h index 358c2da..6469da3 100644 --- a/src/CalcManager/CalculatorManager.h +++ b/src/CalcManager/CalculatorManager.h @@ -101,7 +101,7 @@ namespace CalculationManager void MaxDigitsReached() override; void BinaryOperatorReceived() override; void MemoryItemChanged(unsigned int indexOfMemory) override; - + void InputChanged() override; CalculatorManager(ICalcDisplay* displayCallback, IResourceProvider* resourceProvider); void Reset(bool clearMemory = true); @@ -118,6 +118,7 @@ namespace CalculationManager void MemorizedNumberClearAll(); bool IsEngineRecording(); + bool IsInputEmpty(); std::vector GetSavedCommands() { return m_savedCommands; diff --git a/src/CalcManager/Command.h b/src/CalcManager/Command.h index 3dd508e..4331ddf 100644 --- a/src/CalcManager/Command.h +++ b/src/CalcManager/Command.h @@ -97,6 +97,7 @@ namespace CalculationManager CommandROL = 99, CommandROR = 100, CommandCOM = 101, + CommandSIN = 102, CommandCOS = 103, CommandTAN = 104, @@ -151,6 +152,34 @@ namespace CalculationManager CommandINV = 146, CommandSET_RESULT = 147, + CommandSEC = 400, + CommandASEC = 401, + CommandCSC = 402, + CommandACSC = 403, + CommandCOT = 404, + CommandACOT = 405, + + CommandSECH = 406, + CommandASECH = 407, + CommandCSCH = 408, + CommandACSCH = 409, + CommandCOTH = 410, + CommandACOTH = 411, + + CommandPOW2 = 412, // 2 ^ x + CommandAbs = 413, + CommandFloor = 414, + CommandCeil = 415, + CommandROLC = 416, + CommandRORC = 417, + CommandLogBaseX = 500, + CommandNand = 501, + CommandNor = 502, + + CommandRSHFL = 505, + CommandRand = 600, + CommandEuler = 601, + CommandAnd = 86, CommandOR = 87, CommandNot = 101, diff --git a/src/CalcManager/Header Files/CCommand.h b/src/CalcManager/Header Files/CCommand.h index 6366b45..f6d74d2 100644 --- a/src/CalcManager/Header Files/CCommand.h +++ b/src/CalcManager/Header Files/CCommand.h @@ -81,6 +81,7 @@ #define IDC_ROL 99 #define IDC_ROR 100 #define IDC_COM 101 + #define IDC_SIN 102 #define IDC_COS 103 #define IDC_TAN 104 @@ -136,7 +137,44 @@ #define IDC_INV 146 #define IDC_SET_RESULT 147 -#define IDC_LASTCONTROL IDC_SET_RESULT +#define IDC_STRING_MAPPED_VALUES 400 +#define IDC_UNARYEXTENDEDFIRST IDC_STRING_MAPPED_VALUES +#define IDC_SEC 400 // Secant +// 401 reserved for inverse +#define IDC_CSC 402 // Cosecant +// 403 reserved for inverse +#define IDC_COT 404 // Cotangent +// 405 reserved for inverse + +#define IDC_SECH 406 //Hyperbolic Secant +// 407 reserved for inverse +#define IDC_CSCH 408 //Hyperbolic Cosecant +// 409 reserved for inverse +#define IDC_COTH 410 //Hyperbolic Cotangent +// 411 reserved for inverse + +#define IDC_POW2 412 // 2 ^ x +#define IDC_ABS 413 // Absolute Value +#define IDC_FLOOR 414 // Floor +#define IDC_CEIL 415 // Ceiling + +#define IDC_ROLC 416 // Rotate Left Circular +#define IDC_RORC 417 // Rotate Right Circular + +#define IDC_UNARYEXTENDEDLAST IDC_RORC + +#define IDC_LASTCONTROL IDC_CEIL + +#define IDC_BINARYEXTENDEDFIRST 500 +#define IDC_LOGBASEX 500 // logx(y) +#define IDC_NAND 501 // Nand +#define IDC_NOR 502 // Nor + +#define IDC_RSHFL 505 //Right Shift Logical +#define IDC_BINARYEXTENDEDLAST IDC_RSHFL + +#define IDC_RAND 600 // Random +#define IDC_EULER 601 // e Constant #define IDC_BINEDITSTART 700 #define IDC_BINPOS0 700 diff --git a/src/CalcManager/Header Files/CalcEngine.h b/src/CalcManager/Header Files/CalcEngine.h index 2444185..1a739af 100644 --- a/src/CalcManager/Header Files/CalcEngine.h +++ b/src/CalcManager/Header Files/CalcEngine.h @@ -14,6 +14,7 @@ * \****************************************************************************/ +#include #include "CCommand.h" #include "EngineStrings.h" #include "../Command.h" @@ -68,6 +69,10 @@ public: { return m_bError; } + bool IsInputEmpty() + { + return m_input.IsEmpty() && (m_numberString.empty() || m_numberString == L"0"); + } bool FInRecordingState() { return m_bRecord; @@ -103,6 +108,7 @@ public: return GetString(IdStrFromCmdId(nOpCode)); } static std::wstring_view OpCodeToUnaryString(int nOpCode, bool fInv, ANGLE_TYPE angletype); + static std::wstring_view OpCodeToBinaryString(int nOpCode, bool isIntegerMode); private: bool m_fPrecedence; @@ -147,6 +153,11 @@ private: NUM_WIDTH m_numwidth; // one of qword, dword, word or byte mode. int32_t m_dwWordBitWidth; // # of bits in currently selected word size + std::unique_ptr m_randomGeneratorEngine; + std::unique_ptr> m_distr; + + uint64_t m_carryBit; + CHistoryCollector m_HistoryCollector; // Accumulator of each line of history as various commands are processed std::array m_chopNumbers; // word size enforcement @@ -171,6 +182,7 @@ private: void SetRadixTypeAndNumWidth(RADIX_TYPE radixtype, NUM_WIDTH numwidth); int32_t DwWordBitWidthFromeNumWidth(NUM_WIDTH numwidth); uint32_t NRadixFromRadixType(RADIX_TYPE radixtype); + double GenerateRandomNumber(); bool TryToggleBit(CalcEngine::Rational& rat, uint32_t wbitno); void CheckAndAddLastBinOpToHistory(bool addToHistory = true); diff --git a/src/CalcManager/Header Files/CalcInput.h b/src/CalcManager/Header Files/CalcInput.h index 045cdb8..b798d06 100644 --- a/src/CalcManager/Header Files/CalcInput.h +++ b/src/CalcManager/Header Files/CalcInput.h @@ -66,6 +66,7 @@ namespace CalcEngine bool TryBeginExponent(); void Backspace(); void SetDecimalSymbol(wchar_t decSymbol); + bool IsEmpty(); std::wstring ToString(uint32_t radix); Rational ToRational(uint32_t radix, int32_t precision); diff --git a/src/CalcManager/Header Files/EngineStrings.h b/src/CalcManager/Header Files/EngineStrings.h index fffebf0..958c828 100644 --- a/src/CalcManager/Header Files/EngineStrings.h +++ b/src/CalcManager/Header Files/EngineStrings.h @@ -87,7 +87,6 @@ inline constexpr auto SIDS_XPOW3 = L"32"; inline constexpr auto SIDS_NFACTORIAL = L"33"; inline constexpr auto SIDS_RECIPROCAL = L"34"; inline constexpr auto SIDS_DMS = L"35"; -inline constexpr auto SIDS_CUBEROOT = L"36"; inline constexpr auto SIDS_POWTEN = L"37"; inline constexpr auto SIDS_PERCENT = L"38"; inline constexpr auto SIDS_SCIENTIFIC_NOTATION = L"39"; @@ -172,125 +171,193 @@ inline constexpr auto SIDS_ERR_UNEX_END = L"117"; inline constexpr auto SIDS_ERR_SG_INV_ERROR = L"118"; inline constexpr auto SIDS_ERR_INPUT_OVERFLOW = L"119"; inline constexpr auto SIDS_ERR_OUTPUT_OVERFLOW = L"120"; +inline constexpr auto SIDS_SECD = L"SecDeg"; +inline constexpr auto SIDS_SECR = L"SecRad"; +inline constexpr auto SIDS_SECG = L"SecGrad"; +inline constexpr auto SIDS_ASECD = L"InverseSecDeg"; +inline constexpr auto SIDS_ASECR = L"InverseSecRad"; +inline constexpr auto SIDS_ASECG = L"InverseSecGrad"; +inline constexpr auto SIDS_CSCD = L"CscDeg"; +inline constexpr auto SIDS_CSCR = L"CscRad"; +inline constexpr auto SIDS_CSCG = L"CscGrad"; +inline constexpr auto SIDS_ACSCD = L"InverseCscDeg"; +inline constexpr auto SIDS_ACSCR = L"InverseCscRad"; +inline constexpr auto SIDS_ACSCG = L"InverseCscGrad"; +inline constexpr auto SIDS_COTD = L"CotDeg"; +inline constexpr auto SIDS_COTR = L"CotRad"; +inline constexpr auto SIDS_COTG = L"CotGrad"; +inline constexpr auto SIDS_ACOTD = L"InverseCotDeg"; +inline constexpr auto SIDS_ACOTR = L"InverseCotRad"; +inline constexpr auto SIDS_ACOTG = L"InverseCotGrad"; +inline constexpr auto SIDS_SECH = L"Sech"; +inline constexpr auto SIDS_ASECH = L"InverseSech"; +inline constexpr auto SIDS_CSCH = L"Csch"; +inline constexpr auto SIDS_ACSCH = L"InverseCsch"; +inline constexpr auto SIDS_COTH = L"Coth"; +inline constexpr auto SIDS_ACOTH = L"InverseCoth"; +inline constexpr auto SIDS_TWOPOWX = L"TwoPowX"; +inline constexpr auto SIDS_LOGBASEX = L"LogBaseX"; +inline constexpr auto SIDS_ABS = L"Abs"; +inline constexpr auto SIDS_FLOOR = L"Floor"; +inline constexpr auto SIDS_CEIL = L"Ceil"; +inline constexpr auto SIDS_NAND = L"Nand"; +inline constexpr auto SIDS_NOR = L"Nor"; +inline constexpr auto SIDS_CUBEROOT = L"CubeRoot"; +inline constexpr auto SIDS_PROGRAMMER_MOD = L"ProgrammerMod"; // Include the resource key ID from above into this vector to load it into memory for the engine to use -inline constexpr std::array g_sids = { SIDS_PLUS_MINUS, - SIDS_C, - SIDS_CE, - SIDS_BACKSPACE, - SIDS_DECIMAL_SEPARATOR, - SIDS_EMPTY_STRING, - SIDS_AND, - SIDS_OR, - SIDS_XOR, - SIDS_LSH, - SIDS_RSH, - SIDS_DIVIDE, - SIDS_MULTIPLY, - SIDS_PLUS, - SIDS_MINUS, - SIDS_MOD, - SIDS_YROOT, - SIDS_POW_HAT, - SIDS_INT, - SIDS_ROL, - SIDS_ROR, - SIDS_NOT, - SIDS_SIN, - SIDS_COS, - SIDS_TAN, - SIDS_SINH, - SIDS_COSH, - SIDS_TANH, - SIDS_LN, - SIDS_LOG, - SIDS_SQRT, - SIDS_XPOW2, - SIDS_XPOW3, - SIDS_NFACTORIAL, - SIDS_RECIPROCAL, - SIDS_DMS, - SIDS_CUBEROOT, - SIDS_POWTEN, - SIDS_PERCENT, - SIDS_SCIENTIFIC_NOTATION, - SIDS_PI, - SIDS_EQUAL, - SIDS_MC, - SIDS_MR, - SIDS_MS, - SIDS_MPLUS, - SIDS_MMINUS, - SIDS_EXP, - SIDS_OPEN_PAREN, - SIDS_CLOSE_PAREN, - SIDS_0, - SIDS_1, - SIDS_2, - SIDS_3, - SIDS_4, - SIDS_5, - SIDS_6, - SIDS_7, - SIDS_8, - SIDS_9, - SIDS_A, - SIDS_B, - SIDS_C, - SIDS_D, - SIDS_E, - SIDS_F, - SIDS_FRAC, - SIDS_SIND, - SIDS_COSD, - SIDS_TAND, - SIDS_ASIND, - SIDS_ACOSD, - SIDS_ATAND, - SIDS_SINR, - SIDS_COSR, - SIDS_TANR, - SIDS_ASINR, - SIDS_ACOSR, - SIDS_ATANR, - SIDS_SING, - SIDS_COSG, - SIDS_TANG, - SIDS_ASING, - SIDS_ACOSG, - SIDS_ATANG, - SIDS_ASINH, - SIDS_ACOSH, - SIDS_ATANH, - SIDS_POWE, - SIDS_POWTEN2, - SIDS_SQRT2, - SIDS_SQR, - SIDS_CUBE, - SIDS_CUBERT, - SIDS_FACT, - SIDS_RECIPROC, - SIDS_DEGREES, - SIDS_NEGATE, - SIDS_RSH, - SIDS_DIVIDEBYZERO, - SIDS_DOMAIN, - SIDS_UNDEFINED, - SIDS_POS_INFINITY, - SIDS_NEG_INFINITY, - SIDS_ABORTED, - SIDS_NOMEM, - SIDS_TOOMANY, - SIDS_OVERFLOW, - SIDS_NORESULT, - SIDS_INSUFFICIENT_DATA, - SIDS_ERR_UNK_CH, - SIDS_ERR_UNK_FN, - SIDS_ERR_UNEX_NUM, - SIDS_ERR_UNEX_CH, - SIDS_ERR_UNEX_SZ, - SIDS_ERR_MISMATCH_CLOSE, - SIDS_ERR_UNEX_END, - SIDS_ERR_SG_INV_ERROR, - SIDS_ERR_INPUT_OVERFLOW, - SIDS_ERR_OUTPUT_OVERFLOW }; +inline constexpr std::array g_sids = +{ + SIDS_PLUS_MINUS, + SIDS_C, + SIDS_CE, + SIDS_BACKSPACE, + SIDS_DECIMAL_SEPARATOR, + SIDS_EMPTY_STRING, + SIDS_AND, + SIDS_OR, + SIDS_XOR, + SIDS_LSH, + SIDS_RSH, + SIDS_DIVIDE, + SIDS_MULTIPLY, + SIDS_PLUS, + SIDS_MINUS, + SIDS_MOD, + SIDS_YROOT, + SIDS_POW_HAT, + SIDS_INT, + SIDS_ROL, + SIDS_ROR, + SIDS_NOT, + SIDS_SIN, + SIDS_COS, + SIDS_TAN, + SIDS_SINH, + SIDS_COSH, + SIDS_TANH, + SIDS_LN, + SIDS_LOG, + SIDS_SQRT, + SIDS_XPOW2, + SIDS_XPOW3, + SIDS_NFACTORIAL, + SIDS_RECIPROCAL, + SIDS_DMS, + SIDS_POWTEN, + SIDS_PERCENT, + SIDS_SCIENTIFIC_NOTATION, + SIDS_PI, + SIDS_EQUAL, + SIDS_MC, + SIDS_MR, + SIDS_MS, + SIDS_MPLUS, + SIDS_MMINUS, + SIDS_EXP, + SIDS_OPEN_PAREN, + SIDS_CLOSE_PAREN, + SIDS_0, + SIDS_1, + SIDS_2, + SIDS_3, + SIDS_4, + SIDS_5, + SIDS_6, + SIDS_7, + SIDS_8, + SIDS_9, + SIDS_A, + SIDS_B, + SIDS_C, + SIDS_D, + SIDS_E, + SIDS_F, + SIDS_FRAC, + SIDS_SIND, + SIDS_COSD, + SIDS_TAND, + SIDS_ASIND, + SIDS_ACOSD, + SIDS_ATAND, + SIDS_SINR, + SIDS_COSR, + SIDS_TANR, + SIDS_ASINR, + SIDS_ACOSR, + SIDS_ATANR, + SIDS_SING, + SIDS_COSG, + SIDS_TANG, + SIDS_ASING, + SIDS_ACOSG, + SIDS_ATANG, + SIDS_ASINH, + SIDS_ACOSH, + SIDS_ATANH, + SIDS_POWE, + SIDS_POWTEN2, + SIDS_SQRT2, + SIDS_SQR, + SIDS_CUBE, + SIDS_CUBERT, + SIDS_FACT, + SIDS_RECIPROC, + SIDS_DEGREES, + SIDS_NEGATE, + SIDS_RSH, + SIDS_DIVIDEBYZERO, + SIDS_DOMAIN, + SIDS_UNDEFINED, + SIDS_POS_INFINITY, + SIDS_NEG_INFINITY, + SIDS_ABORTED, + SIDS_NOMEM, + SIDS_TOOMANY, + SIDS_OVERFLOW, + SIDS_NORESULT, + SIDS_INSUFFICIENT_DATA, + SIDS_ERR_UNK_CH, + SIDS_ERR_UNK_FN, + SIDS_ERR_UNEX_NUM, + SIDS_ERR_UNEX_CH, + SIDS_ERR_UNEX_SZ, + SIDS_ERR_MISMATCH_CLOSE, + SIDS_ERR_UNEX_END, + SIDS_ERR_SG_INV_ERROR, + SIDS_ERR_INPUT_OVERFLOW, + SIDS_ERR_OUTPUT_OVERFLOW, + SIDS_SECD, + SIDS_SECG, + SIDS_SECR, + SIDS_ASECD, + SIDS_ASECR, + SIDS_ASECG, + SIDS_CSCD, + SIDS_CSCR, + SIDS_CSCG, + SIDS_ACSCD, + SIDS_ACSCR, + SIDS_ACSCG, + SIDS_COTD, + SIDS_COTR, + SIDS_COTG, + SIDS_ACOTD, + SIDS_ACOTR, + SIDS_ACOTG, + SIDS_SECH, + SIDS_ASECH, + SIDS_CSCH, + SIDS_ACSCH, + SIDS_COTH, + SIDS_ACOTH, + SIDS_TWOPOWX, + SIDS_LOGBASEX, + SIDS_ABS, + SIDS_FLOOR, + SIDS_CEIL, + SIDS_NAND, + SIDS_NOR, + SIDS_CUBEROOT, + SIDS_PROGRAMMER_MOD, +}; diff --git a/src/CalcManager/Header Files/History.h b/src/CalcManager/Header Files/History.h index b6d6d8d..3365d98 100644 --- a/src/CalcManager/Header Files/History.h +++ b/src/CalcManager/Header Files/History.h @@ -21,8 +21,8 @@ public: ~CHistoryCollector(); void AddOpndToHistory(std::wstring_view numStr, CalcEngine::Rational const& rat, bool fRepetition = false); void RemoveLastOpndFromHistory(); - void AddBinOpToHistory(int nOpCode, bool fNoRepetition = true); - void ChangeLastBinOp(int nOpCode, bool fPrecInvToHigher); + void AddBinOpToHistory(int nOpCode, bool isIntgerMode, bool fNoRepetition = true); + void ChangeLastBinOp(int nOpCode, bool fPrecInvToHigher, bool isIntgerMode); void AddUnaryOpToHistory(int nOpCode, bool fInv, ANGLE_TYPE angletype); void AddOpenBraceToHistory(); void AddCloseBraceToHistory(); diff --git a/src/CalcManager/Header Files/ICalcDisplay.h b/src/CalcManager/Header Files/ICalcDisplay.h index f4aebec..4e1f62e 100644 --- a/src/CalcManager/Header Files/ICalcDisplay.h +++ b/src/CalcManager/Header Files/ICalcDisplay.h @@ -22,4 +22,5 @@ public: virtual void OnHistoryItemAdded(_In_ unsigned int addedItemIndex) = 0; virtual void SetMemorizedNumbers(const std::vector& memorizedNumbers) = 0; virtual void MemoryItemChanged(unsigned int indexOfMemory) = 0; + virtual void InputChanged() = 0; }; diff --git a/src/CalcManager/pch.h b/src/CalcManager/pch.h index 9207ebf..288bbc9 100644 --- a/src/CalcManager/pch.h +++ b/src/CalcManager/pch.h @@ -22,3 +22,5 @@ #include #include #include +#include +#include diff --git a/src/CalcViewModel/Common/CalculatorDisplay.cpp b/src/CalcViewModel/Common/CalculatorDisplay.cpp index 91892dd..036c51b 100644 --- a/src/CalcViewModel/Common/CalculatorDisplay.cpp +++ b/src/CalcViewModel/Common/CalculatorDisplay.cpp @@ -136,3 +136,14 @@ void CalculatorDisplay::MemoryItemChanged(unsigned int indexOfMemory) } } } + +void CalculatorDisplay::InputChanged() +{ + if (m_callbackReference != nullptr) + { + if (auto calcVM = m_callbackReference.Resolve()) + { + calcVM->OnInputChanged(); + } + } +} diff --git a/src/CalcViewModel/Common/CalculatorDisplay.h b/src/CalcViewModel/Common/CalculatorDisplay.h index 93865c9..dccfc00 100644 --- a/src/CalcViewModel/Common/CalculatorDisplay.h +++ b/src/CalcViewModel/Common/CalculatorDisplay.h @@ -28,6 +28,7 @@ namespace CalculatorApp void MaxDigitsReached() override; void BinaryOperatorReceived() override; void MemoryItemChanged(unsigned int indexOfMemory) override; + void InputChanged() override; private: Platform::WeakReference m_callbackReference; diff --git a/src/CalcViewModel/StandardCalculatorViewModel.cpp b/src/CalcViewModel/StandardCalculatorViewModel.cpp index ca99e31..04f5726 100644 --- a/src/CalcViewModel/StandardCalculatorViewModel.cpp +++ b/src/CalcViewModel/StandardCalculatorViewModel.cpp @@ -1026,6 +1026,11 @@ NumbersAndOperatorsEnum StandardCalculatorViewModel::MapCharacterToButtonId(cons return mappedValue; } +void StandardCalculatorViewModel::OnInputChanged() +{ + IsInputEmpty = m_standardCalculatorManager.IsInputEmpty(); +} + void StandardCalculatorViewModel::OnMemoryButtonPressed() { m_standardCalculatorManager.MemorizeNumber(); diff --git a/src/CalcViewModel/StandardCalculatorViewModel.h b/src/CalcViewModel/StandardCalculatorViewModel.h index c4b693c..d003708 100644 --- a/src/CalcViewModel/StandardCalculatorViewModel.h +++ b/src/CalcViewModel/StandardCalculatorViewModel.h @@ -76,6 +76,7 @@ namespace CalculatorApp OBSERVABLE_PROPERTY_RW(bool, AreAlwaysOnTopResultsUpdated); OBSERVABLE_PROPERTY_RW(bool, AreHistoryShortcutsEnabled); OBSERVABLE_PROPERTY_RW(bool, AreProgrammerRadixOperatorsEnabled); + OBSERVABLE_PROPERTY_RW(bool, IsInputEmpty); OBSERVABLE_PROPERTY_RW(CalculatorApp::Common::Automation::NarratorAnnouncement ^, Announcement); OBSERVABLE_PROPERTY_R(unsigned int, OpenParenthesisCount); @@ -122,13 +123,8 @@ namespace CalculatorApp } } } - static property Platform::String ^ IsBitFlipCheckedPropertyName - { - Platform::String ^ get() - { - return Platform::StringReference(L"IsBitFlipChecked"); - } - } + static property Platform::String + ^ IsBitFlipCheckedPropertyName { Platform::String ^ get() { return Platform::StringReference(L"IsBitFlipChecked"); } } property bool IsBinaryBitFlippingEnabled { @@ -223,13 +219,8 @@ namespace CalculatorApp } } } - static property Platform::String ^ IsProgrammerPropertyName - { - Platform::String ^ get() - { - return Platform::StringReference(L"IsProgrammer"); - } - } + static property Platform::String + ^ IsProgrammerPropertyName { Platform::String ^ get() { return Platform::StringReference(L"IsProgrammer"); } } property bool IsAlwaysOnTop { @@ -365,6 +356,7 @@ namespace CalculatorApp void OnMemoryClear(_In_ Platform::Object ^ memoryItemPosition); void OnPinUnpinCommand(Platform::Object ^ parameter); + void OnInputChanged(); void SetPrimaryDisplay(_In_ std::wstring const& displayString, _In_ bool isError); void DisplayPasteError(); void SetTokens(_Inout_ std::shared_ptr>> const& tokens); diff --git a/src/Calculator/Resources/en-US/CEngineStrings.resw b/src/Calculator/Resources/en-US/CEngineStrings.resw index 17f8a14..0cea3ad 100644 --- a/src/Calculator/Resources/en-US/CEngineStrings.resw +++ b/src/Calculator/Resources/en-US/CEngineStrings.resw @@ -1,4 +1,4 @@ - +