KiCad PCB EDA Suite
infobar.cpp
Go to the documentation of this file.
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 (C) 2020 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 
21 #include <id.h>
22 #include <kiplatform/ui.h>
23 #include <widgets/infobar.h>
24 #include "wx/artprov.h"
25 #include <wx/aui/framemanager.h>
26 #include <wx/debug.h>
27 #include <wx/infobar.h>
28 #include <wx/sizer.h>
29 #include <wx/timer.h>
30 #include <wx/hyperlink.h>
31 #include <wx/bmpbuttn.h>
32 #include <eda_base_frame.h>
33 
34 
35 wxDEFINE_EVENT( KIEVT_SHOW_INFOBAR, wxCommandEvent );
36 wxDEFINE_EVENT( KIEVT_DISMISS_INFOBAR, wxCommandEvent );
37 
38 BEGIN_EVENT_TABLE( WX_INFOBAR, wxInfoBarGeneric )
39  EVT_COMMAND( wxID_ANY, KIEVT_SHOW_INFOBAR, WX_INFOBAR::onShowInfoBar )
40  EVT_COMMAND( wxID_ANY, KIEVT_DISMISS_INFOBAR, WX_INFOBAR::onDismissInfoBar )
41 
44 END_EVENT_TABLE()
45 
46 
47 WX_INFOBAR::WX_INFOBAR( wxWindow* aParent, wxAuiManager* aMgr, wxWindowID aWinid )
48  : wxInfoBarGeneric( aParent, aWinid ),
49  m_showTime( 0 ),
50  m_updateLock( false ),
51  m_showTimer( nullptr ),
52  m_auiManager( aMgr ),
53  m_type( MESSAGE_TYPE::GENERIC )
54 {
55  m_showTimer = new wxTimer( this, ID_CLOSE_INFOBAR );
56 
57 #ifdef __WXMAC__
58  // wxWidgets hard-codes wxSYS_COLOUR_INFOBK to { 0xFF, 0xFF, 0xD3 } on Mac.
60  SetBackgroundColour( wxColour( 28, 27, 20 ) );
61  else
62  SetBackgroundColour( wxColour( 255, 249, 189 ) );
63 #endif
64 
65  SetShowHideEffects( wxSHOW_EFFECT_ROLL_TO_BOTTOM, wxSHOW_EFFECT_ROLL_TO_TOP );
66  SetEffectDuration( 300 );
67 
68  // The infobar seems to start too small, so increase its height
69  int sx, sy;
70  GetSize( &sx, &sy );
71  sy = 1.5 * sy;
72  SetSize( sx, sy );
73 
74  // The bitmap gets cutoff sometimes with the default size, so force it to be the same
75  // height as the infobar.
76  wxSizer* sizer = GetSizer();
77  wxSize iconSize = wxArtProvider::GetSizeHint( wxART_BUTTON );
78 
79  sizer->SetItemMinSize( (size_t) 0, iconSize.x, sy );
80 
81  // Forcefully remove all existing buttons added by the wx constructors.
82  // The default close button doesn't work with the AUI manager update scheme, so this
83  // ensures any close button displayed is ours.
84  RemoveAllButtons();
85 
86  Layout();
87 
88  m_parent->Bind( wxEVT_SIZE, &WX_INFOBAR::onSize, this );
89 }
90 
91 
93 {
94  delete m_showTimer;
95 }
96 
97 
98 void WX_INFOBAR::SetShowTime( int aTime )
99 {
100  m_showTime = aTime;
101 }
102 
103 
104 void WX_INFOBAR::QueueShowMessage( const wxString& aMessage, int aFlags )
105 {
106  wxCommandEvent* evt = new wxCommandEvent( KIEVT_SHOW_INFOBAR );
107 
108  evt->SetString( aMessage.c_str() );
109  evt->SetInt( aFlags );
110 
111  GetEventHandler()->QueueEvent( evt );
112 }
113 
114 
116 {
117  wxCommandEvent* evt = new wxCommandEvent( KIEVT_DISMISS_INFOBAR );
118 
119  GetEventHandler()->QueueEvent( evt );
120 }
121 
122 
123 void WX_INFOBAR::ShowMessageFor( const wxString& aMessage, int aTime, int aFlags )
124 {
125  // Don't do anything if we requested the UI update
126  if( m_updateLock )
127  return;
128 
129  m_showTime = aTime;
130  ShowMessage( aMessage, aFlags );
131 }
132 
133 
134 void WX_INFOBAR::ShowMessage( const wxString& aMessage, int aFlags )
135 {
136  // Don't do anything if we requested the UI update
137  if( m_updateLock )
138  return;
139 
140  m_updateLock = true;
141 
142  wxInfoBarGeneric::ShowMessage( aMessage, aFlags );
143 
144  if( m_auiManager )
145  updateAuiLayout( true );
146 
147  if( m_showTime > 0 )
148  m_showTimer->StartOnce( m_showTime );
149 
151  m_updateLock = false;
152 }
153 
154 
155 void WX_INFOBAR::ShowMessage( const wxString& aMessage, int aFlags, MESSAGE_TYPE aType )
156 {
157  // Don't do anything if we requested the UI update
158  if( m_updateLock )
159  return;
160 
161  ShowMessage( aMessage, aFlags );
162 
163  m_type = aType;
164 }
165 
166 
168 {
170  return;
171 
172  Dismiss();
173 }
174 
175 
177 {
178  // Don't do anything if we requested the UI update
179  if( m_updateLock )
180  return;
181 
182  m_updateLock = true;
183 
184  wxInfoBarGeneric::Dismiss();
185 
186  if( m_auiManager )
187  updateAuiLayout( false );
188 
189  if( m_callback )
190  (*m_callback)();
191 
192  m_updateLock = false;
193 }
194 
195 
196 void WX_INFOBAR::onSize( wxSizeEvent& aEvent )
197 {
198  int barWidth = GetSize().GetWidth();
199 
200  // Calculate the horizontal size: because the infobar is shown on top of the draw canvas
201  // it is adjusted to the canvas width.
202  // On Mac, the canvas is the parent
203  // On other OS the parent is EDA_BASE_FRAME that contains the canvas
204  int parentWidth = m_parent->GetClientSize().GetWidth();
205  EDA_BASE_FRAME* frame = dynamic_cast<EDA_BASE_FRAME*>( m_parent );
206 
207  if( frame && frame->GetToolCanvas() )
208  parentWidth = frame->GetToolCanvas()->GetSize().GetWidth();
209 
210 
211  if( barWidth != parentWidth )
212  SetSize( parentWidth, GetSize().GetHeight() );
213 
214  aEvent.Skip();
215 }
216 
217 
218 void WX_INFOBAR::updateAuiLayout( bool aShow )
219 {
220  wxASSERT( m_auiManager );
221 
222  wxAuiPaneInfo& pane = m_auiManager->GetPane( this );
223 
224  // If the infobar is in a pane, then show/hide the pane
225  if( pane.IsOk() )
226  {
227  if( aShow )
228  pane.Show();
229  else
230  pane.Hide();
231  }
232 
233  // Update the AUI manager regardless
234  m_auiManager->Update();
235 }
236 
237 
238 void WX_INFOBAR::AddButton( wxWindowID aId, const wxString& aLabel )
239 {
240  wxButton* button = new wxButton( this, aId, aLabel );
241 
242  AddButton( button );
243 }
244 
245 
246 void WX_INFOBAR::AddButton( wxButton* aButton )
247 {
248  wxSizer* sizer = GetSizer();
249 
250  wxASSERT( aButton );
251 
252 #ifdef __WXMAC__
253  // Based on the code in the original class:
254  // smaller buttons look better in the (narrow) info bar under OS X
255  aButton->SetWindowVariant( wxWINDOW_VARIANT_SMALL );
256 #endif // __WXMAC__
257  sizer->Add( aButton, wxSizerFlags().Centre().Border( wxRIGHT ) );
258 
259  if( IsShown() )
260  sizer->Layout();
261 }
262 
263 
264 void WX_INFOBAR::AddButton( wxHyperlinkCtrl* aHypertextButton )
265 {
266  wxSizer* sizer = GetSizer();
267 
268  wxASSERT( aHypertextButton );
269 
270  sizer->Add( aHypertextButton, wxSizerFlags().Centre().Border( wxRIGHT ) );
271 
272  if( IsShown() )
273  sizer->Layout();
274 }
275 
276 
277 void WX_INFOBAR::AddCloseButton( const wxString& aTooltip )
278 {
279  wxBitmapButton* button = wxBitmapButton::NewCloseButton( this, ID_CLOSE_INFOBAR );
280 
281  button->SetToolTip( aTooltip );
282 
283  AddButton( button );
284 }
285 
286 
288 {
289  wxSizer* sizer = GetSizer();
290 
291  if( sizer->GetItemCount() == 0 )
292  return;
293 
294  // The last item is already the spacer
295  if( sizer->GetItem( sizer->GetItemCount() - 1 )->IsSpacer() )
296  return;
297 
298  for( int i = sizer->GetItemCount() - 1; i >= 0; i-- )
299  {
300  wxSizerItem* sItem = sizer->GetItem( i );
301 
302  // The spacer is the end of the custom buttons
303  if( sItem->IsSpacer() )
304  break;
305 
306  delete sItem->GetWindow();
307  }
308 }
309 
310 
312 {
313  wxSizer* sizer = GetSizer();
314 
315  if( sizer->GetItemCount() == 0 )
316  return false;
317 
318  if( sizer->GetItem( sizer->GetItemCount() - 1 )->IsSpacer() )
319  return false;
320 
321  wxSizerItem* item = sizer->GetItem( sizer->GetItemCount() - 1 );
322 
323  return ( item->GetWindow()->GetId() == ID_CLOSE_INFOBAR );
324 }
325 
326 
327 void WX_INFOBAR::onShowInfoBar( wxCommandEvent& aEvent )
328 {
330  AddCloseButton();
331  ShowMessage( aEvent.GetString(), aEvent.GetInt() );
332 }
333 
334 
335 void WX_INFOBAR::onDismissInfoBar( wxCommandEvent& aEvent )
336 {
337  Dismiss();
338 }
339 
340 
341 void WX_INFOBAR::onCloseButton( wxCommandEvent& aEvent )
342 {
343  Dismiss();
344 }
345 
346 
347 void WX_INFOBAR::onTimer( wxTimerEvent& aEvent )
348 {
349  // Reset and clear the timer
350  m_showTimer->Stop();
351  m_showTime = 0;
352 
353  Dismiss();
354 }
355 
356 
357 EDA_INFOBAR_PANEL::EDA_INFOBAR_PANEL( wxWindow* aParent, wxWindowID aId, const wxPoint& aPos,
358  const wxSize& aSize, long aStyle, const wxString& aName )
359  : wxPanel( aParent, aId, aPos, aSize, aStyle, aName )
360 {
361  m_mainSizer = new wxFlexGridSizer( 1, 0, 0 );
362 
363  m_mainSizer->SetFlexibleDirection( wxBOTH );
364  m_mainSizer->AddGrowableCol( 0, 1 );
365 
366  SetSizer( m_mainSizer );
367 }
368 
369 
371 {
372  wxASSERT( aInfoBar );
373 
374  aInfoBar->Reparent( this );
375  m_mainSizer->Add( aInfoBar, 1, wxEXPAND, 0 );
376  m_mainSizer->Layout();
377 }
378 
379 
380 void EDA_INFOBAR_PANEL::AddOtherItem( wxWindow* aOtherItem )
381 {
382  wxASSERT( aOtherItem );
383 
384  aOtherItem->Reparent( this );
385  m_mainSizer->Add( aOtherItem, 1, wxEXPAND, 0 );
386 
387  m_mainSizer->AddGrowableRow( 1, 1 );
388  m_mainSizer->Layout();
389 }
void ShowMessageFor(const wxString &aMessage, int aTime, int aFlags=wxICON_INFORMATION)
Show the infobar with the provided message and icon for a specific period of time.
Definition: infobar.cpp:123
void ShowMessage(const wxString &aMessage, int aFlags=wxICON_INFORMATION) override
Show the info bar with the provided message and icon.
Definition: infobar.cpp:134
MESSAGE_TYPE
Sets the type of message for special handling if needed.
Definition: infobar.h:91
void AddButton(wxButton *aButton)
Add an already created button to the infobar.
Definition: infobar.cpp:246
void onTimer(wxTimerEvent &aEvent)
Event handler for the automatic closing timer.
Definition: infobar.cpp:347
void onSize(wxSizeEvent &aEvent)
Definition: infobar.cpp:196
void updateAuiLayout(bool aShow)
Update the AUI pane to show or hide this infobar.
Definition: infobar.cpp:218
void onCloseButton(wxCommandEvent &aEvent)
Event handler for the close button.
Definition: infobar.cpp:341
GENERIC Are messages that do not have special handling.
bool IsDarkTheme()
Determine if the desktop interface is currently using a dark theme or a light theme.
Definition: gtk/ui.cpp:31
wxTimer * m_showTimer
The timer counting the autoclose period.
Definition: infobar.h:254
void onShowInfoBar(wxCommandEvent &aEvent)
Event handler for showing the infobar using a wxCommandEvent of the type KIEVT_SHOW_INFOBAR.
Definition: infobar.cpp:327
OPT< std::function< void(void)> > m_callback
Optional callback made when closing infobar.
Definition: infobar.h:258
~WX_INFOBAR()
Definition: infobar.cpp:92
bool HasCloseButton() const
Definition: infobar.cpp:311
wxDEFINE_EVENT(KIEVT_SHOW_INFOBAR, wxCommandEvent)
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
Definition: infobar.cpp:176
virtual wxWindow * GetToolCanvas() const =0
Canvas access.
ID for the close button on the frame's infobar.
Definition: infobar.h:39
void AddOtherItem(wxWindow *aOtherItem)
Add the other item to the panel.
Definition: infobar.cpp:380
Base window classes and related definitions.
void RemoveAllButtons()
Remove all the buttons that have been added by the user.
Definition: infobar.cpp:287
void QueueShowMessage(const wxString &aMessage, int aFlags=wxICON_INFORMATION)
Send the infobar an event telling it to show a message.
Definition: infobar.cpp:104
void DismissOutdatedSave()
Dismisses the infobar for outdated save warnings and updates the containing layout and AUI manager (i...
Definition: infobar.cpp:167
A modified version of the wxInfoBar class that allows us to:
Definition: infobar.h:73
void SetShowTime(int aTime)
Set the time period to show the infobar.
Definition: infobar.cpp:98
void QueueDismiss()
Send the infobar an event telling it to hide itself.
Definition: infobar.cpp:115
wxFlexGridSizer * m_mainSizer
Definition: infobar.h:304
The base frame for deriving all KiCad main window classes.
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)
Definition: infobar.cpp:357
wxAuiManager * m_auiManager
The AUI manager that contains this infobar.
Definition: infobar.h:255
OUTDATED_SAVE Messages that should be cleared on save.
void onDismissInfoBar(wxCommandEvent &aEvent)
Event handler for dismissing the infobar using a wxCommandEvent of the type KIEVT_DISMISS_INFOBAR.
Definition: infobar.cpp:335
bool m_updateLock
True if this infobar requested the UI update.
Definition: infobar.h:253
void AddInfoBar(WX_INFOBAR *aInfoBar)
Add the given infobar object to the panel.
Definition: infobar.cpp:370
MESSAGE_TYPE m_type
The type of message being displayed.
Definition: infobar.h:256
int m_showTime
The time to show the infobar. 0 = don't auto hide.
Definition: infobar.h:252
void AddCloseButton(const wxString &aTooltip=_("Hide this message."))
Add the default close button to the infobar on the right side.
Definition: infobar.cpp:277