KiCad PCB EDA Suite
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
wx_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 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
21#include <id.h>
22#include <kiplatform/ui.h>
23#include <widgets/wx_infobar.h>
24#include "wx/artprov.h"
25#include <wx/aui/framemanager.h>
26#include <wx/bmpbuttn.h>
27#include <wx/debug.h>
28#include <wx/hyperlink.h>
29#include <wx/infobar.h>
30#include <wx/sizer.h>
31#include <wx/stattext.h>
32#include <wx/timer.h>
33#include <eda_base_frame.h>
34
35#ifdef __WXMSW__
36#include <dpi_scaling_common.h>
37#endif
38
39
40wxDEFINE_EVENT( KIEVT_SHOW_INFOBAR, wxCommandEvent );
41wxDEFINE_EVENT( KIEVT_DISMISS_INFOBAR, wxCommandEvent );
42
43BEGIN_EVENT_TABLE( WX_INFOBAR, wxInfoBarGeneric )
44 EVT_COMMAND( wxID_ANY, KIEVT_SHOW_INFOBAR, WX_INFOBAR::onShowInfoBar )
45 EVT_COMMAND( wxID_ANY, KIEVT_DISMISS_INFOBAR, WX_INFOBAR::onDismissInfoBar )
46
47 EVT_SYS_COLOUR_CHANGED( WX_INFOBAR::onThemeChange )
50END_EVENT_TABLE()
51
52
53WX_INFOBAR::WX_INFOBAR( wxWindow* aParent, wxAuiManager* aMgr, wxWindowID aWinid )
54 : wxInfoBarGeneric( aParent, aWinid ),
55 m_showTime( 0 ),
56 m_updateLock( false ),
57 m_showTimer( nullptr ),
58 m_auiManager( aMgr ),
59 m_type( MESSAGE_TYPE::GENERIC )
60{
61 m_showTimer = new wxTimer( this, ID_CLOSE_INFOBAR );
62
63 wxColour fg, bg;
65 SetBackgroundColour( bg );
66 SetForegroundColour( fg );
67
68#ifdef __WXMAC__
69 // Infobar is broken on Mac without the effects
70 SetShowHideEffects( wxSHOW_EFFECT_ROLL_TO_BOTTOM, wxSHOW_EFFECT_ROLL_TO_TOP );
71 SetEffectDuration( 200 );
72#else
73 // Infobar freezes canvas on Windows with the effect, and GTK looks bad with it
74 SetShowHideEffects( wxSHOW_EFFECT_NONE, wxSHOW_EFFECT_NONE );
75#endif
76
77 // The infobar seems to start too small, so increase its height
78 int sx, sy;
79 GetSize( &sx, &sy );
80 sy = 1.5 * sy;
81
82 // The bitmap gets cutoff sometimes with the default size, so force it to be the same
83 // height as the infobar.
84 wxSizer* sizer = GetSizer();
85 wxSize iconSize = wxArtProvider::GetSizeHint( wxART_BUTTON );
86
87#ifdef __WXMSW__
88 DPI_SCALING_COMMON dpi( nullptr, aParent );
89 iconSize.x *= dpi.GetContentScaleFactor();
90 sx *= dpi.GetContentScaleFactor();
91 sy *= dpi.GetContentScaleFactor();
92#endif
93
94 SetSize( sx, sy );
95
96 sizer->SetItemMinSize( (size_t) 0, iconSize.x, sy );
97
98 // Forcefully remove all existing buttons added by the wx constructors.
99 // The default close button doesn't work with the AUI manager update scheme, so this
100 // ensures any close button displayed is ours.
101 RemoveAllButtons();
102
103 Layout();
104
105 m_parent->Bind( wxEVT_SIZE, &WX_INFOBAR::onSize, this );
106}
107
108
110{
111 delete m_showTimer;
112}
113
114
115void WX_INFOBAR::SetShowTime( int aTime )
116{
117 m_showTime = aTime;
118}
119
120
121void WX_INFOBAR::QueueShowMessage( const wxString& aMessage, int aFlags )
122{
123 wxCommandEvent* evt = new wxCommandEvent( KIEVT_SHOW_INFOBAR );
124
125 evt->SetString( aMessage.c_str() );
126 evt->SetInt( aFlags );
127
128 GetEventHandler()->QueueEvent( evt );
129}
130
131
133{
134 wxCommandEvent* evt = new wxCommandEvent( KIEVT_DISMISS_INFOBAR );
135
136 GetEventHandler()->QueueEvent( evt );
137}
138
139
140void WX_INFOBAR::ShowMessageFor( const wxString& aMessage, int aTime, int aFlags,
141 MESSAGE_TYPE aType )
142{
143 // Don't do anything if we requested the UI update
144 if( m_updateLock )
145 return;
146
147 m_showTime = aTime;
148 ShowMessage( aMessage, aFlags );
149
150 m_type = aType;
151}
152
153
154void WX_INFOBAR::ShowMessage( const wxString& aMessage, int aFlags )
155{
156 // Don't do anything if we requested the UI update
157 if( m_updateLock )
158 return;
159
160 m_updateLock = true;
161
162 m_message = aMessage;
163 m_message.Trim();
164
165 wxInfoBarGeneric::ShowMessage( m_message, aFlags );
166
167 if( m_auiManager )
168 updateAuiLayout( true );
169
170 if( m_showTime > 0 )
171 m_showTimer->StartOnce( m_showTime );
172
174 m_updateLock = false;
175}
176
177
178void WX_INFOBAR::ShowMessage( const wxString& aMessage, int aFlags, MESSAGE_TYPE aType )
179{
180 // Don't do anything if we requested the UI update
181 if( m_updateLock )
182 return;
183
184 ShowMessage( aMessage, aFlags );
185
186 m_type = aType;
187}
188
189
191{
192 if( !IsShownOnScreen() )
193 return;
194
195 // Don't do anything if we requested the UI update
196 if( m_updateLock )
197 return;
198
199 m_updateLock = true;
200
201 wxInfoBarGeneric::Dismiss();
202
203 if( m_auiManager )
204 updateAuiLayout( false );
205
206 if( m_callback )
207 (*m_callback)();
208
209 m_updateLock = false;
210}
211
212
213void WX_INFOBAR::onThemeChange( wxSysColourChangedEvent& aEvent )
214{
215 wxColour fg, bg;
217 SetBackgroundColour( bg );
218 SetForegroundColour( fg );
219
220 if( wxBitmapButton* btn = GetCloseButton() )
221 {
222 wxString tooltip = btn->GetToolTipText();
224 AddCloseButton( tooltip );
225 }
226}
227
228
229void WX_INFOBAR::onSize( wxSizeEvent& aEvent )
230{
231 int barWidth = GetSize().GetWidth();
232 wxSizer* sizer = GetSizer();
233
234 if( !sizer )
235 return;
236
237 wxSizerItem* text = sizer->GetItem( 1 );
238
239 if( text )
240 {
241 if( auto textCtrl = dynamic_cast<wxStaticText*>( text->GetWindow() ) )
242 textCtrl->SetLabelText( m_message );
243 }
244
245 // Calculate the horizontal size: because the infobar is shown on top of the draw canvas
246 // it is adjusted to the canvas width.
247 // On Mac, the canvas is the parent
248 // On other OS the parent is EDA_BASE_FRAME that contains the canvas
249 int parentWidth = m_parent->GetClientSize().GetWidth();
250 EDA_BASE_FRAME* frame = dynamic_cast<EDA_BASE_FRAME*>( m_parent );
251
252 if( frame && frame->GetToolCanvas() )
253 parentWidth = frame->GetToolCanvas()->GetSize().GetWidth();
254
255 if( barWidth != parentWidth )
256 SetSize( parentWidth, GetSize().GetHeight() );
257
258 if( text )
259 {
260 if( auto textCtrl = dynamic_cast<wxStaticText*>( text->GetWindow() ) )
261 {
262 // Re-wrap the text (this is done automatically later but we need it now)
263 // And count how many lines we need. If we have embedded newlines, then
264 // multiply the number of lines by the text min height to find the correct
265 // min height for the control. The min height of the text control will be the size
266 // of a single line of text. This assumes that two lines of text are larger
267 // than the height of the icon for the bar.
268 textCtrl->Wrap( -1 );
269 wxString wrapped_text = textCtrl->GetLabel();
270 int height = ( wrapped_text.Freq( '\n' ) + 1 ) * text->GetMinSize().GetHeight();
271 int margins = text->GetMinSize().GetHeight() - 1;
272 SetMinSize( wxSize( GetSize().GetWidth(), height + margins ) );
273 textCtrl->Wrap( -1 );
274 }
275 }
276
277 aEvent.Skip();
278}
279
280
282{
283 wxASSERT( m_auiManager );
284
285 wxAuiPaneInfo& pane = m_auiManager->GetPane( this );
286
287 // If the infobar is in a pane, then show/hide the pane
288 if( pane.IsOk() )
289 {
290 if( aShow )
291 pane.Show();
292 else
293 pane.Hide();
294 }
295
296 // Update the AUI manager regardless
297 m_auiManager->Update();
298}
299
300
301void WX_INFOBAR::AddButton( wxWindowID aId, const wxString& aLabel )
302{
303 wxButton* button = new wxButton( this, aId, aLabel );
304
305 AddButton( button );
306}
307
308
309void WX_INFOBAR::AddButton( wxButton* aButton )
310{
311 wxSizer* sizer = GetSizer();
312
313 wxASSERT( aButton );
314
315#ifdef __WXMAC__
316 // Based on the code in the original class:
317 // smaller buttons look better in the (narrow) info bar under OS X
318 aButton->SetWindowVariant( wxWINDOW_VARIANT_SMALL );
319#endif // __WXMAC__
320
321 auto element = sizer->Add( aButton, wxSizerFlags( 0 ).Centre().Border( wxRIGHT ) );
322
323 element->SetFlag( wxSTRETCH_MASK );
324
325 if( IsShownOnScreen() )
326 sizer->Layout();
327}
328
329
330void WX_INFOBAR::AddButton( wxHyperlinkCtrl* aHypertextButton )
331{
332 wxSizer* sizer = GetSizer();
333
334 wxASSERT( aHypertextButton );
335
336 sizer->Add( aHypertextButton, wxSizerFlags().Centre().Border( wxRIGHT ).Shaped() );
337
338 if( IsShownOnScreen() )
339 sizer->Layout();
340}
341
342
343void WX_INFOBAR::AddCloseButton( const wxString& aTooltip )
344{
345 wxBitmapButton* button = wxBitmapButton::NewCloseButton( this, ID_CLOSE_INFOBAR );
346
347 button->SetToolTip( aTooltip );
348
349 AddButton( button );
350}
351
352
354{
355 wxSizer* sizer = GetSizer();
356
357 if( sizer->GetItemCount() == 0 )
358 return;
359
360 // The last item is already the spacer
361 if( sizer->GetItem( sizer->GetItemCount() - 1 )->IsSpacer() )
362 return;
363
364 for( int i = sizer->GetItemCount() - 1; i >= 0; i-- )
365 {
366 wxSizerItem* sItem = sizer->GetItem( i );
367
368 // The spacer is the end of the custom buttons
369 if( sItem->IsSpacer() )
370 break;
371
372 delete sItem->GetWindow();
373 }
374}
375
376
378{
379 return GetCloseButton();
380}
381
382
383wxBitmapButton* WX_INFOBAR::GetCloseButton() const
384{
385 wxSizer* sizer = GetSizer();
386
387 if( sizer->GetItemCount() == 0 )
388 return nullptr;
389
390 if( sizer->GetItem( sizer->GetItemCount() - 1 )->IsSpacer() )
391 return nullptr;
392
393 wxSizerItem* item = sizer->GetItem( sizer->GetItemCount() - 1 );
394
395 if( item->GetWindow()->GetId() == ID_CLOSE_INFOBAR )
396 return static_cast<wxBitmapButton*>( item->GetWindow() );
397
398 return nullptr;
399}
400
401
402void WX_INFOBAR::onShowInfoBar( wxCommandEvent& aEvent )
403{
406 ShowMessage( aEvent.GetString(), aEvent.GetInt() );
407}
408
409
410void WX_INFOBAR::onDismissInfoBar( wxCommandEvent& aEvent )
411{
412 Dismiss();
413}
414
415
416void WX_INFOBAR::onCloseButton( wxCommandEvent& aEvent )
417{
418 Dismiss();
419}
420
421
422void WX_INFOBAR::onTimer( wxTimerEvent& aEvent )
423{
424 // Reset and clear the timer
425 m_showTimer->Stop();
426 m_showTime = 0;
427
428 Dismiss();
429}
430
431
432EDA_INFOBAR_PANEL::EDA_INFOBAR_PANEL( wxWindow* aParent, wxWindowID aId, const wxPoint& aPos,
433 const wxSize& aSize, long aStyle, const wxString& aName )
434 : wxPanel( aParent, aId, aPos, aSize, aStyle, aName )
435{
436 m_mainSizer = new wxFlexGridSizer( 1, 0, 0 );
437
438 m_mainSizer->SetFlexibleDirection( wxBOTH );
439 m_mainSizer->AddGrowableCol( 0, 1 );
440
441 SetSizer( m_mainSizer );
442}
443
444
446{
447 wxASSERT( aInfoBar );
448
449 aInfoBar->Reparent( this );
450 m_mainSizer->Add( aInfoBar, 1, wxEXPAND, 0 );
451 m_mainSizer->Layout();
452}
453
454
455void EDA_INFOBAR_PANEL::AddOtherItem( wxWindow* aOtherItem )
456{
457 wxASSERT( aOtherItem );
458
459 aOtherItem->Reparent( this );
460 m_mainSizer->Add( aOtherItem, 1, wxEXPAND, 0 );
461
462 m_mainSizer->AddGrowableRow( 1, 1 );
463 m_mainSizer->Layout();
464}
465
466
467REPORTER& INFOBAR_REPORTER::Report( const wxString& aText, SEVERITY aSeverity )
468{
469 m_message.reset( new wxString( aText ) );
470 m_severity = aSeverity;
471 m_messageSet = true;
472
473 return *this;
474}
475
476
478{
479 return m_message && !m_message->IsEmpty();
480}
481
482
484{
485 // Don't do anything if no message was ever given
486 if( !m_infoBar || !m_messageSet )
487 return;
488
489 // Short circuit if the message is empty and it is already hidden
490 if( !HasMessage() && !m_infoBar->IsShownOnScreen() )
491 return;
492
493 int icon = wxICON_NONE;
494
495 switch( m_severity )
496 {
497 case RPT_SEVERITY_UNDEFINED: icon = wxICON_INFORMATION; break;
498 case RPT_SEVERITY_INFO: icon = wxICON_INFORMATION; break;
499 case RPT_SEVERITY_EXCLUSION: icon = wxICON_WARNING; break;
500 case RPT_SEVERITY_ACTION: icon = wxICON_WARNING; break;
501 case RPT_SEVERITY_WARNING: icon = wxICON_WARNING; break;
502 case RPT_SEVERITY_ERROR: icon = wxICON_ERROR; break;
503 case RPT_SEVERITY_IGNORE: icon = wxICON_INFORMATION; break;
504 case RPT_SEVERITY_DEBUG: icon = wxICON_INFORMATION; break;
505 }
506
507 if( m_message->EndsWith( wxS( "\n" ) ) )
508 *m_message = m_message->Left( m_message->Length() - 1 );
509
510 if( HasMessage() )
512 else
514}
Class to handle configuration and automatic determination of the DPI scale to use for canvases.
double GetContentScaleFactor() const override
Get the content scale factor, which may be different from the scale factor on some platforms.
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: wx_infobar.cpp:432
wxFlexGridSizer * m_mainSizer
Definition: wx_infobar.h:313
void AddInfoBar(WX_INFOBAR *aInfoBar)
Add the given infobar object to the panel.
Definition: wx_infobar.cpp:445
void AddOtherItem(wxWindow *aOtherItem)
Add the other item to the panel.
Definition: wx_infobar.cpp:455
WX_INFOBAR * m_infoBar
Definition: wx_infobar.h:348
void Finalize()
Update the infobar with the reported text.
Definition: wx_infobar.cpp:483
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Report a string with a given severity.
Definition: wx_infobar.cpp:467
SEVERITY m_severity
Definition: wx_infobar.h:350
std::unique_ptr< wxString > m_message
Definition: wx_infobar.h:349
bool HasMessage() const override
Returns true if the reporter client is non-empty.
Definition: wx_infobar.cpp:477
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:73
virtual wxWindow * GetToolCanvas() const =0
Canvas access.
A modified version of the wxInfoBar class that allows us to:
Definition: wx_infobar.h:76
void SetShowTime(int aTime)
Set the time period to show the infobar.
Definition: wx_infobar.cpp:115
void RemoveAllButtons()
Remove all the buttons that have been added by the user.
Definition: wx_infobar.cpp:353
void ShowMessageFor(const wxString &aMessage, int aTime, int aFlags=wxICON_INFORMATION, MESSAGE_TYPE aType=WX_INFOBAR::MESSAGE_TYPE::GENERIC)
Show the infobar with the provided message and icon for a specific period of time.
Definition: wx_infobar.cpp:140
bool HasCloseButton() const
Definition: wx_infobar.cpp:377
MESSAGE_TYPE m_type
The type of message being displayed.
Definition: wx_infobar.h:264
void updateAuiLayout(bool aShow)
Update the AUI pane to show or hide this infobar.
Definition: wx_infobar.cpp:281
std::optional< std::function< void(void)> > m_callback
Optional callback made when closing infobar.
Definition: wx_infobar.h:267
wxString m_message
The original message without wrapping.
Definition: wx_infobar.h:265
int m_showTime
The time to show the infobar. 0 = don't auto hide.
Definition: wx_infobar.h:260
bool m_updateLock
True if this infobar requested the UI update.
Definition: wx_infobar.h:261
void onShowInfoBar(wxCommandEvent &aEvent)
Event handler for showing the infobar using a wxCommandEvent of the type KIEVT_SHOW_INFOBAR.
Definition: wx_infobar.cpp:402
void onDismissInfoBar(wxCommandEvent &aEvent)
Event handler for dismissing the infobar using a wxCommandEvent of the type KIEVT_DISMISS_INFOBAR.
Definition: wx_infobar.cpp:410
void AddButton(wxButton *aButton)
Add an already created button to the infobar.
Definition: wx_infobar.cpp:309
MESSAGE_TYPE
Sets the type of message for special handling if needed.
Definition: wx_infobar.h:94
@ GENERIC
GENERIC Are messages that do not have special handling.
void QueueShowMessage(const wxString &aMessage, int aFlags=wxICON_INFORMATION)
Send the infobar an event telling it to show a message.
Definition: wx_infobar.cpp:121
void onCloseButton(wxCommandEvent &aEvent)
Event handler for the close button.
Definition: wx_infobar.cpp:416
wxBitmapButton * GetCloseButton() const
Definition: wx_infobar.cpp:383
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
Definition: wx_infobar.cpp:190
void onThemeChange(wxSysColourChangedEvent &aEvent)
Event handler for the color theme change event.
Definition: wx_infobar.cpp:213
void AddCloseButton(const wxString &aTooltip=_("Hide this message."))
Add the default close button to the infobar on the right side.
Definition: wx_infobar.cpp:343
wxTimer * m_showTimer
The timer counting the autoclose period.
Definition: wx_infobar.h:262
void onTimer(wxTimerEvent &aEvent)
Event handler for the automatic closing timer.
Definition: wx_infobar.cpp:422
void ShowMessage(const wxString &aMessage, int aFlags=wxICON_INFORMATION) override
Show the info bar with the provided message and icon.
Definition: wx_infobar.cpp:154
wxAuiManager * m_auiManager
The AUI manager that contains this infobar.
Definition: wx_infobar.h:263
void onSize(wxSizeEvent &aEvent)
Definition: wx_infobar.cpp:229
void QueueDismiss()
Send the infobar an event telling it to hide itself.
Definition: wx_infobar.cpp:132
Base window classes and related definitions.
Common command IDs shared by more than one of the KiCad applications.
void GetInfoBarColours(wxColour &aFGColour, wxColour &aBGColour)
Return the background and foreground colors for info bars in the current scheme.
Definition: wxgtk/ui.cpp:67
SEVERITY
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_UNDEFINED
@ RPT_SEVERITY_EXCLUSION
@ RPT_SEVERITY_IGNORE
@ RPT_SEVERITY_DEBUG
@ RPT_SEVERITY_INFO
@ RPT_SEVERITY_ACTION
wxDEFINE_EVENT(KIEVT_SHOW_INFOBAR, wxCommandEvent)
@ ID_CLOSE_INFOBAR
ID for the close button on the frame's infobar.
Definition: wx_infobar.h:41