KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 <[email protected]>
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( text->GetSize().GetWidth() );
269 wxString new_text = textCtrl->GetLabel();
270 int height = ( new_text.Freq( '\n' ) + 1 ) * text->GetMinSize().GetHeight();
271 SetMinSize( wxSize( GetSize().GetWidth(), height ) );
272 }
273 }
274
275 aEvent.Skip();
276}
277
278
280{
281 wxASSERT( m_auiManager );
282
283 wxAuiPaneInfo& pane = m_auiManager->GetPane( this );
284
285 // If the infobar is in a pane, then show/hide the pane
286 if( pane.IsOk() )
287 {
288 if( aShow )
289 pane.Show();
290 else
291 pane.Hide();
292 }
293
294 // Update the AUI manager regardless
295 m_auiManager->Update();
296}
297
298
299void WX_INFOBAR::AddButton( wxWindowID aId, const wxString& aLabel )
300{
301 wxButton* button = new wxButton( this, aId, aLabel );
302
303 AddButton( button );
304}
305
306
307void WX_INFOBAR::AddButton( wxButton* aButton )
308{
309 wxSizer* sizer = GetSizer();
310
311 wxASSERT( aButton );
312
313#ifdef __WXMAC__
314 // Based on the code in the original class:
315 // smaller buttons look better in the (narrow) info bar under OS X
316 aButton->SetWindowVariant( wxWINDOW_VARIANT_SMALL );
317#endif // __WXMAC__
318
319 auto element = sizer->Add( aButton, wxSizerFlags( 0 ).Centre().Border( wxRIGHT ) );
320
321 element->SetFlag( wxSTRETCH_MASK );
322
323 if( IsShownOnScreen() )
324 sizer->Layout();
325}
326
327
328void WX_INFOBAR::AddButton( wxHyperlinkCtrl* aHypertextButton )
329{
330 wxSizer* sizer = GetSizer();
331
332 wxASSERT( aHypertextButton );
333
334 sizer->Add( aHypertextButton, wxSizerFlags().Centre().Border( wxRIGHT ).Shaped() );
335
336 if( IsShownOnScreen() )
337 sizer->Layout();
338}
339
340
341void WX_INFOBAR::AddCloseButton( const wxString& aTooltip )
342{
343 wxBitmapButton* button = wxBitmapButton::NewCloseButton( this, ID_CLOSE_INFOBAR );
344
345 button->SetToolTip( aTooltip );
346
347 AddButton( button );
348}
349
350
352{
353 wxSizer* sizer = GetSizer();
354
355 if( sizer->GetItemCount() == 0 )
356 return;
357
358 // The last item is already the spacer
359 if( sizer->GetItem( sizer->GetItemCount() - 1 )->IsSpacer() )
360 return;
361
362 for( int i = sizer->GetItemCount() - 1; i >= 0; i-- )
363 {
364 wxSizerItem* sItem = sizer->GetItem( i );
365
366 // The spacer is the end of the custom buttons
367 if( sItem->IsSpacer() )
368 break;
369
370 delete sItem->GetWindow();
371 }
372}
373
374
376{
377 return GetCloseButton();
378}
379
380
381wxBitmapButton* WX_INFOBAR::GetCloseButton() const
382{
383 wxSizer* sizer = GetSizer();
384
385 if( sizer->GetItemCount() == 0 )
386 return nullptr;
387
388 if( sizer->GetItem( sizer->GetItemCount() - 1 )->IsSpacer() )
389 return nullptr;
390
391 wxSizerItem* item = sizer->GetItem( sizer->GetItemCount() - 1 );
392
393 if( item->GetWindow()->GetId() == ID_CLOSE_INFOBAR )
394 return static_cast<wxBitmapButton*>( item->GetWindow() );
395
396 return nullptr;
397}
398
399
400void WX_INFOBAR::onShowInfoBar( wxCommandEvent& aEvent )
401{
404 ShowMessage( aEvent.GetString(), aEvent.GetInt() );
405}
406
407
408void WX_INFOBAR::onDismissInfoBar( wxCommandEvent& aEvent )
409{
410 Dismiss();
411}
412
413
414void WX_INFOBAR::onCloseButton( wxCommandEvent& aEvent )
415{
416 Dismiss();
417}
418
419
420void WX_INFOBAR::onTimer( wxTimerEvent& aEvent )
421{
422 // Reset and clear the timer
423 m_showTimer->Stop();
424 m_showTime = 0;
425
426 Dismiss();
427}
428
429
430EDA_INFOBAR_PANEL::EDA_INFOBAR_PANEL( wxWindow* aParent, wxWindowID aId, const wxPoint& aPos,
431 const wxSize& aSize, long aStyle, const wxString& aName )
432 : wxPanel( aParent, aId, aPos, aSize, aStyle, aName )
433{
434 m_mainSizer = new wxFlexGridSizer( 1, 0, 0 );
435
436 m_mainSizer->SetFlexibleDirection( wxBOTH );
437 m_mainSizer->AddGrowableCol( 0, 1 );
438
439 SetSizer( m_mainSizer );
440}
441
442
444{
445 wxASSERT( aInfoBar );
446
447 aInfoBar->Reparent( this );
448 m_mainSizer->Add( aInfoBar, 1, wxEXPAND, 0 );
449 m_mainSizer->Layout();
450}
451
452
453void EDA_INFOBAR_PANEL::AddOtherItem( wxWindow* aOtherItem )
454{
455 wxASSERT( aOtherItem );
456
457 aOtherItem->Reparent( this );
458 m_mainSizer->Add( aOtherItem, 1, wxEXPAND, 0 );
459
460 m_mainSizer->AddGrowableRow( 1, 1 );
461 m_mainSizer->Layout();
462}
463
464
465REPORTER& INFOBAR_REPORTER::Report( const wxString& aText, SEVERITY aSeverity )
466{
467 m_message.reset( new wxString( aText ) );
468 m_severity = aSeverity;
469 m_messageSet = true;
470
471 return *this;
472}
473
474
476{
477 return m_message && !m_message->IsEmpty();
478}
479
480
482{
483 // Don't do anything if no message was ever given
484 if( !m_infoBar || !m_messageSet )
485 return;
486
487 // Short circuit if the message is empty and it is already hidden
488 if( !HasMessage() && !m_infoBar->IsShownOnScreen() )
489 return;
490
491 int icon = wxICON_NONE;
492
493 switch( m_severity )
494 {
495 case RPT_SEVERITY_UNDEFINED: icon = wxICON_INFORMATION; break;
496 case RPT_SEVERITY_INFO: icon = wxICON_INFORMATION; break;
497 case RPT_SEVERITY_EXCLUSION: icon = wxICON_WARNING; break;
498 case RPT_SEVERITY_ACTION: icon = wxICON_WARNING; break;
499 case RPT_SEVERITY_WARNING: icon = wxICON_WARNING; break;
500 case RPT_SEVERITY_ERROR: icon = wxICON_ERROR; break;
501 case RPT_SEVERITY_IGNORE: icon = wxICON_INFORMATION; break;
502 case RPT_SEVERITY_DEBUG: icon = wxICON_INFORMATION; break;
503 }
504
505 if( m_message->EndsWith( wxS( "\n" ) ) )
506 *m_message = m_message->Left( m_message->Length() - 1 );
507
508 if( HasMessage() )
510 else
512}
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:430
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:443
void AddOtherItem(wxWindow *aOtherItem)
Add the other item to the panel.
Definition: wx_infobar.cpp:453
WX_INFOBAR * m_infoBar
Definition: wx_infobar.h:348
void Finalize()
Update the infobar with the reported text.
Definition: wx_infobar.cpp:481
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Report a string with a given severity.
Definition: wx_infobar.cpp:465
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:475
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:72
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:351
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:375
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:279
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:400
void onDismissInfoBar(wxCommandEvent &aEvent)
Event handler for dismissing the infobar using a wxCommandEvent of the type KIEVT_DISMISS_INFOBAR.
Definition: wx_infobar.cpp:408
void AddButton(wxButton *aButton)
Add an already created button to the infobar.
Definition: wx_infobar.cpp:307
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:414
wxBitmapButton * GetCloseButton() const
Definition: wx_infobar.cpp:381
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:341
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:420
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