/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2009-2015 Jean-Pierre Charras, jp.charras wanadoo.fr * Copyright (C) 2011 Wayne Stambaugh * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, you may find one here: * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * or you may search the http://www.gnu.org website for the version 2 license, * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /** * @file eda_base_frame.h * @brief Base window classes and related definitions. */ #ifndef EDA_BASE_FRAME_H_ #define EDA_BASE_FRAME_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Option for main frames #define KICAD_DEFAULT_DRAWFRAME_STYLE wxDEFAULT_FRAME_STYLE | wxWANTS_CHARS #define KICAD_MANAGER_FRAME_NAME wxT( "KicadFrame" ) class EDA_ITEM; class EDA_RECT; class EDA_DRAW_PANEL_GAL; class EDA_MSG_PANEL; class BASE_SCREEN; class PARAM_CFG; class PAGE_INFO; class PLOTTER; class TITLE_BLOCK; class MSG_PANEL_ITEM; class TOOL_MANAGER; class TOOL_DISPATCHER; class ACTIONS; class PAGED_DIALOG; class DIALOG_EDIT_LIBRARY_TABLES; class PANEL_HOTKEYS_EDITOR; class FILE_HISTORY; class SETTINGS_MANAGER; class APP_SETTINGS_BASE; class WX_INFOBAR; struct WINDOW_SETTINGS; struct WINDOW_STATE; enum id_librarytype { LIBRARY_TYPE_EESCHEMA, LIBRARY_TYPE_PCBNEW, LIBRARY_TYPE_DOC, LIBRARY_TYPE_SYMBOL }; #define DEFAULT_MAX_UNDO_ITEMS 0 #define ABS_MAX_UNDO_ITEMS (INT_MAX / 2) /// This is the handler functor for the update UI events typedef std::function< void( wxUpdateUIEvent& ) > UIUpdateHandler; wxDECLARE_EVENT( UNITS_CHANGED, wxCommandEvent ); /** * The base frame for deriving all KiCad main window classes. * * This class is not intended to be used directly. It provides support for automatic calls * to SaveSettings() function. SaveSettings() for a derived class can choose to do nothing, * or rely on basic SaveSettings() support in this base class to do most of the work by * calling it from the derived class's SaveSettings(). *

* This class is not a KIWAY_PLAYER because KICAD_MANAGER_FRAME is derived from it * and that class is not a player. *

*/ class EDA_BASE_FRAME : public wxFrame, public TOOLS_HOLDER, public KIWAY_HOLDER { /** * (with its unexpected name so it does not collide with the real OnWindowClose() * function provided in derived classes) is called just before a window * closing, and is used to call a derivation specific * SaveSettings(). SaveSettings() is called for all derived wxFrames in this * base class overload. (Calling it from a destructor is deprecated since the * wxFrame's position is not available in the destructor on linux.) In other words, * you should not need to call SaveSettings() anywhere, except in this * one function found only in this class. */ void windowClosing( wxCloseEvent& event ); wxWindow* findQuasiModalDialog(); /** * Return true if the frame is shown in our modal mode * and false if the frame is shown as an usual frame * In modal mode, the caller that created the frame is responsible to Destroy() * this frame after closing */ virtual bool IsModal() const { return false; } protected: FRAME_T m_Ident; // Id Type (pcb, schematic, library..) wxPoint m_FramePos; wxSize m_FrameSize; // These contain the frame size and position for when it is not maximized wxPoint m_NormalFramePos; wxSize m_NormalFrameSize; wxString m_AboutTitle; // Name of program displayed in About. wxAuiManager m_auimgr; wxString m_perspective; // wxAuiManager perspective. WX_INFOBAR* m_infoBar; // Infobar for the frame wxString m_configName; // Prefix used to identify some params (frame size...) // and to name some config files (legacy hotkey files) SETTINGS_MANAGER* m_settingsManager; FILE_HISTORY* m_fileHistory; // The frame's recently opened file list bool m_hasAutoSave; bool m_autoSaveState; int m_autoSaveInterval; // The auto save interval time in seconds. wxTimer* m_autoSaveTimer; bool m_FlagModified; // Indicates current drawing has been modified. bool m_FlagSave; // Indicates automatic file save. int m_UndoRedoCountMax; // undo/Redo command Max depth UNDO_REDO_CONTAINER m_undoList; // Objects list for the undo command (old data) UNDO_REDO_CONTAINER m_redoList; // Objects list for the redo command (old data) wxString m_mruPath; // Most recently used path. EDA_UNITS m_userUnits; // Map containing the UI update handlers registered with wx for each action std::map m_uiUpdateMap; bool m_isClosing; // Set by the close window event handler after frames are asked if they can close // Allows other functions when called to know our state is cleanup bool m_isNonUserClose; // Set by NonUserClose() to indicate that the user did not request the current close ///> Default style flags used for wxAUI toolbars static constexpr int KICAD_AUI_TB_STYLE = wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_PLAIN_BACKGROUND; /** * @return the suffix to be appended to the file extension on backup */ static wxString GetBackupSuffix() { return wxT( "-bak" ); } /** * @return the string to prepend to a file name for automatic save. */ static wxString GetAutoSaveFilePrefix() { return wxT( "_autosave-" ); } /** * Handle the auto save timer event. */ void onAutoSaveTimer( wxTimerEvent& aEvent ); /** * Return the auto save status of the application. * * Override this function if your derived frame supports automatic file saving. */ virtual bool isAutoSaveRequired() const { return false; } /** * This should be overridden by the derived class to handle the auto save feature. * * @return true if the auto save was successful otherwise false. */ virtual bool doAutoSave(); virtual bool canCloseWindow( wxCloseEvent& aCloseEvent ) { return true; } virtual void doCloseWindow() { } /** * Called when when the units setting has changed to allow for any derived classes * to handle refreshing and controls that have units based measurements in them. The * default version only updates the status bar. Don't forget to call the default * in your derived class or the status bar will not get updated properly. */ virtual void unitsChangeRefresh() { } /** * Setup the UI conditions for the various actions and their controls in this frame. */ virtual void setupUIConditions(); DECLARE_EVENT_TABLE() public: EDA_BASE_FRAME( wxWindow* aParent, FRAME_T aFrameType, const wxString& aTitle, const wxPoint& aPos, const wxSize& aSize, long aStyle, const wxString& aFrameName, KIWAY* aKiway ); ~EDA_BASE_FRAME(); /** * Return the user units currently in use. */ EDA_UNITS GetUserUnits() const { return m_userUnits; } void SetUserUnits( EDA_UNITS aUnits ) { m_userUnits = aUnits; } void ChangeUserUnits( EDA_UNITS aUnits ); virtual void ToggleUserUnits() { } SETTINGS_MANAGER* GetSettingsManager() const { return m_settingsManager; } virtual int GetSeverity( int aErrorCode ) const { return RPT_SEVERITY_UNDEFINED; } /** * Override the default process event handler to implement the auto save feature. * * @warning If you override this function in a derived class, make sure you call down to * this or the auto save feature will be disabled. */ bool ProcessEvent( wxEvent& aEvent ) override; /** * Capture the key event before it is sent to the GUI. * * The basic frame does not capture this event. Editor frames should override this event * function to capture and filter these keys when they are used as hotkeys, and skip it if * the key is not used as hotkey (otherwise the key events will be not sent to menus). */ virtual void OnCharHook( wxKeyEvent& event ); /** * The TOOL_DISPATCHER needs these to work around some issues in wxWidgets where the menu * events aren't captured by the menus themselves. */ void OnMenuEvent( wxMenuEvent& event ); virtual void RegisterUIUpdateHandler( const TOOL_ACTION& aAction, const ACTION_CONDITIONS& aConditions ) override { RegisterUIUpdateHandler( aAction.GetUIId(), aConditions ); } /** * Register a UI update handler for the control with ID @c aID * * @param aID is the control ID to register the handler for * @param aConditions are the UI conditions to use for the control states */ virtual void RegisterUIUpdateHandler( int aID, const ACTION_CONDITIONS& aConditions ); virtual void UnregisterUIUpdateHandler( const TOOL_ACTION& aAction ) override { UnregisterUIUpdateHandler( aAction.GetUIId() ); } /** * Unregister a UI handler for a given ID that was registered using @c RegisterUIUpdateHandler * * @param aID is the control ID to unregister the handler for */ virtual void UnregisterUIUpdateHandler( int aID ); /** * Handles events generated when the UI is trying to figure out the current state of the UI controls * related to TOOL_ACTIONS (e.g. enabled, checked, etc.). * * @param aEvent is the wxUpdateUIEvent to be processed. * @param aFrame is the frame to get the selection from * @param aCond are the UI SELECTION_CONDITIONS used */ static void HandleUpdateUIEvent( wxUpdateUIEvent& aEvent, EDA_BASE_FRAME* aFrame, ACTION_CONDITIONS aCond ); virtual void OnMove( wxMoveEvent& aEvent ) { aEvent.Skip(); } void OnMaximize( wxMaximizeEvent& aEvent ); void SetAutoSaveInterval( int aInterval ); int GetAutoSaveInterval() const { return m_autoSaveInterval; } bool IsType( FRAME_T aType ) const { return m_Ident == aType; } /** * Return a SEARCH_STACK pertaining to entire program. * * This is overloaded in #KICAD_MANAGER_FRAME */ virtual const SEARCH_STACK& sys_search(); virtual wxString help_name(); void OnKicadAbout( wxCommandEvent& event ); void OnPreferences( wxCommandEvent& event ); void PrintMsg( const wxString& text ); WX_INFOBAR* GetInfoBar() { return m_infoBar; } void ShowInfoBarError( const wxString& aErrorMsg ); void ShowInfoBarWarning( const wxString& aWarningMsg ); void ShowInfoBarMsg( const wxString& aMsg ); /** * Returns the settings object used in SaveSettings(), and is overloaded in * KICAD_MANAGER_FRAME */ virtual APP_SETTINGS_BASE* config() const; /** * Function InstallPreferences * Allow a frame to load its preference panels (if any) into the preferences dialog. * @param aParent a paged dialog into which the preference panels should be installed */ virtual void InstallPreferences( PAGED_DIALOG* , PANEL_HOTKEYS_EDITOR* ) { } void LoadWindowState( const wxString& aFileName ); /** * Loads window settings from the given settings object * Normally called by LoadSettings unless the window in question is a child window that * stores its settings somewhere other than APP_SETTINGS_BASE::m_Window */ void LoadWindowSettings( const WINDOW_SETTINGS* aCfg ); /** * Saves window settings to the given settings object * Normally called by SaveSettings unless the window in question is a child window that * stores its settings somewhere other than APP_SETTINGS_BASE::m_Window */ void SaveWindowSettings( WINDOW_SETTINGS* aCfg ); /** * Load common frame parameters from a configuration file. * * Don't forget to call the base method or your frames won't * remember their positions and sizes. */ virtual void LoadSettings( APP_SETTINGS_BASE* aCfg ); /** * Saves common frame parameters to a configuration data file. * * Don't forget to call the base class's SaveSettings() from * your derived SaveSettings() otherwise the frames won't remember their * positions and sizes. */ virtual void SaveSettings( APP_SETTINGS_BASE* aCfg ); /** * Returns a pointer to the window settings for this frame. * By default, points to aCfg->m_Window for top-level frames. * @param aCfg is this frame's config object */ virtual WINDOW_SETTINGS* GetWindowSettings( APP_SETTINGS_BASE* aCfg ); /** * Load frame state info from a configuration file */ virtual void LoadWindowState( const WINDOW_STATE& aState ); /** * @return a base name prefix used in Load/Save settings to build the full name of keys * used in config. * This is usually the name of the frame set by CTOR, except for frames shown in multiple * modes in which case the m_configName must be set to the base name so that a single * config can be used. */ wxString ConfigBaseName() override { wxString baseCfgName = m_configName.IsEmpty() ? GetName() : m_configName; return baseCfgName; } /** * Save changes to the project settings to the project (.pro) file. * * The method is virtual so you can override it to call the suitable save method. * The base method do nothing * @param aAskForSave = true to open a dialog before saving the settings */ virtual void SaveProjectSettings() {}; // Read/Save and Import/export hotkeys config /** * Prompt the user for a hotkey file to read, and read it. * * @param aActionMap = current hotkey map (over which the imported hotkeys will be applied) * @param aDefaultShortname = a default short name (extension not needed) * like eechema, kicad... */ void ImportHotkeyConfigFromFile( std::map aActionMap, const wxString& aDefaultShortname ); /** * Fetches the file name from the file history list. * * This removes the selected file, if this file does not exist. The menu is also updated, * if FILE_HISTORY::UseMenu was called at init time * * @param cmdId The command ID associated with the \a aFileHistory object. * @param type Please document me! * @param aFileHistory The FILE_HISTORY in use. If null, the main application file * history is used * @return a wxString containing the selected filename */ wxString GetFileFromHistory( int cmdId, const wxString& type, FILE_HISTORY* aFileHistory = nullptr ); /** * Removes all files from the file history. * * @param aFileHistory The FILE_HISTORY in use. If null, the main application file * history is used */ void ClearFileHistory( FILE_HISTORY* aFileHistory = nullptr ); /** * Update the list of recently opened files. * * The menu is also updated, if FILE_HISTORY::UseMenu was called at init time. * * @param FullFileName The full file name including the path. * @param aFileHistory The FILE_HISTORY in use. * If NULL, the main application file history is used. */ void UpdateFileHistory( const wxString& FullFileName, FILE_HISTORY* aFileHistory = nullptr ); /** * Get the frame's main file history. * * @return the main file history */ FILE_HISTORY& GetFileHistory() { return *m_fileHistory; } void SetMruPath( const wxString& aPath ) { m_mruPath = aPath; } wxString GetMruPath() const { return m_mruPath; } /** * Get the full filename + path of the currently opened file in the frame. * If no file is open, an empty string is returned. * * @return the filename and full path to the open file */ virtual wxString GetCurrentFileName() const { return wxEmptyString; } /** * Recreates the menu bar. * * Needed when the language is changed */ virtual void ReCreateMenuBar(); /** * Adds the standard KiCad help menu to the menubar. */ void AddStandardHelpMenu( wxMenuBar* aMenuBar ); /** * Checks if \a aFileName can be written. *

* The function performs a number of tests on \a aFileName to verify that it can be saved. * If \a aFileName defines a path with no file name, them the path is tested for user write * permission. If \a aFileName defines a file name that does not exist in the path, the * path is tested for user write permission. If \a aFileName defines a file that already * exits, the file name is tested for user write permissions. *

* @note The file name path must be set or an assertion will be raised on debug builds and * return false on release builds. * @param aFileName The full path and/or file name of the file to test. * @return False if \a aFileName cannot be written. */ bool IsWritable( const wxFileName& aFileName ); /** * Check if an auto save file exists for \a aFileName and takes the appropriate action * depending on the user input. *

* If an auto save file exists for \a aFileName, the user is prompted if they wish to * replace file \a aFileName with the auto saved file. If the user chooses to replace the * file, the backup file of \a aFileName is removed, \a aFileName is renamed to the backup * file name, and the auto save file is renamed to \a aFileName. If user chooses to keep * the existing version of \a aFileName, the auto save file is removed. *

* @param aFileName A wxFileName object containing the file name to check. */ void CheckForAutoSaveFile( const wxFileName& aFileName ); /** * Update the status bar information. * * The status bar can draw itself. This is not a drawing function per se, but rather * updates lines of text held by the components within the status bar which is owned * by the wxFrame. */ virtual void UpdateStatusBar() { } /** * Redraw the menus and what not in current language. */ virtual void ShowChangedLanguage(); /** * Notification event that some of the common (suite-wide) settings have changed. * Update menus, toolbars, local variables, etc. */ void CommonSettingsChanged( bool aEnvVarsChanged, bool aTextVarsChanged ) override; /** * Notification event that the project has changed. */ virtual void ProjectChanged() {} const wxString& GetAboutTitle() const { return m_AboutTitle; } /** * Get if the contents of the frame have been modified since the last save. * * @return true if the contents of the frame have not been saved */ virtual bool IsContentModified(); /** * Get the undecorated window size that can be used for restoring the window size. * * This is needed for GTK, since the normal wxWidgets GetSize() call will return * a window size that includes the window decorations added by the window manager. * * @return the undecorated window size */ wxSize GetWindowSize(); /* general Undo/Redo command control */ /** * Function ClearUndoORRedoList (virtual). * this function must remove the aItemCount old commands from aList * and delete commands, pickers and picked items if needed * Because picked items must be deleted only if they are not in use, this * is a virtual pure function that must be created for SCH_SCREEN and * PCB_SCREEN * @param aList = the UNDO_REDO_CONTAINER of commands * @param aItemCount = number of old commands to delete. -1 to remove all * old commands this will empty the list of commands. * Commands are deleted from the older to the last. */ enum UNDO_REDO_LIST { UNDO_LIST, REDO_LIST }; virtual void ClearUndoORRedoList( UNDO_REDO_LIST aList, int aItemCount = -1 ) { } /** * Function ClearUndoRedoList * clear undo and redo list, using ClearUndoORRedoList() * picked items are deleted by ClearUndoORRedoList() according to their * status */ virtual void ClearUndoRedoList(); /** * Function PushCommandToUndoList * add a command to undo in undo list * delete the very old commands when the max count of undo commands is * reached * ( using ClearUndoORRedoList) */ virtual void PushCommandToUndoList( PICKED_ITEMS_LIST* aItem ); /** * Function PushCommandToRedoList * add a command to redo in redo list * delete the very old commands when the max count of redo commands is * reached * ( using ClearUndoORRedoList) */ virtual void PushCommandToRedoList( PICKED_ITEMS_LIST* aItem ); /** PopCommandFromUndoList * return the last command to undo and remove it from list * nothing is deleted. */ virtual PICKED_ITEMS_LIST* PopCommandFromUndoList(); /** PopCommandFromRedoList * return the last command to undo and remove it from list * nothing is deleted. */ virtual PICKED_ITEMS_LIST* PopCommandFromRedoList(); virtual int GetUndoCommandCount() const { return m_undoList.m_CommandsList.size(); } virtual int GetRedoCommandCount() const { return m_redoList.m_CommandsList.size(); } int GetMaxUndoItems() const { return m_UndoRedoCountMax; } bool NonUserClose( bool aForce ) { m_isNonUserClose = true; return Close( aForce ); } }; /** * Specialization of the wxAuiPaneInfo class for KiCad panels. * * Documentation for wxAui is poor at this time. The following notes spring from errors made in * previous KiCad implementations: * * wxAuiPaneInfo.ToolbarPane() and .Defaults() are used to clear and then prepare the objects so * only use them once at the beginning of configuration.. * * Panels are organized in layers, from 0 (close to the center) and increasing outward. Note * that for ToolbarPanes, layer 0 considered a special default value, and ToolbarPanes on * layer 0 are pushed to layer 10 automatically. Use Layer 1 for the inner layer as a work- * around. * * Each panel has rows, starting at 0. Each row has positions starting at 0. Each item in a panel * can have it's row and position set. * * Eventually panels will be movable. Each initialization function sets up the panel for this, * then after a //==// break has additional calls to anchor toolbars in a way that matches * present functionality. */ class EDA_PANE : public wxAuiPaneInfo { public: EDA_PANE() { Gripper( false ); CloseButton( false ); PaneBorder( false ); } /** * Turn *this to a horizontal toolbar for KiCad. */ EDA_PANE& HToolbar() { SetFlag( optionToolbar, true ); CaptionVisible( false ); TopDockable().BottomDockable(); DockFixed( true ); Movable( false ); Resizable( true ); // expand to fit available space return *this; } /** * Turn *this into a vertical toolbar for KiCad. */ EDA_PANE& VToolbar() { SetFlag( optionToolbar, true ); CaptionVisible( false ); LeftDockable().RightDockable(); DockFixed( true ); Movable( false ); Resizable( true ); // expand to fit available space return *this; } /** * Turn *this into a captioned palette suitable for a symbol tree, layers manager, etc. */ EDA_PANE& Palette() { CaptionVisible( true ); PaneBorder( true ); return *this; } /** * Turn *this into an undecorated pane suitable for a drawing canvas. */ EDA_PANE& Canvas() { CaptionVisible( false ); Layer( 0 ); PaneBorder( true ); Resizable( true ); // expand to fit available space return *this; } /** * Turn *this into a messages pane for KiCad. */ EDA_PANE& Messages() { CaptionVisible( false ); BottomDockable( true ); DockFixed( true ); Movable( false ); Resizable( true ); // expand to fit available space return *this; } /** * Turn *this into a infobar for KiCad. */ EDA_PANE& InfoBar() { CaptionVisible( false ); Movable( false ); Resizable( true ); PaneBorder( false ); DockFixed( true ); return *this; } }; #endif // EDA_BASE_FRAME_H_