/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2020 Ian McInerney <ian.s.mcinerney@ieee.org> * Copyright (C) 2020 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 3 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, see <http://www.gnu.org/licenses/>. */ #ifndef INFOBAR_H_ #define INFOBAR_H_ #include <functional> #include <optional> #include <wx/event.h> #include <wx/infobar.h> #include <wx/timer.h> #include <wx/panel.h> #include <wx/sizer.h> class wxAuiManager; class wxHyperlinkCtrl; enum { /// ID for the close button on the frame's infobar ID_CLOSE_INFOBAR = 2000, }; wxDECLARE_EVENT( KIEVT_SHOW_INFOBAR, wxCommandEvent ); wxDECLARE_EVENT( KIEVT_DISMISS_INFOBAR, wxCommandEvent ); /** * A modified version of the wxInfoBar class that allows us to: * * Show the close button along with the other buttons * * Remove all user-provided buttons at once * * Allow automatically hiding the infobar after a time period * * Show/hide using events * * Place it inside an AUI manager * * This inherits from the generic infobar because the native infobar * on GTK doesn't include the icon on the left and it looks worse. * * There are 2 events associated with the infobar: * * KIEVT_SHOW_INFOBAR: * An event that tells the infobar to show a message. * * The message text is contained inside the string component, * and the message flag is contained inside the int component. * * Sample event creation code: * wxCommandEvent* evt = new wxCommandEvent( KIEVT_SHOW_INFOBAR ); * evt->SetString( "A message to show" ); * evt->SetInt( wxICON_WARNING ); * * KIEVT_DISMISS_INFOBAR: * An event that tells the infobar to hide itself. */ class WX_INFOBAR : public wxInfoBarGeneric { public: /** * Construct an infobar that can exist inside an AUI managed frame. * * @param aParent is the parent * @param aMgr is the AUI manager that this infobar is added to * @param aWinId is the ID for this infobar object */ WX_INFOBAR( wxWindow* aParent, wxAuiManager* aMgr = nullptr, wxWindowID aWinid = wxID_ANY ); ~WX_INFOBAR(); /** * Sets the type of message for special handling if needed */ enum class MESSAGE_TYPE { GENERIC, /**< GENERIC Are messages that do not have special handling */ OUTDATED_SAVE, /**< OUTDATED_SAVE Messages that should be cleared on save */ DRC_RULES_ERROR, DRC_VIOLATION }; MESSAGE_TYPE GetMessageType() const { return m_type; } /** * Set the time period to show the infobar. * * This only applies for the next showing of the infobar, * so it must be reset every time. A value of 0 disables * the automatic hiding (this is the default). * * @param aTime is the time in milliseconds to show the infobar */ void SetShowTime( int aTime ); /** * Add the default close button to the infobar on the right side. * * @param aTooltip is the tooltip to give the close button */ void AddCloseButton( const wxString& aTooltip = _( "Hide this message." ) ); /** * Add an already created button to the infobar. * New buttons are added in the right-most position. * * @param aButton is the button to add */ void AddButton( wxButton* aButton ); /** * Add an already created hypertext link to the infobar. * New buttons are added in the right-most position. * * @param aHypertextButton is the button to add */ void AddButton( wxHyperlinkCtrl* aHypertextButton ); /** * Add a button with the provided ID and text. * The new button is created on the right-most position. * * @param aId is the ID to assign to the button * @param aLabel is the text for the button */ void AddButton( wxWindowID aId, const wxString& aLabel = wxEmptyString ) override; /** * Remove all the buttons that have been added by the user. */ void RemoveAllButtons(); bool HasCloseButton() const; /** * Provide a callback to be called when the infobar is dismissed (either by user action * or timer). * @param aCallback */ void SetCallback( std::function<void(void)> aCallback ) { m_callback = aCallback; } /** * Show the infobar with the provided message and icon for a specific period * of time. * * @param aMessage is the message to display * @param aTime is the amount of time in milliseconds to show the infobar * @param aFlags is the flag containing the icon to display on the left side of the infobar */ void ShowMessageFor( const wxString& aMessage, int aTime, int aFlags = wxICON_INFORMATION, MESSAGE_TYPE aType = WX_INFOBAR::MESSAGE_TYPE::GENERIC ); /** * Show the info bar with the provided message and icon. * * @param aMessage is the message to display * @param aFlags is the flag containing the icon to display on the left side of the infobar */ void ShowMessage( const wxString& aMessage, int aFlags = wxICON_INFORMATION ) override; /** * Show the info bar with the provided message and icon, setting the type * * @param aMessage is the message to display * @param aFlags is the flag containing the icon to display on the left side of the infobar * @param aType is the type of message being displayed */ void ShowMessage( const wxString& aMessage, int aFlags, MESSAGE_TYPE aType ); /** * Dismisses the infobar and updates the containing layout and AUI manager * (if one is provided). */ void Dismiss() override; /** * Send the infobar an event telling it to show a message. * * @param aMessage is the message to display * @param aFlags is the flag containing the icon to display on the left side of the infobar */ void QueueShowMessage( const wxString& aMessage, int aFlags = wxICON_INFORMATION ); /** * Send the infobar an event telling it to hide itself. */ void QueueDismiss(); /** * Returns true if the infobar is being updated. */ bool IsLocked() { return m_updateLock; } protected: /** * Event handler for showing the infobar using a wxCommandEvent of the type * KIEVT_SHOW_INFOBAR. The message is stored inside the string field, and the * icon flag is stored inside the int field. */ void onShowInfoBar( wxCommandEvent& aEvent ); /** * Event handler for dismissing the infobar using a wxCommandEvent of the type * KIEVT_DISMISS_INFOBAR. */ void onDismissInfoBar( wxCommandEvent& aEvent ); /** * Event handler for the close button. * This is bound to ID_CLOSE_INFOBAR on the infobar. */ void onCloseButton( wxCommandEvent& aEvent ); /** * Event handler for the automatic closing timer. */ void onTimer( wxTimerEvent& aEvent ); void onSize( wxSizeEvent& aEvent ); /** * Update the AUI pane to show or hide this infobar. * * @param aShow is true to show the pane */ void updateAuiLayout( bool aShow ); protected: int m_showTime; ///< The time to show the infobar. 0 = don't auto hide bool m_updateLock; ///< True if this infobar requested the UI update wxTimer* m_showTimer; ///< The timer counting the autoclose period wxAuiManager* m_auiManager; ///< The AUI manager that contains this infobar MESSAGE_TYPE m_type; ///< The type of message being displayed std::optional<std::function<void(void)>> m_callback; ///< Optional callback made when closing infobar DECLARE_EVENT_TABLE() }; /** * A wxPanel derived class that hold an infobar and another control. * The infobar is located at the top of the panel, and the other control * is located below it. * * This allows the infobar to be controlled nicely by an AUI manager, * since adding the infobar on its own to the AUI manager produces * artifacts when showing/hiding it due to the AUI pane layout. * * Note that this implementation currently has issues on Windows with * event processing inside the GAL canvas, see: * https://gitlab.com/kicad/code/kicad/-/issues/4501 * */ class EDA_INFOBAR_PANEL : public wxPanel { public: EDA_INFOBAR_PANEL( wxWindow* aParent, wxWindowID aId = wxID_ANY, const wxPoint& aPos = wxDefaultPosition, const wxSize& aSize = wxSize( -1,-1 ), long aStyle = wxTAB_TRAVERSAL, const wxString& aName = wxEmptyString ); /** * Add the given infobar object to the panel * * @param aInfoBar is the infobar to add */ void AddInfoBar( WX_INFOBAR* aInfoBar ); /** * Add the other item to the panel. * This item will expand to fill up the vertical space left. * * @param aOtherItem is the item to add */ void AddOtherItem( wxWindow* aOtherItem ); protected: // The sizer containing the infobar and the other object wxFlexGridSizer* m_mainSizer; }; #endif // INFOBAR_H_