You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

352 lines
11 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2020 Ian McInerney <ian.s.mcinerney@ieee.org>
  5. * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * This program is free software: you can redistribute it and/or modify it
  8. * under the terms of the GNU General Public License as published by the
  9. * Free Software Foundation, either version 3 of the License, or (at your
  10. * option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along
  18. * with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #ifndef INFOBAR_H_
  21. #define INFOBAR_H_
  22. #include <functional>
  23. #include <optional>
  24. #include <wx/event.h>
  25. #include <wx/infobar.h>
  26. #include <wx/timer.h>
  27. #include <wx/panel.h>
  28. #include <wx/sizer.h>
  29. #include <reporter.h>
  30. class wxAuiManager;
  31. class wxHyperlinkCtrl;
  32. enum
  33. {
  34. /// ID for the close button on the frame's infobar
  35. ID_CLOSE_INFOBAR = 2000,
  36. };
  37. wxDECLARE_EVENT( KIEVT_SHOW_INFOBAR, wxCommandEvent );
  38. wxDECLARE_EVENT( KIEVT_DISMISS_INFOBAR, wxCommandEvent );
  39. /**
  40. * A modified version of the wxInfoBar class that allows us to:
  41. * * Show the close button along with the other buttons
  42. * * Remove all user-provided buttons at once
  43. * * Allow automatically hiding the infobar after a time period
  44. * * Show/hide using events
  45. * * Place it inside an AUI manager
  46. *
  47. * This inherits from the generic infobar because the native infobar
  48. * on GTK doesn't include the icon on the left and it looks worse.
  49. *
  50. * There are 2 events associated with the infobar:
  51. *
  52. * KIEVT_SHOW_INFOBAR:
  53. * An event that tells the infobar to show a message.
  54. *
  55. * The message text is contained inside the string component,
  56. * and the message flag is contained inside the int component.
  57. *
  58. * Sample event creation code:
  59. * wxCommandEvent* evt = new wxCommandEvent( KIEVT_SHOW_INFOBAR );
  60. * evt->SetString( "A message to show" );
  61. * evt->SetInt( wxICON_WARNING );
  62. *
  63. * KIEVT_DISMISS_INFOBAR:
  64. * An event that tells the infobar to hide itself.
  65. */
  66. class WX_INFOBAR : public wxInfoBarGeneric
  67. {
  68. public:
  69. /**
  70. * Construct an infobar that can exist inside an AUI managed frame.
  71. *
  72. * @param aParent is the parent
  73. * @param aMgr is the AUI manager that this infobar is added to
  74. * @param aWinId is the ID for this infobar object
  75. */
  76. WX_INFOBAR( wxWindow* aParent, wxAuiManager* aMgr = nullptr, wxWindowID aWinid = wxID_ANY );
  77. ~WX_INFOBAR();
  78. /**
  79. * Sets the type of message for special handling if needed
  80. */
  81. enum class MESSAGE_TYPE
  82. {
  83. GENERIC, /**< GENERIC Are messages that do not have special handling */
  84. OUTDATED_SAVE, /**< OUTDATED_SAVE Messages that should be cleared on save */
  85. DRC_RULES_ERROR,
  86. DRC_VIOLATION
  87. };
  88. MESSAGE_TYPE GetMessageType() const { return m_type; }
  89. /**
  90. * Set the time period to show the infobar.
  91. *
  92. * This only applies for the next showing of the infobar,
  93. * so it must be reset every time. A value of 0 disables
  94. * the automatic hiding (this is the default).
  95. *
  96. * @param aTime is the time in milliseconds to show the infobar
  97. */
  98. void SetShowTime( int aTime );
  99. /**
  100. * Add the default close button to the infobar on the right side.
  101. *
  102. * @param aTooltip is the tooltip to give the close button
  103. */
  104. void AddCloseButton( const wxString& aTooltip = _( "Hide this message." ) );
  105. /**
  106. * Add an already created button to the infobar.
  107. * New buttons are added in the right-most position.
  108. *
  109. * @param aButton is the button to add
  110. */
  111. void AddButton( wxButton* aButton );
  112. /**
  113. * Add an already created hypertext link to the infobar.
  114. * New buttons are added in the right-most position.
  115. *
  116. * @param aHypertextButton is the button to add
  117. */
  118. void AddButton( wxHyperlinkCtrl* aHypertextButton );
  119. /**
  120. * Add a button with the provided ID and text.
  121. * The new button is created on the right-most position.
  122. *
  123. * @param aId is the ID to assign to the button
  124. * @param aLabel is the text for the button
  125. */
  126. void AddButton( wxWindowID aId, const wxString& aLabel = wxEmptyString ) override;
  127. /**
  128. * Remove all the buttons that have been added by the user.
  129. */
  130. void RemoveAllButtons();
  131. bool HasCloseButton() const;
  132. wxBitmapButton* GetCloseButton() const;
  133. /**
  134. * Provide a callback to be called when the infobar is dismissed (either by user action
  135. * or timer).
  136. * @param aCallback
  137. */
  138. void SetCallback( std::function<void(void)> aCallback )
  139. {
  140. m_callback = aCallback;
  141. }
  142. /**
  143. * Show the infobar with the provided message and icon for a specific period
  144. * of time.
  145. *
  146. * @param aMessage is the message to display
  147. * @param aTime is the amount of time in milliseconds to show the infobar
  148. * @param aFlags is the flag containing the icon to display on the left side of the infobar
  149. */
  150. void ShowMessageFor( const wxString& aMessage, int aTime, int aFlags = wxICON_INFORMATION,
  151. MESSAGE_TYPE aType = WX_INFOBAR::MESSAGE_TYPE::GENERIC );
  152. /**
  153. * Show the info bar with the provided message and icon.
  154. *
  155. * @param aMessage is the message to display
  156. * @param aFlags is the flag containing the icon to display on the left side of the infobar
  157. */
  158. void ShowMessage( const wxString& aMessage, int aFlags = wxICON_INFORMATION ) override;
  159. /**
  160. * Show the info bar with the provided message and icon, setting the type
  161. *
  162. * @param aMessage is the message to display
  163. * @param aFlags is the flag containing the icon to display on the left side of the infobar
  164. * @param aType is the type of message being displayed
  165. */
  166. void ShowMessage( const wxString& aMessage, int aFlags, MESSAGE_TYPE aType );
  167. /**
  168. * Dismisses the infobar and updates the containing layout and AUI manager
  169. * (if one is provided).
  170. */
  171. void Dismiss() override;
  172. /**
  173. * Send the infobar an event telling it to show a message.
  174. *
  175. * @param aMessage is the message to display
  176. * @param aFlags is the flag containing the icon to display on the left side of the infobar
  177. */
  178. void QueueShowMessage( const wxString& aMessage, int aFlags = wxICON_INFORMATION );
  179. /**
  180. * Send the infobar an event telling it to hide itself.
  181. */
  182. void QueueDismiss();
  183. /**
  184. * Returns true if the infobar is being updated.
  185. */
  186. bool IsLocked()
  187. {
  188. return m_updateLock;
  189. }
  190. protected:
  191. /**
  192. * Event handler for showing the infobar using a wxCommandEvent of the type
  193. * KIEVT_SHOW_INFOBAR. The message is stored inside the string field, and the
  194. * icon flag is stored inside the int field.
  195. */
  196. void onShowInfoBar( wxCommandEvent& aEvent );
  197. /**
  198. * Event handler for dismissing the infobar using a wxCommandEvent of the type
  199. * KIEVT_DISMISS_INFOBAR.
  200. */
  201. void onDismissInfoBar( wxCommandEvent& aEvent );
  202. /**
  203. * Event handler for the close button.
  204. * This is bound to ID_CLOSE_INFOBAR on the infobar.
  205. */
  206. void onCloseButton( wxCommandEvent& aEvent );
  207. /**
  208. * Event handler for the color theme change event.
  209. */
  210. void onThemeChange( wxSysColourChangedEvent& aEvent );
  211. /**
  212. * Event handler for the automatic closing timer.
  213. */
  214. void onTimer( wxTimerEvent& aEvent );
  215. void onSize( wxSizeEvent& aEvent );
  216. /**
  217. * Update the AUI pane to show or hide this infobar.
  218. *
  219. * @param aShow is true to show the pane
  220. */
  221. void updateAuiLayout( bool aShow );
  222. protected:
  223. int m_showTime; ///< The time to show the infobar. 0 = don't auto hide
  224. bool m_updateLock; ///< True if this infobar requested the UI update
  225. wxTimer* m_showTimer; ///< The timer counting the autoclose period
  226. wxAuiManager* m_auiManager; ///< The AUI manager that contains this infobar
  227. MESSAGE_TYPE m_type; ///< The type of message being displayed
  228. wxString m_message; ///< The original message without wrapping
  229. std::optional<std::function<void(void)>> m_callback; ///< Optional callback made when closing infobar
  230. DECLARE_EVENT_TABLE()
  231. };
  232. /**
  233. * A wxPanel derived class that hold an infobar and another control.
  234. * The infobar is located at the top of the panel, and the other control
  235. * is located below it.
  236. *
  237. * This allows the infobar to be controlled nicely by an AUI manager,
  238. * since adding the infobar on its own to the AUI manager produces
  239. * artifacts when showing/hiding it due to the AUI pane layout.
  240. *
  241. * Note that this implementation currently has issues on Windows with
  242. * event processing inside the GAL canvas, see:
  243. * https://gitlab.com/kicad/code/kicad/-/issues/4501
  244. *
  245. */
  246. class EDA_INFOBAR_PANEL : public wxPanel
  247. {
  248. public:
  249. EDA_INFOBAR_PANEL( wxWindow* aParent, wxWindowID aId = wxID_ANY,
  250. const wxPoint& aPos = wxDefaultPosition,
  251. const wxSize& aSize = wxSize( -1,-1 ),
  252. long aStyle = wxTAB_TRAVERSAL,
  253. const wxString& aName = wxEmptyString );
  254. /**
  255. * Add the given infobar object to the panel
  256. *
  257. * @param aInfoBar is the infobar to add
  258. */
  259. void AddInfoBar( WX_INFOBAR* aInfoBar );
  260. /**
  261. * Add the other item to the panel.
  262. * This item will expand to fill up the vertical space left.
  263. *
  264. * @param aOtherItem is the item to add
  265. */
  266. void AddOtherItem( wxWindow* aOtherItem );
  267. protected:
  268. // The sizer containing the infobar and the other object
  269. wxFlexGridSizer* m_mainSizer;
  270. };
  271. /**
  272. * A wrapper for reporting to a #WX_INFOBAR UI element.
  273. *
  274. * The infobar is not updated until the @c Finalize() method is called. That method will
  275. * queue either a show message or a dismiss event for the infobar - so this reporter is
  276. * safe to use inside a paint event without causing an infinite paint event loop.
  277. *
  278. * No action is taken if no message is given to the reporter.
  279. */
  280. class INFOBAR_REPORTER : public REPORTER
  281. {
  282. public:
  283. INFOBAR_REPORTER( WX_INFOBAR* aInfoBar ) :
  284. REPORTER(), m_messageSet( false ), m_infoBar( aInfoBar ),
  285. m_severity( RPT_SEVERITY_UNDEFINED )
  286. {
  287. }
  288. virtual ~INFOBAR_REPORTER() {};
  289. REPORTER& Report( const wxString& aText, SEVERITY aSeverity = RPT_SEVERITY_UNDEFINED ) override;
  290. bool HasMessage() const override;
  291. /**
  292. * Update the infobar with the reported text.
  293. */
  294. void Finalize();
  295. private:
  296. bool m_messageSet;
  297. WX_INFOBAR* m_infoBar;
  298. std::unique_ptr<wxString> m_message;
  299. SEVERITY m_severity;
  300. };
  301. #endif // INFOBAR_H_