#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]; static void check_dynamic_menus_absent(); 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. // (Because the handler is a method of an object that is about to be destroyed.) // Also avoids the need for manually creating a new windowid to link each additional bind // to each menu item, thus avoids the likelihood of mismatching binds and menu entries. class MenuLink { typedef void (T::* method_handler)(wxCommandEvent&); // (thing.*p)(args) is how you use a pointer to method T* m_handler = nullptr; method_handler m_method; int m_winid; wxMenu* m_menu = nullptr; wxMenuItem* m_menuItem = nullptr; public: MenuLink() = delete; MenuLink(const MenuLink&) = default; MenuLink(const MenuLink&&) = delete; MenuLink& operator=(const MenuLink&) = delete; MenuLink& operator=(MenuLink&) = delete; MenuLink(T* handler, method_handler method) : m_handler(handler), m_method{ method }, m_winid{ wxWindow::NewControlId() }{} MenuLink(T* handler, method_handler method, MyIDs winid) : m_handler(handler), m_method{ method }, m_winid{ winid } {} ~MenuLink() { if (m_menu != nullptr) { m_menu->Unbind(wxEVT_MENU, m_method, m_handler, m_winid); m_menu->Destroy(m_menuItem); } } wxMenuItem* Insert( wxMenu* menu, size_t pos, const wxString& item, const wxString& help = wxEmptyString ) { if (m_menu == nullptr) m_menu = menu; else { assert(false); throw MyException("Reinsertion of menu item"); } m_menuItem = menu->Insert(pos, m_winid, item, help); menu->Bind(wxEVT_MENU, m_method, m_handler, m_winid); return m_menuItem; } void queue_event() { if (m_menu != nullptr) { auto event = new wxCommandEvent(wxEVT_MENU, m_winid); wxQueueEvent(m_menu, event); } else { assert(false); throw MyException("Event sent to uninitialized Menu item"); } } }; class Frame : public wxFrame { int m_TipOfTheDayIndex; int m_FileDialogFilterIndex; public: bool m_showTipsAtStartup; wxFileName m_LastUsedWallet; wxFileName m_DefaultWalletLocation; Frame(const wxString& title); virtual ~Frame(); wxLogWindow*m_pLogWindow{ nullptr }; std::unique_ptrm_pLogNull{ nullptr }; wxPanel* m_panel{nullptr}; //The once current child panel. private: typedef MenuLink MenuLink; void StorePositionToConfig(void); void RestorePositionFromConfig(const wxSize&); void OnExit(wxCommandEvent&); void OnAbout(wxCommandEvent&); void OnDeleteConfiguration(wxCommandEvent&); void OnMyCloseMPanel(wxCommandEvent&); public: void OnSaveNew(wxCommandEvent&); void NewWallet(wxFileName&, ristretto255::hash<256>&); void RecreateWalletFromExistingSecret(wxCommandEvent&); void OnFileOpen(wxCommandEvent&); void OnClose(wxCloseEvent& event); private: void OnMenuOpen(wxMenuEvent&); public: void OnFirstUse(wxCommandEvent&); public: // MenuLink menu_OnFirstUse = // MenuLink(&Frame::OnFirstUse, myID_WELCOME_TO_ROCOIN); }; extern Frame* singletonFrame;