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 m_parent->Unbind( wxEVT_SIZE, &WX_INFOBAR::onSize, this );
112
113 delete m_showTimer;
114}
115
116
117void WX_INFOBAR::SetShowTime( int aTime )
118{
119 m_showTime = aTime;
120}
121
122
123void WX_INFOBAR::QueueShowMessage( const wxString& aMessage, int aFlags )
124{
125 wxCommandEvent* evt = new wxCommandEvent( KIEVT_SHOW_INFOBAR );
126
127 evt->SetString( aMessage.c_str() );
128 evt->SetInt( aFlags );
129
130 GetEventHandler()->QueueEvent( evt );
131}
132
133
135{
136 wxCommandEvent* evt = new wxCommandEvent( KIEVT_DISMISS_INFOBAR );
137
138 GetEventHandler()->QueueEvent( evt );
139}
140
141
142void WX_INFOBAR::ShowMessageFor( const wxString& aMessage, int aTime, int aFlags,
143 MESSAGE_TYPE aType )
144{
145 // Don't do anything if we requested the UI update
146 if( m_updateLock )
147 return;
148
149 m_showTime = aTime;
150 ShowMessage( aMessage, aFlags );
151
152 m_type = aType;
153}
154
155
156void WX_INFOBAR::ShowMessage( const wxString& aMessage, int aFlags )
157{
158 // Don't do anything if we requested the UI update
159 if( m_updateLock )
160 return;
161
162 m_updateLock = true;
163
164 m_message = aMessage;
165 m_message.Trim();
166
167 wxInfoBarGeneric::ShowMessage( m_message, aFlags );
168
169 if( m_auiManager )
170 updateAuiLayout( true );
171
172 if( m_showTime > 0 )
173 m_showTimer->StartOnce( m_showTime );
174
176 m_updateLock = false;
177}
178
179
180void WX_INFOBAR::ShowMessage( const wxString& aMessage, int aFlags, MESSAGE_TYPE aType )
181{
182 // Don't do anything if we requested the UI update
183 if( m_updateLock )
184 return;
185
186 ShowMessage( aMessage, aFlags );
187
188 m_type = aType;
189}
190
191
193{
194 if( !IsShownOnScreen() )
195 return;
196
197 // Don't do anything if we requested the UI update
198 if( m_updateLock )
199 return;
200
201 m_updateLock = true;
202
203 wxInfoBarGeneric::Dismiss();
204
205 if( m_auiManager )
206 updateAuiLayout( false );
207
208 if( m_callback )
209 (*m_callback)();
210
211 m_updateLock = false;
212}
213
214
215void WX_INFOBAR::onThemeChange( wxSysColourChangedEvent& aEvent )
216{
217 wxColour fg, bg;
219 SetBackgroundColour( bg );
220 SetForegroundColour( fg );
221
222 if( wxBitmapButton* btn = GetCloseButton() )
223 {
224 wxString tooltip = btn->GetToolTipText();
226 AddCloseButton( tooltip );
227 }
228}
229
230
231void WX_INFOBAR::onSize( wxSizeEvent& aEvent )
232{
233 int barWidth = GetSize().GetWidth();
234 wxSizer* sizer = GetSizer();
235
236 if( !sizer )
237 return;
238
239 // wx3.3 moved the sizer we previously wanted deeper into sizers...
240 // do we actually still need this for wx3.3?
241 #if wxCHECK_VERSION( 3, 3, 0 )
242 wxSizerItem* outerSizer = sizer->GetItem( (size_t) 0 );
243 wxSizerItem* text = nullptr;
244 if (outerSizer->IsSizer())
245 {
246 wxBoxSizer* innerSizer1 = dynamic_cast<wxBoxSizer*>( outerSizer->GetSizer() );
247 wxBoxSizer* innerSizer2 =
248 dynamic_cast<wxBoxSizer*>( innerSizer1->GetItem((size_t)0)->GetSizer() );
249
250 if( innerSizer2 )
251 text = innerSizer2->GetItem( 1 );
252 }
253 #else
254 wxSizerItem* text = sizer->GetItem( 1 );
255 #endif
256
257 if( text )
258 {
259 if( auto textCtrl = dynamic_cast<wxStaticText*>( text->GetWindow() ) )
260 textCtrl->SetLabelText( m_message );
261 }
262
263 // Calculate the horizontal size: because the infobar is shown on top of the draw canvas
264 // it is adjusted to the canvas width.
265 // On Mac, the canvas is the parent
266 // On other OS the parent is EDA_BASE_FRAME that contains the canvas
267 int parentWidth = m_parent->GetClientSize().GetWidth();
268 EDA_BASE_FRAME* frame = dynamic_cast<EDA_BASE_FRAME*>( m_parent );
269
270 if( frame && frame->GetToolCanvas() )
271 parentWidth = frame->GetToolCanvas()->GetSize().GetWidth();
272
273 if( barWidth != parentWidth )
274 SetSize( parentWidth, GetSize().GetHeight() );
275
276 if( text )
277 {
278 if( auto textCtrl = dynamic_cast<wxStaticText*>( text->GetWindow() ) )
279 {
280 // Re-wrap the text (this is done automatically later but we need it now)
281 // And count how many lines we need. If we have embedded newlines, then
282 // multiply the number of lines by the text min height to find the correct
283 // min height for the control. The min height of the text control will be the size
284 // of a single line of text. This assumes that two lines of text are larger
285 // than the height of the icon for the bar.
286 textCtrl->Wrap( -1 );
287 wxString wrapped_text = textCtrl->GetLabel();
288 int height = ( wrapped_text.Freq( '\n' ) + 1 ) * text->GetMinSize().GetHeight();
289 int margins = text->GetMinSize().GetHeight() - 1;
290 SetMinSize( wxSize( GetSize().GetWidth(), height + margins ) );
291 textCtrl->Wrap( -1 );
292 }
293 }
294
295 aEvent.Skip();
296}
297
298
300{
301 wxASSERT( m_auiManager );
302
303 wxAuiPaneInfo& pane = m_auiManager->GetPane( this );
304
305 // If the infobar is in a pane, then show/hide the pane
306 if( pane.IsOk() )
307 {
308 if( aShow )
309 pane.Show();
310 else
311 pane.Hide();
312 }
313
314 // Update the AUI manager regardless
315 m_auiManager->Update();
316}
317
318
319void WX_INFOBAR::AddButton( wxWindowID aId, const wxString& aLabel )
320{
321 wxButton* button = new wxButton( this, aId, aLabel );
322
323 AddButton( button );
324}
325
326
327void WX_INFOBAR::AddButton( wxButton* aButton )
328{
329 wxSizer* sizer = GetSizer();
330
331 wxASSERT( aButton );
332
333#ifdef __WXMAC__
334 // Based on the code in the original class:
335 // smaller buttons look better in the (narrow) info bar under OS X
336 aButton->SetWindowVariant( wxWINDOW_VARIANT_SMALL );
337#endif // __WXMAC__
338
339 auto element = sizer->Add( aButton, wxSizerFlags( 0 ).Centre().Border( wxRIGHT ) );
340
341 element->SetFlag( wxSTRETCH_MASK );
342
343 if( IsShownOnScreen() )
344 sizer->Layout();
345}
346
347
348void WX_INFOBAR::AddButton( wxHyperlinkCtrl* aHypertextButton )
349{
350 wxSizer* sizer = GetSizer();
351
352 wxASSERT( aHypertextButton );
353
354 sizer->Add( aHypertextButton, wxSizerFlags().Centre().Border( wxRIGHT ).Shaped() );
355
356 if( IsShownOnScreen() )
357 sizer->Layout();
358}
359
360
361void WX_INFOBAR::AddCloseButton( const wxString& aTooltip )
362{
363 wxBitmapButton* button = wxBitmapButton::NewCloseButton( this, ID_CLOSE_INFOBAR );
364
365 button->SetToolTip( aTooltip );
366
367 AddButton( button );
368}
369
370
372{
373 wxSizer* sizer = GetSizer();
374
375 if( sizer->GetItemCount() == 0 )
376 return;
377
378 // The last item is already the spacer
379 if( sizer->GetItem( sizer->GetItemCount() - 1 )->IsSpacer() )
380 return;
381
382 for( int i = sizer->GetItemCount() - 1; i >= 0; i-- )
383 {
384 wxSizerItem* sItem = sizer->GetItem( i );
385
386 // The spacer is the end of the custom buttons
387 if( sItem->IsSpacer() )
388 break;
389
390 delete sItem->GetWindow();
391 }
392}
393
394
396{
397 return GetCloseButton();
398}
399
400
401wxBitmapButton* WX_INFOBAR::GetCloseButton() const
402{
403 wxSizer* sizer = GetSizer();
404
405 if( !sizer )
406 return nullptr;
407
408 if( sizer->GetItemCount() == 0 )
409 return nullptr;
410
411 if( sizer->GetItem( sizer->GetItemCount() - 1 )->IsSpacer() )
412 return nullptr;
413
414 wxSizerItem* item = sizer->GetItem( sizer->GetItemCount() - 1 );
415
416 if( item && item->GetWindow() && item->GetWindow()->GetId() == ID_CLOSE_INFOBAR )
417 return static_cast<wxBitmapButton*>( item->GetWindow() );
418
419 return nullptr;
420}
421
422
423void WX_INFOBAR::onShowInfoBar( wxCommandEvent& aEvent )
424{
427 ShowMessage( aEvent.GetString(), aEvent.GetInt() );
428}
429
430
431void WX_INFOBAR::onDismissInfoBar( wxCommandEvent& aEvent )
432{
433 Dismiss();
434}
435
436
437void WX_INFOBAR::onCloseButton( wxCommandEvent& aEvent )
438{
439 Dismiss();
440}
441
442
443void WX_INFOBAR::onTimer( wxTimerEvent& aEvent )
444{
445 // Reset and clear the timer
446 m_showTimer->Stop();
447 m_showTime = 0;
448
449 Dismiss();
450}
451
452
453EDA_INFOBAR_PANEL::EDA_INFOBAR_PANEL( wxWindow* aParent, wxWindowID aId, const wxPoint& aPos,
454 const wxSize& aSize, long aStyle, const wxString& aName )
455 : wxPanel( aParent, aId, aPos, aSize, aStyle, aName )
456{
457 m_mainSizer = new wxFlexGridSizer( 1, 0, 0 );
458
459 m_mainSizer->SetFlexibleDirection( wxBOTH );
460 m_mainSizer->AddGrowableCol( 0, 1 );
461
462 SetSizer( m_mainSizer );
463}
464
465
467{
468 wxASSERT( aInfoBar );
469
470 aInfoBar->Reparent( this );
471 m_mainSizer->Add( aInfoBar, 1, wxEXPAND, 0 );
472 m_mainSizer->Layout();
473}
474
475
476void EDA_INFOBAR_PANEL::AddOtherItem( wxWindow* aOtherItem )
477{
478 wxASSERT( aOtherItem );
479
480 aOtherItem->Reparent( this );
481 m_mainSizer->Add( aOtherItem, 1, wxEXPAND, 0 );
482
483 m_mainSizer->AddGrowableRow( 1, 1 );
484 m_mainSizer->Layout();
485}
486
487
488REPORTER& INFOBAR_REPORTER::Report( const wxString& aText, SEVERITY aSeverity )
489{
490 m_message.reset( new wxString( aText ) );
491 m_severity = aSeverity;
492 m_messageSet = true;
493
494 return *this;
495}
496
497
499{
500 return m_message && !m_message->IsEmpty();
501}
502
503
505{
506 // Don't do anything if no message was ever given
507 if( !m_infoBar || !m_messageSet )
508 return;
509
510 // Short circuit if the message is empty and it is already hidden
511 if( !HasMessage() && !m_infoBar->IsShownOnScreen() )
512 return;
513
514 int icon = wxICON_NONE;
515
516 switch( m_severity )
517 {
518 case RPT_SEVERITY_UNDEFINED: icon = wxICON_INFORMATION; break;
519 case RPT_SEVERITY_INFO: icon = wxICON_INFORMATION; break;
520 case RPT_SEVERITY_EXCLUSION: icon = wxICON_WARNING; break;
521 case RPT_SEVERITY_ACTION: icon = wxICON_WARNING; break;
522 case RPT_SEVERITY_WARNING: icon = wxICON_WARNING; break;
523 case RPT_SEVERITY_ERROR: icon = wxICON_ERROR; break;
524 case RPT_SEVERITY_IGNORE: icon = wxICON_INFORMATION; break;
525 case RPT_SEVERITY_DEBUG: icon = wxICON_INFORMATION; break;
526 }
527
528 if( m_message->EndsWith( wxS( "\n" ) ) )
529 *m_message = m_message->Left( m_message->Length() - 1 );
530
531 if( HasMessage() )
533 else
535}
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:453
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:466
void AddOtherItem(wxWindow *aOtherItem)
Add the other item to the panel.
Definition: wx_infobar.cpp:476
WX_INFOBAR * m_infoBar
Definition: wx_infobar.h:348
void Finalize()
Update the infobar with the reported text.
Definition: wx_infobar.cpp:504
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Report a string with a given severity.
Definition: wx_infobar.cpp:488
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:498
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:117
void RemoveAllButtons()
Remove all the buttons that have been added by the user.
Definition: wx_infobar.cpp:371
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:142
bool HasCloseButton() const
Definition: wx_infobar.cpp:395
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:299
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:423
void onDismissInfoBar(wxCommandEvent &aEvent)
Event handler for dismissing the infobar using a wxCommandEvent of the type KIEVT_DISMISS_INFOBAR.
Definition: wx_infobar.cpp:431
void AddButton(wxButton *aButton)
Add an already created button to the infobar.
Definition: wx_infobar.cpp:327
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:123
void onCloseButton(wxCommandEvent &aEvent)
Event handler for the close button.
Definition: wx_infobar.cpp:437
wxBitmapButton * GetCloseButton() const
Definition: wx_infobar.cpp:401
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
Definition: wx_infobar.cpp:192
void onThemeChange(wxSysColourChangedEvent &aEvent)
Event handler for the color theme change event.
Definition: wx_infobar.cpp:215
void AddCloseButton(const wxString &aTooltip=_("Hide this message."))
Add the default close button to the infobar on the right side.
Definition: wx_infobar.cpp:361
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:443
void ShowMessage(const wxString &aMessage, int aFlags=wxICON_INFORMATION) override
Show the info bar with the provided message and icon.
Definition: wx_infobar.cpp:156
wxAuiManager * m_auiManager
The AUI manager that contains this infobar.
Definition: wx_infobar.h:263
void onSize(wxSizeEvent &aEvent)
Definition: wx_infobar.cpp:231
void QueueDismiss()
Send the infobar an event telling it to hide itself.
Definition: wx_infobar.cpp:134
Base window classes and related definitions.
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