calculator/src/Calculator/Views/CalculatorProgrammerBitFlipPanel.xaml.cpp

223 lines
7.4 KiB
C++

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// CalculatorProgrammerBitFlipPanel.xaml.cpp
// Implementation of the CalculatorProgrammerBitFlipPanel class
//
#include "pch.h"
#include "CalculatorProgrammerBitFlipPanel.xaml.h"
#include "CalcViewModel/Common/TraceLogger.h"
#include "CalcViewModel/Common/LocalizationSettings.h"
#include "Converters/BooleanToVisibilityConverter.h"
using namespace CalculatorApp;
using namespace CalculatorApp::Common;
using namespace CalculatorApp::Controls;
using namespace CalculatorApp::ViewModel;
using namespace Platform;
using namespace std;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Input;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
CalculatorProgrammerBitFlipPanel::CalculatorProgrammerBitFlipPanel() :
m_updatingCheckedStates(false)
{
InitializeComponent();
auto booleanToVisibilityConverter = ref new Converters::BooleanToVisibilityConverter;
SetVisibilityBinding(BitFlipPanel, L"IsBinaryBitFlippingEnabled", booleanToVisibilityConverter);
AssignFlipButtons();
}
void CalculatorProgrammerBitFlipPanel::OnLoaded(Object^ sender, RoutedEventArgs^ e)
{
UnsubscribePropertyChanged();
SubscribePropertyChanged();
}
void CalculatorProgrammerBitFlipPanel::OnUnloaded(Object^ sender, RoutedEventArgs^ e)
{
UnsubscribePropertyChanged();
}
void CalculatorProgrammerBitFlipPanel::SubscribePropertyChanged()
{
if (Model != nullptr)
{
m_propertyChangedToken =
Model->PropertyChanged += ref new PropertyChangedEventHandler(this, &CalculatorProgrammerBitFlipPanel::OnPropertyChanged);
UpdateCheckedStates();
}
}
void CalculatorProgrammerBitFlipPanel::UnsubscribePropertyChanged()
{
if (Model != nullptr && m_propertyChangedToken.Value != 0)
{
Model->PropertyChanged -= m_propertyChangedToken;
m_propertyChangedToken.Value = 0;
}
}
void CalculatorProgrammerBitFlipPanel::OnPropertyChanged(Object^ sender, PropertyChangedEventArgs^ e)
{
if (e->PropertyName == StandardCalculatorViewModel::BinaryDisplayValuePropertyName)
{
UpdateCheckedStates();
}
}
StandardCalculatorViewModel^ CalculatorProgrammerBitFlipPanel::Model::get()
{
return static_cast<StandardCalculatorViewModel^>(this->DataContext);
}
void CalculatorProgrammerBitFlipPanel::AssignFlipButtons()
{
assert(m_flipButtons.size() == 64);
m_flipButtons[0] = this->Bit0;
m_flipButtons[1] = this->Bit1;
m_flipButtons[2] = this->Bit2;
m_flipButtons[3] = this->Bit3;
m_flipButtons[4] = this->Bit4;
m_flipButtons[5] = this->Bit5;
m_flipButtons[6] = this->Bit6;
m_flipButtons[7] = this->Bit7;
m_flipButtons[8] = this->Bit8;
m_flipButtons[9] = this->Bit9;
m_flipButtons[10] = this->Bit10;
m_flipButtons[11] = this->Bit11;
m_flipButtons[12] = this->Bit12;
m_flipButtons[13] = this->Bit13;
m_flipButtons[14] = this->Bit14;
m_flipButtons[15] = this->Bit15;
m_flipButtons[16] = this->Bit16;
m_flipButtons[17] = this->Bit17;
m_flipButtons[18] = this->Bit18;
m_flipButtons[19] = this->Bit19;
m_flipButtons[20] = this->Bit20;
m_flipButtons[21] = this->Bit21;
m_flipButtons[22] = this->Bit22;
m_flipButtons[23] = this->Bit23;
m_flipButtons[24] = this->Bit24;
m_flipButtons[25] = this->Bit25;
m_flipButtons[26] = this->Bit26;
m_flipButtons[27] = this->Bit27;
m_flipButtons[28] = this->Bit28;
m_flipButtons[29] = this->Bit29;
m_flipButtons[30] = this->Bit30;
m_flipButtons[31] = this->Bit31;
m_flipButtons[32] = this->Bit32;
m_flipButtons[33] = this->Bit33;
m_flipButtons[34] = this->Bit34;
m_flipButtons[35] = this->Bit35;
m_flipButtons[36] = this->Bit36;
m_flipButtons[37] = this->Bit37;
m_flipButtons[38] = this->Bit38;
m_flipButtons[39] = this->Bit39;
m_flipButtons[40] = this->Bit40;
m_flipButtons[41] = this->Bit41;
m_flipButtons[42] = this->Bit42;
m_flipButtons[43] = this->Bit43;
m_flipButtons[44] = this->Bit44;
m_flipButtons[45] = this->Bit45;
m_flipButtons[46] = this->Bit46;
m_flipButtons[47] = this->Bit47;
m_flipButtons[48] = this->Bit48;
m_flipButtons[49] = this->Bit49;
m_flipButtons[50] = this->Bit50;
m_flipButtons[51] = this->Bit51;
m_flipButtons[52] = this->Bit52;
m_flipButtons[53] = this->Bit53;
m_flipButtons[54] = this->Bit54;
m_flipButtons[55] = this->Bit55;
m_flipButtons[56] = this->Bit56;
m_flipButtons[57] = this->Bit57;
m_flipButtons[58] = this->Bit58;
m_flipButtons[59] = this->Bit59;
m_flipButtons[60] = this->Bit60;
m_flipButtons[61] = this->Bit61;
m_flipButtons[62] = this->Bit62;
m_flipButtons[63] = this->Bit63;
}
void CalculatorProgrammerBitFlipPanel::SetVisibilityBinding(_In_ FrameworkElement^ element, _In_ String^ path, _In_ IValueConverter^ converter)
{
Binding^ commandBinding = ref new Binding();
commandBinding->Path = ref new PropertyPath(path);
commandBinding->Converter = converter;
element->SetBinding(VisibilityProperty, commandBinding);
}
void CalculatorProgrammerBitFlipPanel::OnBitToggled(_In_ Object^ sender, _In_ RoutedEventArgs^ e)
{
if (m_updatingCheckedStates) { return; }
// Handle this the bit toggled event only if it is coming from BitFlip mode.
// Any input from the Numpad may also result in toggling the bit as their state is bound to the BinaryDisplayValue.
// Also, if the mode is switched to other Calculator modes when the BitFlip panel is open,
// a race condition exists in which the IsProgrammerMode property is still true and the UpdatePrimaryResult() is called,
// which continuously alters the Display Value and the state of the Bit Flip buttons.
if ((Model->IsBitFlipChecked)
&& Model->IsProgrammer)
{
TraceLogger::GetInstance().LogBitFlipUsed();
auto flipButton = static_cast<FlipButtons^>(sender);
Model->ButtonPressed->Execute(flipButton->ButtonId);
}
}
void CalculatorProgrammerBitFlipPanel::UpdateCheckedStates()
{
assert(!m_updatingCheckedStates);
assert(m_flipButtons.size() == s_numBits);
if (Model == nullptr) { return; }
static const wchar_t ch0 = LocalizationSettings::GetInstance().GetDigitSymbolFromEnUsDigit(L'0');
// Filter any unwanted characters from the displayed string.
static constexpr array<wchar_t, 4> unwantedChars = {
L' ',
Utils::LRE,
Utils::PDF,
Utils::LRO
};
wstringstream stream;
wstring displayValue = Model->BinaryDisplayValue->Data();
for (const wchar_t& c : displayValue)
{
if (find(begin(unwantedChars), end(unwantedChars), c) == unwantedChars.end())
{
stream << c;
}
}
wstring rawDisplay = stream.str();
size_t paddingCount = s_numBits - rawDisplay.length();
wstring setBits = wstring(paddingCount, ch0) + rawDisplay;
assert(setBits.length() == s_numBits);
m_updatingCheckedStates = true;
for (unsigned int bitIndex = 0; bitIndex < s_numBits; bitIndex++)
{
// Highest bit (64) is at index 0 in bit string.
// To get bit 0, grab from opposite end of string.
wchar_t bit = setBits[s_numBits - bitIndex - 1];
m_flipButtons[bitIndex]->IsChecked = (bit != ch0);
}
m_updatingCheckedStates = false;
}