380 lines
15 KiB
C++
380 lines
15 KiB
C++
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// Licensed under the MIT License.
|
|
|
|
#include "pch.h"
|
|
#include "NavCategory.h"
|
|
#include "AppResourceProvider.h"
|
|
#include "Common/LocalizationStringUtil.h"
|
|
|
|
using namespace CalculatorApp;
|
|
using namespace CalculatorApp::Common;
|
|
using namespace Platform;
|
|
using namespace Platform::Collections;
|
|
using namespace std;
|
|
using namespace Windows::Foundation::Collections;
|
|
|
|
namespace UCM = UnitConversionManager;
|
|
|
|
// Calculator categories always support negative and positive.
|
|
static constexpr bool SUPPORTS_ALL = true;
|
|
|
|
// Converter categories usually only support positive.
|
|
static constexpr bool SUPPORTS_NEGATIVE = true;
|
|
static constexpr bool POSITIVE_ONLY = false;
|
|
|
|
// The order of items in this list determines the order of groups in the menu.
|
|
static constexpr array<const NavCategoryGroupInitializer, 2> s_categoryGroupManifest = {
|
|
NavCategoryGroupInitializer { CategoryGroupType::Calculator, L"CalculatorModeTextCaps", L"CalculatorModeText", L"CalculatorModePluralText"},
|
|
NavCategoryGroupInitializer { CategoryGroupType::Converter, L"ConverterModeTextCaps", L"ConverterModeText", L"ConverterModePluralText" }
|
|
};
|
|
|
|
// vvv THESE CONSTANTS SHOULD NEVER CHANGE vvv
|
|
static constexpr int STANDARD_ID = 0;
|
|
static constexpr int SCIENTIFIC_ID = 1;
|
|
static constexpr int PROGRAMMER_ID = 2;
|
|
static constexpr int DATE_ID = 3;
|
|
static constexpr int VOLUME_ID = 4;
|
|
static constexpr int LENGTH_ID = 5;
|
|
static constexpr int WEIGHT_ID = 6;
|
|
static constexpr int TEMPERATURE_ID = 7;
|
|
static constexpr int ENERGY_ID = 8;
|
|
static constexpr int AREA_ID = 9;
|
|
static constexpr int SPEED_ID = 10;
|
|
static constexpr int TIME_ID = 11;
|
|
static constexpr int POWER_ID = 12;
|
|
static constexpr int DATA_ID = 13;
|
|
static constexpr int PRESSURE_ID = 14;
|
|
static constexpr int ANGLE_ID = 15;
|
|
static constexpr int CURRENCY_ID = 16;
|
|
// ^^^ THESE CONSTANTS SHOULD NEVER CHANGE ^^^
|
|
|
|
// The order of items in this list determines the order of items in the menu.
|
|
static constexpr array<const NavCategoryInitializer, 17> s_categoryManifest = {
|
|
NavCategoryInitializer { ViewMode::Standard, STANDARD_ID, L"Standard", L"StandardMode", L"\uE8EF", CategoryGroupType::Calculator, MyVirtualKey::Number1, SUPPORTS_ALL },
|
|
NavCategoryInitializer { ViewMode::Scientific, SCIENTIFIC_ID, L"Scientific", L"ScientificMode", L"\uF196", CategoryGroupType::Calculator, MyVirtualKey::Number2, SUPPORTS_ALL },
|
|
NavCategoryInitializer { ViewMode::Programmer, PROGRAMMER_ID, L"Programmer", L"ProgrammerMode", L"\uECCE", CategoryGroupType::Calculator, MyVirtualKey::Number3, SUPPORTS_ALL },
|
|
NavCategoryInitializer { ViewMode::Date, DATE_ID, L"Date", L"DateCalculationMode", L"\uE787", CategoryGroupType::Calculator, MyVirtualKey::Number4, SUPPORTS_ALL },
|
|
NavCategoryInitializer { ViewMode::Currency, CURRENCY_ID, L"Currency", L"CategoryName_Currency", L"\uEB0D", CategoryGroupType::Converter, MyVirtualKey::None, POSITIVE_ONLY },
|
|
NavCategoryInitializer { ViewMode::Volume, VOLUME_ID, L"Volume", L"CategoryName_Volume", L"\uF1AA", CategoryGroupType::Converter, MyVirtualKey::None, POSITIVE_ONLY },
|
|
NavCategoryInitializer { ViewMode::Length, LENGTH_ID, L"Length", L"CategoryName_Length", L"\uECC6", CategoryGroupType::Converter, MyVirtualKey::None, POSITIVE_ONLY },
|
|
NavCategoryInitializer { ViewMode::Weight, WEIGHT_ID, L"Weight and Mass", L"CategoryName_Weight", L"\uF4C1", CategoryGroupType::Converter, MyVirtualKey::None, POSITIVE_ONLY },
|
|
NavCategoryInitializer { ViewMode::Temperature, TEMPERATURE_ID, L"Temperature", L"CategoryName_Temperature", L"\uE7A3", CategoryGroupType::Converter, MyVirtualKey::None, SUPPORTS_NEGATIVE },
|
|
NavCategoryInitializer { ViewMode::Energy, ENERGY_ID, L"Energy", L"CategoryName_Energy", L"\uECAD", CategoryGroupType::Converter, MyVirtualKey::None, POSITIVE_ONLY },
|
|
NavCategoryInitializer { ViewMode::Area, AREA_ID, L"Area", L"CategoryName_Area", L"\uE809", CategoryGroupType::Converter, MyVirtualKey::None, POSITIVE_ONLY },
|
|
NavCategoryInitializer { ViewMode::Speed, SPEED_ID, L"Speed", L"CategoryName_Speed", L"\uEADA", CategoryGroupType::Converter, MyVirtualKey::None, POSITIVE_ONLY },
|
|
NavCategoryInitializer { ViewMode::Time, TIME_ID, L"Time", L"CategoryName_Time", L"\uE917", CategoryGroupType::Converter, MyVirtualKey::None, POSITIVE_ONLY },
|
|
NavCategoryInitializer { ViewMode::Power, POWER_ID, L"Power", L"CategoryName_Power", L"\uE945", CategoryGroupType::Converter, MyVirtualKey::None, POSITIVE_ONLY },
|
|
NavCategoryInitializer { ViewMode::Data, DATA_ID, L"Data", L"CategoryName_Data", L"\uF20F", CategoryGroupType::Converter, MyVirtualKey::None, POSITIVE_ONLY },
|
|
NavCategoryInitializer { ViewMode::Pressure, PRESSURE_ID, L"Pressure", L"CategoryName_Pressure", L"\uEC4A", CategoryGroupType::Converter, MyVirtualKey::None, POSITIVE_ONLY },
|
|
NavCategoryInitializer { ViewMode::Angle, ANGLE_ID, L"Angle", L"CategoryName_Angle", L"\uF515", CategoryGroupType::Converter, MyVirtualKey::None, POSITIVE_ONLY }
|
|
};
|
|
|
|
// This function should only be used when storing the mode to app data.
|
|
int NavCategory::Serialize(ViewMode mode)
|
|
{
|
|
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest),
|
|
[mode](const NavCategoryInitializer& initializer)
|
|
{
|
|
return initializer.viewMode == mode;
|
|
});
|
|
|
|
return (iter != s_categoryManifest.end())
|
|
? iter->serializationId
|
|
: -1;
|
|
}
|
|
|
|
// This function should only be used when restoring the mode from app data.
|
|
ViewMode NavCategory::Deserialize(Platform::Object^ obj)
|
|
{
|
|
// If we cast directly to ViewMode we will fail
|
|
// because we technically store an int.
|
|
// Need to cast to int, then ViewMode.
|
|
auto boxed = dynamic_cast<Box<int>^>(obj);
|
|
if (boxed != nullptr)
|
|
{
|
|
int serializationId = boxed->Value;
|
|
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest),
|
|
[serializationId](const NavCategoryInitializer& initializer)
|
|
{
|
|
return initializer.serializationId == serializationId;
|
|
});
|
|
|
|
if (iter != s_categoryManifest.end())
|
|
{
|
|
return iter->viewMode;
|
|
}
|
|
}
|
|
|
|
return ViewMode::None;
|
|
}
|
|
|
|
bool NavCategory::IsValidViewMode(ViewMode mode)
|
|
{
|
|
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest),
|
|
[mode](const NavCategoryInitializer& initializer)
|
|
{
|
|
return initializer.viewMode == mode;
|
|
});
|
|
|
|
return iter != s_categoryManifest.end();
|
|
}
|
|
|
|
bool NavCategory::IsCalculatorViewMode(ViewMode mode)
|
|
{
|
|
// Historically, Date Calculator is not a Calculator mode
|
|
// even though it is in the Calculator category.
|
|
return !IsDateCalculatorViewMode(mode) && IsModeInCategoryGroup(mode, CategoryGroupType::Calculator);
|
|
}
|
|
|
|
bool NavCategory::IsDateCalculatorViewMode(ViewMode mode)
|
|
{
|
|
return mode == ViewMode::Date;
|
|
}
|
|
|
|
bool NavCategory::IsConverterViewMode(ViewMode mode)
|
|
{
|
|
return IsModeInCategoryGroup(mode, CategoryGroupType::Converter);
|
|
}
|
|
|
|
bool NavCategory::IsModeInCategoryGroup(ViewMode mode, CategoryGroupType type)
|
|
{
|
|
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest),
|
|
[mode, type](const NavCategoryInitializer& initializer)
|
|
{
|
|
return initializer.viewMode == mode && initializer.groupType == type;
|
|
});
|
|
|
|
return iter != s_categoryManifest.end();
|
|
}
|
|
|
|
String^ NavCategory::GetFriendlyName(ViewMode mode)
|
|
{
|
|
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest),
|
|
[mode](const NavCategoryInitializer& initializer)
|
|
{
|
|
return initializer.viewMode == mode;
|
|
});
|
|
|
|
return (iter != s_categoryManifest.end())
|
|
? StringReference(iter->friendlyName)
|
|
: L"None";
|
|
}
|
|
|
|
ViewMode NavCategory::GetViewModeForFriendlyName(String^ name)
|
|
{
|
|
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest),
|
|
[name](const NavCategoryInitializer& initializer)
|
|
{
|
|
return wcscmp(initializer.friendlyName, name->Data()) == 0;
|
|
});
|
|
|
|
return (iter != s_categoryManifest.end())
|
|
? iter->viewMode
|
|
: ViewMode::None;
|
|
}
|
|
|
|
String^ NavCategory::GetNameResourceKey(ViewMode mode)
|
|
{
|
|
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest),
|
|
[mode](const NavCategoryInitializer& initializer)
|
|
{
|
|
return initializer.viewMode == mode;
|
|
});
|
|
|
|
return (iter != s_categoryManifest.end())
|
|
? StringReference(iter->nameResourceKey) + "Text"
|
|
: nullptr;
|
|
}
|
|
|
|
CategoryGroupType NavCategory::GetGroupType(ViewMode mode)
|
|
{
|
|
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest),
|
|
[mode](const NavCategoryInitializer& initializer)
|
|
{
|
|
return initializer.viewMode == mode;
|
|
});
|
|
|
|
return (iter != s_categoryManifest.end())
|
|
? iter->groupType
|
|
: CategoryGroupType::None;
|
|
}
|
|
|
|
// GetIndex is 0-based, GetPosition is 1-based
|
|
int NavCategory::GetIndex(ViewMode mode)
|
|
{
|
|
int position = NavCategory::GetPosition(mode);
|
|
return max(-1, position - 1);
|
|
}
|
|
|
|
int NavCategory::GetFlatIndex(ViewMode mode)
|
|
{
|
|
int index = -1;
|
|
CategoryGroupType type = CategoryGroupType::None;
|
|
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest),
|
|
[mode, &type, &index](const NavCategoryInitializer& initializer)
|
|
{
|
|
index++;
|
|
if (initializer.groupType != type)
|
|
{
|
|
type = initializer.groupType;
|
|
index++;
|
|
}
|
|
|
|
return initializer.viewMode == mode;
|
|
});
|
|
|
|
return (iter != s_categoryManifest.end())
|
|
? index
|
|
: -1;
|
|
}
|
|
|
|
// GetIndex is 0-based, GetPosition is 1-based
|
|
int NavCategory::GetIndexInGroup(ViewMode mode, CategoryGroupType type)
|
|
{
|
|
int index = -1;
|
|
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest),
|
|
[mode, type, &index](const NavCategoryInitializer& initializer)
|
|
{
|
|
if (initializer.groupType == type)
|
|
{
|
|
index++;
|
|
return initializer.viewMode == mode;
|
|
}
|
|
|
|
return false;
|
|
});
|
|
|
|
return (iter != s_categoryManifest.end())
|
|
? index
|
|
: -1;
|
|
}
|
|
|
|
// GetIndex is 0-based, GetPosition is 1-based
|
|
int NavCategory::GetPosition(ViewMode mode)
|
|
{
|
|
int position = 0;
|
|
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest),
|
|
[mode, &position](const NavCategoryInitializer& initializer)
|
|
{
|
|
position++;
|
|
return initializer.viewMode == mode;
|
|
});
|
|
|
|
return (iter != s_categoryManifest.end())
|
|
? position
|
|
: -1;
|
|
}
|
|
|
|
ViewMode NavCategory::GetViewModeForVirtualKey(MyVirtualKey virtualKey)
|
|
{
|
|
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest),
|
|
[virtualKey](const NavCategoryInitializer& initializer)
|
|
{
|
|
return initializer.virtualKey == virtualKey;
|
|
});
|
|
|
|
return (iter != s_categoryManifest.end())
|
|
? iter->viewMode
|
|
: ViewMode::None;
|
|
}
|
|
|
|
vector<MyVirtualKey> NavCategory::GetCategoryAcceleratorKeys()
|
|
{
|
|
vector<MyVirtualKey> accelerators{};
|
|
for (auto category : s_categoryManifest)
|
|
{
|
|
if (category.virtualKey != MyVirtualKey::None)
|
|
{
|
|
accelerators.push_back(category.virtualKey);
|
|
}
|
|
}
|
|
|
|
return accelerators;
|
|
}
|
|
|
|
NavCategoryGroup::NavCategoryGroup(const NavCategoryGroupInitializer& groupInitializer) :
|
|
m_Categories(ref new Vector<NavCategory^>())
|
|
{
|
|
m_GroupType = groupInitializer.type;
|
|
|
|
auto resProvider = AppResourceProvider::GetInstance();
|
|
String^ headerResourceKey = StringReference(groupInitializer.headerResourceKey);
|
|
String^ modeResourceKey = StringReference(groupInitializer.modeResourceKey);
|
|
String^ automationResourceKey = StringReference(groupInitializer.automationResourceKey);
|
|
m_Name = resProvider.GetResourceString(headerResourceKey);
|
|
String^ groupMode = resProvider.GetResourceString(modeResourceKey);
|
|
String^ automationName = resProvider.GetResourceString(automationResourceKey);
|
|
|
|
String^ navCategoryHeaderAutomationNameFormat = resProvider.GetResourceString(L"NavCategoryHeader_AutomationNameFormat");
|
|
m_AutomationName = ref new String(LocalizationStringUtil::GetLocalizedString(
|
|
navCategoryHeaderAutomationNameFormat->Data(),
|
|
automationName->Data()).c_str());
|
|
|
|
String^ navCategoryItemAutomationNameFormat = resProvider.GetResourceString(L"NavCategoryItem_AutomationNameFormat");
|
|
|
|
for (const NavCategoryInitializer& categoryInitializer : s_categoryManifest)
|
|
{
|
|
if (categoryInitializer.groupType == groupInitializer.type)
|
|
{
|
|
String^ nameResourceKey = StringReference(categoryInitializer.nameResourceKey);
|
|
String^ categoryName = resProvider.GetResourceString(nameResourceKey + "Text");
|
|
String^ categoryAutomationName = ref new String(LocalizationStringUtil::GetLocalizedString(
|
|
navCategoryItemAutomationNameFormat->Data(),
|
|
categoryName->Data(),
|
|
m_Name->Data()).c_str());
|
|
|
|
m_Categories->Append(ref new NavCategory(
|
|
categoryName,
|
|
categoryAutomationName,
|
|
StringReference(categoryInitializer.glyph),
|
|
resProvider.GetResourceString(nameResourceKey + "AccessKey"),
|
|
groupMode,
|
|
categoryInitializer.viewMode,
|
|
categoryInitializer.supportsNegative));
|
|
}
|
|
}
|
|
}
|
|
|
|
IObservableVector<NavCategoryGroup^>^ NavCategoryGroup::CreateMenuOptions()
|
|
{
|
|
auto menuOptions = ref new Vector<NavCategoryGroup^>();
|
|
menuOptions->Append(CreateCalculatorCategory());
|
|
menuOptions->Append(CreateConverterCategory());
|
|
return menuOptions;
|
|
}
|
|
|
|
NavCategoryGroup^ NavCategoryGroup::CreateCalculatorCategory()
|
|
{
|
|
return ref new NavCategoryGroup(s_categoryGroupManifest.at(0));
|
|
}
|
|
|
|
NavCategoryGroup^ NavCategoryGroup::CreateConverterCategory()
|
|
{
|
|
return ref new NavCategoryGroup(s_categoryGroupManifest.at(1));
|
|
}
|
|
|
|
vector<NavCategoryInitializer> NavCategoryGroup::GetInitializerCategoryGroup(CategoryGroupType groupType)
|
|
{
|
|
vector<NavCategoryInitializer> initializers{};
|
|
copy_if(begin(s_categoryManifest), end(s_categoryManifest), back_inserter(initializers),
|
|
[groupType](const NavCategoryInitializer& initializer)
|
|
{
|
|
return initializer.groupType == groupType;
|
|
});
|
|
|
|
return initializers;
|
|
}
|
|
|
|
String^ NavCategoryGroup::GetHeaderResourceKey(CategoryGroupType type)
|
|
{
|
|
auto iter = find_if(begin(s_categoryGroupManifest), end(s_categoryGroupManifest),
|
|
[type](const NavCategoryGroupInitializer& initializer)
|
|
{
|
|
return initializer.type == type;
|
|
});
|
|
|
|
return (iter != s_categoryGroupManifest.end())
|
|
? StringReference(iter->headerResourceKey)
|
|
: nullptr;
|
|
}
|