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