diff --git a/msvc/wallet.vcxproj b/msvc/wallet.vcxproj
index 41f374e..d4424b6 100644
--- a/msvc/wallet.vcxproj
+++ b/msvc/wallet.vcxproj
@@ -43,19 +43,19 @@
true
- $(SolutionDir)wxWidgets\include\msvc;$(SolutionDir)wxWidgets\include;$(SolutionDir)libsodium\src\libsodium\include;$(SolutionDir)mpir;$(IncludePath)
- $(SolutionDir)wxWidgets\lib\vc_x64_lib\;$(SolutionDir)libsodium\bin\x64\Debug\v143\static;$(SolutionDir)mpir\lib\x64\Debug;$(LibraryPath)
+ ..\wxWidgets\include\msvc;..\wxWidgets\include;..\libsodium\src\libsodium\include;..\mpir;$(IncludePath)
+ ..\wxWidgets\lib\vc_x64_lib\;..\libsodium\bin\x64\Debug\v143\static;..\mpir\lib\x64\Debug;$(LibraryPath)
- $(SolutionDir)build\$(Configuration)\
- $(SolutionDir)build\$(Configuration)\
+ ..\build\$(Configuration)\
+ ..\build\$(Configuration)\
false
- $(SolutionDir)wxWidgets\include\msvc;$(SolutionDir)wxWidgets\include;$(SolutionDir)libsodium\src\libsodium\include;$(SolutionDir)mpir;$(IncludePath)
- $(SolutionDir)wxWidgets\lib\vc_x64_lib\;$(SolutionDir)libsodium\bin\x64\Release\v143\static;$(SolutionDir)mpir\lib\x64\Release;$(LibraryPath)
+ ..\wxWidgets\include\msvc;..\wxWidgets\include;..\libsodium\src\libsodium\include;..\mpir;$(IncludePath)
+ ..\wxWidgets\lib\vc_x64_lib\;..\libsodium\bin\x64\Release\v143\static;..\mpir\lib\x64\Release;$(LibraryPath)
- $(SolutionDir)build\$(Configuration)\
- $(SolutionDir)build\$(Configuration)\
+ ..\build\$(Configuration)\
+ ..\build\$(Configuration)\
@@ -168,7 +168,7 @@
NotUsing
NotUsing
-
+
NotUsing
NotUsing
@@ -193,4 +193,4 @@
-
\ No newline at end of file
+
diff --git a/src/display_wallet.cpp b/src/display_wallet.cpp
index bc2b98b..5fbdadd 100644
--- a/src/display_wallet.cpp
+++ b/src/display_wallet.cpp
@@ -3,8 +3,7 @@ using ro::base58;
static constexpr char SrcFilename[]{ "src/display_wallet.cpp" };
display_wallet::display_wallet(wxWindow* parent, wxFileName& walletfile) :
wxPanel(parent, myID_WALLET_UI, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, wxT("Wallet")),
- m_db(nullptr),
- m_menuitem_add_name(this, &display_wallet::add_name_event_handler)
+ m_db(nullptr), m_DisplayWalletEditMenu(1)
{
wxLogMessage(wxT("Loading %s"), walletfile.GetFullPath());
try {
@@ -73,10 +72,16 @@ display_wallet::display_wallet(wxWindow* parent, wxFileName& walletfile) :
this->SetSize(this->GetParent()->GetClientSize());
singletonFrame->m_LastUsedWallet.Assign(walletfile);
- wxMenu* menuFile{ singletonFrame->GetMenuBar()->GetMenu(0) };
- singletonFrame->GetMenuBar()->EnableTop(1, true); //enable edit menu.
- wxMenu* menuEdit{ singletonFrame->GetMenuBar()->GetMenu(1) };
- m_menuitem_add_name.Insert(menuEdit, 0, "add name", "create new Zooko identity");
+ m_DisplayWalletEditMenu.Menu->Append(
+ myID_DISPLAY_WALLET_ADD_NAME,
+ "add name", "create new Zooko identity"
+ );
+ m_DisplayWalletEditMenu.Menu->Bind(
+ wxEVT_MENU,
+ &display_wallet::add_name_event_handler,
+ this, myID_DISPLAY_WALLET_ADD_NAME
+ );
+ m_DisplayWalletEditMenu.Replace();
}
catch (const MyException&) {
throw;
@@ -91,10 +96,8 @@ display_wallet::display_wallet(wxWindow* parent, wxFileName& walletfile) :
}
-display_wallet::~display_wallet() {
- assert(true);
- singletonFrame->GetMenuBar()->EnableTop(1, false); //disable edit menu.
+display_wallet::~display_wallet() {
}
void display_wallet::close_menu_event_handler(wxCommandEvent& event) {
diff --git a/src/display_wallet.h b/src/display_wallet.h
index 00243fa..0080c5e 100644
--- a/src/display_wallet.h
+++ b/src/display_wallet.h
@@ -14,6 +14,6 @@ private:
wxBoxSizer* m_rSizer;
void close_menu_event_handler(wxCommandEvent&);
void add_name_event_handler(wxCommandEvent&);
- MenuLink m_menuitem_add_name;
void OnClose(wxCloseEvent& event);
+ wxMenuTracker m_DisplayWalletEditMenu;
};
diff --git a/src/frame.cpp b/src/frame.cpp
index fe9ea89..2ac8cb9 100644
--- a/src/frame.cpp
+++ b/src/frame.cpp
@@ -1,6 +1,36 @@
#include "stdafx.h"
static constexpr char SrcFilename[]{ "src/frame.cpp" };
+// ----------------------------------------------------------------------------
+//wxMenuTracker
+// ----------------------------------------------------------------------------
+
+wxMenuTracker::wxMenuTracker(const int i) : Menu(new wxMenu), MenuPosition(i) {};
+
+wxMenu* wxMenuTracker::InitialAndFinal[]{ nullptr, new wxMenu, nullptr };
+
+void wxMenuTracker::Replace() {
+ singletonFrame->GetMenuBar()->Replace(
+ MenuPosition,
+ Menu,
+ menu_strings[MenuPosition].head
+ );
+ singletonFrame->GetMenuBar()->EnableTop(MenuPosition, true); //enable edit menu.
+};
+wxMenuTracker::~wxMenuTracker() {
+ auto menu_bar = singletonFrame->GetMenuBar();
+ if (menu_bar->GetMenu(MenuPosition) == Menu) {
+ assert(InitialAndFinal[MenuPosition]);
+ menu_bar->Replace(
+ MenuPosition,
+ InitialAndFinal[MenuPosition],
+ menu_strings[MenuPosition].head
+ );
+ menu_bar->EnableTop(MenuPosition, false);
+ delete Menu;
+ }
+};
+
// ----------------------------------------------------------------------------
// frame
// ----------------------------------------------------------------------------
@@ -157,18 +187,36 @@ Frame::Frame(const wxString& wxs)
menuFile->Bind(wxEVT_MENU, &Frame::OnDeleteConfiguration, this, myID_DELETECONFIG);
menuFile->Append(wxID_EXIT);
menuFile->Bind(wxEVT_MENU, &Frame::OnExit, this, wxID_EXIT);
-
+
+ wxMenu* menuEdit = wxMenuTracker::InitialAndFinal[1];
wxMenu* menuHelp = new wxMenu;
menuHelp->Append(wxID_ABOUT);
menuHelp->Bind(wxEVT_MENU, &Frame::OnAbout, this, wxID_ABOUT);
wxMenuBar* menuBar = new wxMenuBar;
menuBar->Append(menuFile, menu_strings[0].head);
- menuBar->Append(new wxMenu, menu_strings[1].head); //Edit menu, initially empty and disabled
+ menuBar->Append(menuEdit, menu_strings[1].head); //Edit menu, initially empty and disabled
menuBar->Append(menuHelp, menu_strings[2].head);
SetMenuBar(menuBar);
- CreateStatusBar();
menuBar->EnableTop(1, false); //disable edit menu.
- // child controls
+ if constexpr (debug_mode) {
+ // Check that the initial values of all replaceable menus
+ // are at their default values as if the window handling them
+ // had just been destroyed and not yet replaced.
+ for (int i = 0; i < std::size(wxMenuTracker::InitialAndFinal); i++) {
+ assert(
+ !wxMenuTracker::InitialAndFinal[i]
+ ||
+ (
+ wxMenuTracker::InitialAndFinal[i] == menuBar->GetMenu(i)
+ &&
+ !menuBar->IsEnabledTop(i)
+ )
+ );
+
+ }
+ }
+ CreateStatusBar();
+ // child controls
wxPanel* panel{ nullptr };
m_panel = panel;
wxConfigBase& Config = singletonApp->m_Config;
@@ -374,45 +422,59 @@ COMMIT;
void Frame::OnSaveNew(wxCommandEvent& WXUNUSED(event))
{
- wxString wxstrWalletPath;
- wxString wxstrWalletName(wxEmptyString);
- if (!m_LastUsedWallet.IsOk() || !m_LastUsedWallet.DirExists()) {
- m_LastUsedWallet = m_DefaultWalletLocation;
- RecursiveCreateDirectory(m_LastUsedWallet);
- }
- wxstrWalletPath = m_LastUsedWallet.GetPath(); //Directory guaranteed to exist, so we will not get idiot default
- // It took me a ridiculous amount of time to fix that all paths to this file dialog
- // are either terminated by an exception, or the directory exists, or is created.
- // Any time the program has to deal with something external to itself, anything that can go wrong
- // will go wrong.
- if (!m_LastUsedWallet.FileExists()) wxstrWalletName = m_LastUsedWallet.GetFullName();
- wxFileDialog dialog(this,
- sz_new_wallet_new_secret,
- wxstrWalletPath,
- wxstrWalletName,
- wxString::Format
- ("wallet (*.wallet)|*.wallet|All (%s)|%s",
- wxFileSelectorDefaultWildcardStr,
- wxFileSelectorDefaultWildcardStr
- ),
- wxFD_SAVE | wxFD_OVERWRITE_PROMPT
- );
- dialog.SetFilterIndex(m_FileDialogFilterIndex);
- if (dialog.ShowModal() == wxID_OK)
- {
- wxLogMessage("%s, filter %d",
- dialog.GetPath(),
- dialog.GetFilterIndex()
+ wxFileName wxFileWallet;
+ if (m_DefaultWalletLocation.FileExists()) {
+ // OK, the default wallet exists, so we need a new
+ // name and wallet location
+ wxString wxstrWalletPath;
+ wxString wxstrWalletName(wxEmptyString);
+ if (!m_LastUsedWallet.IsOk() || !m_LastUsedWallet.DirExists()) {
+ m_LastUsedWallet = m_DefaultWalletLocation;
+ RecursiveCreateDirectory(m_LastUsedWallet);
+ }
+ wxstrWalletPath = m_LastUsedWallet.GetPath(); //Directory guaranteed to exist, so we will not get idiot default
+ // It took me a ridiculous amount of time to fix that all paths to this file dialog
+ // are either terminated by an exception, or the directory exists, or is created.
+ // Any time the program has to deal with something external to itself, anything that can go wrong
+ // will go wrong.
+ if (!m_LastUsedWallet.FileExists()) wxstrWalletName = m_LastUsedWallet.GetFullName();
+ wxFileDialog dialog(this,
+ sz_new_wallet_new_secret,
+ wxstrWalletPath,
+ wxstrWalletName,
+ wxString::Format
+ ("wallet (*.wallet)|*.wallet|All (%s)|%s",
+ wxFileSelectorDefaultWildcardStr,
+ wxFileSelectorDefaultWildcardStr
+ ),
+ wxFD_SAVE | wxFD_OVERWRITE_PROMPT
);
- wxFileName wxFileWallet(dialog.GetPath());
- ristretto255::hash<256> WalletSecret( wxFileWallet.GetFullPath().ToUTF8());
+ dialog.SetFilterIndex(m_FileDialogFilterIndex);
+ if (dialog.ShowModal() == wxID_OK)
+ {
+ wxLogMessage("%s, filter %d",
+ dialog.GetPath(),
+ dialog.GetFilterIndex()
+ );
+ wxFileWallet.Assign(dialog.GetPath());
+ m_FileDialogFilterIndex = dialog.GetFilterIndex();
+ }
+ }
+ else {
+ // Default does not exist, so we go right
+ // ahead without asking the user to invent
+ // a name and select a directory
+ RecursiveCreateDirectory(m_DefaultWalletLocation);
+ wxFileWallet = m_DefaultWalletLocation;
+ }
+ if (wxFileWallet.IsOk()) {
+ ristretto255::hash<256> WalletSecret(wxFileWallet.GetFullPath().ToUTF8());
NewWallet(wxFileWallet, WalletSecret);
wxLogMessage("new wallet created: %s", wxFileWallet.GetFullPath());
if (m_panel)m_panel->Close(true);
m_panel = nullptr;
auto panel = new display_wallet(this, wxFileWallet);
m_panel = panel;
- m_FileDialogFilterIndex = dialog.GetFilterIndex();
m_LastUsedWallet = wxFileWallet; //We do this last, so that if an exception occurs the filename is forgotten.
}
}
@@ -497,11 +559,29 @@ Frame::~Frame() {
wxConfigBase& Config = singletonApp->m_Config;
StorePositionToConfig();
Config.SetPath(wxT("/TipOfTheDay"));
- Config.Write("show", (int)m_showTipsAtStartup);
- Config.Write("index", (int)m_TipOfTheDayIndex);
- Config.SetPath(wxT("/FileDialog"));
- Config.Write("index", (int)m_FileDialogFilterIndex);
- Config.Write(wxT("LastUsed"), m_LastUsedWallet.GetFullPath());
- Config.SetPath(wxT("/"));
- Config.Flush();
+ Config.Write("show", (int)m_showTipsAtStartup);
+ Config.Write("index", (int)m_TipOfTheDayIndex);
+ Config.SetPath(wxT("/FileDialog"));
+ Config.Write("index", (int)m_FileDialogFilterIndex);
+ Config.Write(wxT("LastUsed"), m_LastUsedWallet.GetFullPath());
+ Config.SetPath(wxT("/"));
+ Config.Flush();
+ if constexpr (debug_mode) {
+ // Check that the final values of all replaceable menus
+ // are at what they should be because the window handling
+ // them should have been destroyed.
+ auto menuBar = this->GetMenuBar();
+ for (int i = 0; i < std::size(wxMenuTracker::InitialAndFinal); i++) {
+ assert(
+ !wxMenuTracker::InitialAndFinal[i]
+ ||
+ (
+ wxMenuTracker::InitialAndFinal[i] == menuBar->GetMenu(i)
+ &&
+ !menuBar->IsEnabledTop(i)
+ )
+ );
+
+ }
+ }
}
diff --git a/src/frame.h b/src/frame.h
index 056872c..40800b5 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -1,4 +1,39 @@
#pragma once
+ // wxWidgets has drop down menus, wxMenu, owned by the wxMenuBar,
+ // which is owned by the Frame window, but menus subject to replacement need
+ // to be destroyed by the child window.
+ // wxMenuOwner tracks a drop down menu that might be at a location in
+ // the menubar, places it in that location in the menubar on demand,
+ // and on destruction destroys it
+ // If, on destruction wxMenuBar is still pointing to this wxMenu, it
+ // replaces it with the default (empty) menu for that location.
+ // and disables it.
+ // We maintain an array of default empty wxMenu menus that are nullptr for
+ // locations not subject to replacement, and are the disabled initial and final
+ // wxMenuBar values for locations in the Menubar where the real drop down
+ // in the menubar will be installed by wxMenuTracker.
+struct wxMenuTracker {
+ wxMenuTracker(int);
+ void Replace();
+ ~wxMenuTracker() noexcept;
+ // Non nullptr members of InitialAndFinal have to be explicitly initially placed
+ // in the menubar in the frame constructor and explicitly disabled in
+ // the frame initializer. In the debug build, congruence between the menu bar
+ // and InitialAndFinal should be checked with assert.
+ static wxMenu* InitialAndFinal[3];
+ wxMenuTracker(wxMenuTracker&&) = delete; // Move constructor
+ wxMenuTracker(const wxMenuTracker&) = delete; // Copy constructor
+ wxMenuTracker& operator=(wxMenuTracker&&) = delete; // Move assignment.
+ wxMenuTracker& operator=(const wxMenuTracker&) = delete; // Copy assignment.
+ bool operator==(const wxMenuTracker&) const = delete;
+ auto operator<=>(const wxMenuTracker&) const = delete;
+ wxMenu* Menu;
+ const int MenuPosition;
+ // The menu title is defined elsewhere as an array
+ // of const strings
+ // menu_strings[MenuPosition].head
+};
+
template
// This class exists to record the needed to unbind a drop down menu action and delete
// the corresponding item from the drop down menu when the handler is destroyed.
diff --git a/src/stdafx.h b/src/stdafx.h
index fbe0ac1..2e633c2 100644
--- a/src/stdafx.h
+++ b/src/stdafx.h
@@ -106,7 +106,7 @@ enum MyIDs {
myID_DELETECONFIG = wxID_HIGHEST + 1, myID_ERRORMESSAGE, myID_Hello,
myID_MAINFRAME,
myID_MAINFRAME_PANEL, myID_TESTWINDOW, myID_WELCOME_TO_ROCOIN, myID_WALLET_UI,
- mID_CLOSE_WALLET, myID_MYEXIT
+ mID_CLOSE_WALLET, myID_MYEXIT, myID_DISPLAY_WALLET_ADD_NAME
};
#include "localization.h"
diff --git a/wallet.sln b/wallet.sln
index bbd3a98..60c3902 100644
--- a/wallet.sln
+++ b/wallet.sln
@@ -1,12 +1,10 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
-VisualStudioVersion = 17.0.32014.148
+VisualStudioVersion = 17.7.34031.279
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wallet", "msvc\wallet.vcxproj", "{B1EC18D5-FA70-4A59-8CAE-EDC65A358314}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2F7D488C-DC53-4ECE-87E2-4FEA32C153EF}"
-EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -22,6 +20,6 @@ Global
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {FAF44986-ACA9-4D9B-A9DA-58DBF57EB341}
+ SolutionGuid = {3DB554F1-91C7-4C5D-9A2E-D0EF86D89C18}
EndGlobalSection
EndGlobal