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 (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/wx_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#ifdef __WXMSW__
35#include <dpi_scaling_common.h>
36#endif
37
38
39wxDEFINE_EVENT( KIEVT_SHOW_INFOBAR, wxCommandEvent );
40wxDEFINE_EVENT( KIEVT_DISMISS_INFOBAR, wxCommandEvent );
41
42BEGIN_EVENT_TABLE( WX_INFOBAR, wxInfoBarGeneric )
43 EVT_COMMAND( wxID_ANY, KIEVT_SHOW_INFOBAR, WX_INFOBAR::onShowInfoBar )
44 EVT_COMMAND( wxID_ANY, KIEVT_DISMISS_INFOBAR, WX_INFOBAR::onDismissInfoBar )
45
48END_EVENT_TABLE()
49
50
51WX_INFOBAR::WX_INFOBAR( wxWindow* aParent, wxAuiManager* aMgr, wxWindowID aWinid )
52 : wxInfoBarGeneric( aParent, aWinid ),
53 m_showTime( 0 ),
54 m_updateLock( false ),
55 m_showTimer( nullptr ),
56 m_auiManager( aMgr ),
57 m_type( MESSAGE_TYPE::GENERIC )
58{
59 m_showTimer = new wxTimer( this, ID_CLOSE_INFOBAR );
60
61#ifdef __WXMAC__
62 // wxWidgets hard-codes wxSYS_COLOUR_INFOBK to { 0xFF, 0xFF, 0xD3 } on Mac.
64 SetBackgroundColour( wxColour( 28, 27, 20 ) );
65 else
66 SetBackgroundColour( wxColour( 255, 249, 189 ) );
67
68 // Infobar is broken on Mac without the effects
69 SetShowHideEffects( wxSHOW_EFFECT_ROLL_TO_BOTTOM, wxSHOW_EFFECT_ROLL_TO_TOP );
70 SetEffectDuration( 200 );
71#else
72 // Infobar freezes canvas on Windows with the effect, and GTK looks bad with it
73 SetShowHideEffects( wxSHOW_EFFECT_NONE, wxSHOW_EFFECT_NONE );
74#endif
75
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 wxString msg = aMessage;
163 msg.Trim();
164
165 wxInfoBarGeneric::ShowMessage( msg, 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::onSize( wxSizeEvent& aEvent )
214{
215 int barWidth = GetSize().GetWidth();
216
217 // Calculate the horizontal size: because the infobar is shown on top of the draw canvas
218 // it is adjusted to the canvas width.
219 // On Mac, the canvas is the parent
220 // On other OS the parent is EDA_BASE_FRAME that contains the canvas
221 int parentWidth = m_parent->GetClientSize().GetWidth();
222 EDA_BASE_FRAME* frame = dynamic_cast<EDA_BASE_FRAME*>( m_parent );
223
224 if( frame && frame->GetToolCanvas() )
225 parentWidth = frame->GetToolCanvas()->GetSize().GetWidth();
226
227
228 if( barWidth != parentWidth )
229 SetSize( parentWidth, GetSize().GetHeight() );
230
231 aEvent.Skip();
232}
233
234
236{
237 wxASSERT( m_auiManager );
238
239 wxAuiPaneInfo& pane = m_auiManager->GetPane( this );
240
241 // If the infobar is in a pane, then show/hide the pane
242 if( pane.IsOk() )
243 {
244 if( aShow )
245 pane.Show();
246 else
247 pane.Hide();
248 }
249
250 // Update the AUI manager regardless
251 m_auiManager->Update();
252}
253
254
255void WX_INFOBAR::AddButton( wxWindowID aId, const wxString& aLabel )
256{
257 wxButton* button = new wxButton( this, aId, aLabel );
258
259 AddButton( button );
260}
261
262
263void WX_INFOBAR::AddButton( wxButton* aButton )
264{
265 wxSizer* sizer = GetSizer();
266
267 wxASSERT( aButton );
268
269#ifdef __WXMAC__
270 // Based on the code in the original class:
271 // smaller buttons look better in the (narrow) info bar under OS X
272 aButton->SetWindowVariant( wxWINDOW_VARIANT_SMALL );
273#endif // __WXMAC__
274 sizer->Add( aButton, wxSizerFlags().Centre().Border( wxRIGHT ) );
275
276 if( IsShownOnScreen() )
277 sizer->Layout();
278}
279
280
281void WX_INFOBAR::AddButton( wxHyperlinkCtrl* aHypertextButton )
282{
283 wxSizer* sizer = GetSizer();
284
285 wxASSERT( aHypertextButton );
286
287 sizer->Add( aHypertextButton, wxSizerFlags().Centre().Border( wxRIGHT ) );
288
289 if( IsShownOnScreen() )
290 sizer->Layout();
291}
292
293
294void WX_INFOBAR::AddCloseButton( const wxString& aTooltip )
295{
296 wxBitmapButton* button = wxBitmapButton::NewCloseButton( this, ID_CLOSE_INFOBAR );
297
298 button->SetToolTip( aTooltip );
299
300 AddButton( button );
301}
302
303
305{
306 wxSizer* sizer = GetSizer();
307
308 if( sizer->GetItemCount() == 0 )
309 return;
310
311 // The last item is already the spacer
312 if( sizer->GetItem( sizer->GetItemCount() - 1 )->IsSpacer() )
313 return;
314
315 for( int i = sizer->GetItemCount() - 1; i >= 0; i-- )
316 {
317 wxSizerItem* sItem = sizer->GetItem( i );
318
319 // The spacer is the end of the custom buttons
320 if( sItem->IsSpacer() )
321 break;
322
323 delete sItem->GetWindow();
324 }
325}
326
327
329{
330 wxSizer* sizer = GetSizer();
331
332 if( sizer->GetItemCount() == 0 )
333 return false;
334
335 if( sizer->GetItem( sizer->GetItemCount() - 1 )->IsSpacer() )
336 return false;
337
338 wxSizerItem* item = sizer->GetItem( sizer->GetItemCount() - 1 );
339
340 return ( item->GetWindow()->GetId() == ID_CLOSE_INFOBAR );
341}
342
343
344void WX_INFOBAR::onShowInfoBar( wxCommandEvent& aEvent )
345{
348 ShowMessage( aEvent.GetString(), aEvent.GetInt() );
349}
350
351
352void WX_INFOBAR::onDismissInfoBar( wxCommandEvent& aEvent )
353{
354 Dismiss();
355}
356
357
358void WX_INFOBAR::onCloseButton( wxCommandEvent& aEvent )
359{
360 Dismiss();
361}
362
363
364void WX_INFOBAR::onTimer( wxTimerEvent& aEvent )
365{
366 // Reset and clear the timer
367 m_showTimer->Stop();
368 m_showTime = 0;
369
370 Dismiss();
371}
372
373
374EDA_INFOBAR_PANEL::EDA_INFOBAR_PANEL( wxWindow* aParent, wxWindowID aId, const wxPoint& aPos,
375 const wxSize& aSize, long aStyle, const wxString& aName )
376 : wxPanel( aParent, aId, aPos, aSize, aStyle, aName )
377{
378 m_mainSizer = new wxFlexGridSizer( 1, 0, 0 );
379
380 m_mainSizer->SetFlexibleDirection( wxBOTH );
381 m_mainSizer->AddGrowableCol( 0, 1 );
382
383 SetSizer( m_mainSizer );
384}
385
386
388{
389 wxASSERT( aInfoBar );
390
391 aInfoBar->Reparent( this );
392 m_mainSizer->Add( aInfoBar, 1, wxEXPAND, 0 );
393 m_mainSizer->Layout();
394}
395
396
397void EDA_INFOBAR_PANEL::AddOtherItem( wxWindow* aOtherItem )
398{
399 wxASSERT( aOtherItem );
400
401 aOtherItem->Reparent( this );
402 m_mainSizer->Add( aOtherItem, 1, wxEXPAND, 0 );
403
404 m_mainSizer->AddGrowableRow( 1, 1 );
405 m_mainSizer->Layout();
406}
407
408
409REPORTER& INFOBAR_REPORTER::Report( const wxString& aText, SEVERITY aSeverity )
410{
411 m_message.reset( new wxString( aText ) );
412 m_severity = aSeverity;
413 m_messageSet = true;
414
415 return *this;
416}
417
418
420{
421 return m_message && !m_message->IsEmpty();
422}
423
424
426{
427 // Don't do anything if no message was ever given
428 if( !m_infoBar || !m_messageSet )
429 return;
430
431 // Short circuit if the message is empty and it is already hidden
432 if( !HasMessage() && !m_infoBar->IsShownOnScreen() )
433 return;
434
435 int icon = wxICON_NONE;
436
437 switch( m_severity )
438 {
439 case RPT_SEVERITY_UNDEFINED: icon = wxICON_INFORMATION; break;
440 case RPT_SEVERITY_INFO: icon = wxICON_INFORMATION; break;
441 case RPT_SEVERITY_EXCLUSION: icon = wxICON_WARNING; break;
442 case RPT_SEVERITY_ACTION: icon = wxICON_WARNING; break;
443 case RPT_SEVERITY_WARNING: icon = wxICON_WARNING; break;
444 case RPT_SEVERITY_ERROR: icon = wxICON_ERROR; break;
445 case RPT_SEVERITY_IGNORE: icon = wxICON_INFORMATION; break;
446 case RPT_SEVERITY_DEBUG: icon = wxICON_INFORMATION; break;
447 }
448
449 if( m_message->EndsWith( wxS( "\n" ) ) )
450 *m_message = m_message->Left( m_message->Length() - 1 );
451
452 if( HasMessage() )
454 else
456}
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:374
wxFlexGridSizer * m_mainSizer
Definition: wx_infobar.h:305
void AddInfoBar(WX_INFOBAR *aInfoBar)
Add the given infobar object to the panel.
Definition: wx_infobar.cpp:387
void AddOtherItem(wxWindow *aOtherItem)
Add the other item to the panel.
Definition: wx_infobar.cpp:397
WX_INFOBAR * m_infoBar
Definition: wx_infobar.h:340
void Finalize()
Update the infobar with the reported text.
Definition: wx_infobar.cpp:425
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Report a string with a given severity.
Definition: wx_infobar.cpp:409
SEVERITY m_severity
Definition: wx_infobar.h:342
std::unique_ptr< wxString > m_message
Definition: wx_infobar.h:341
bool HasMessage() const override
Returns true if the reporter client is non-empty.
Definition: wx_infobar.cpp:419
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:304
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:328
MESSAGE_TYPE m_type
The type of message being displayed.
Definition: wx_infobar.h:257
void updateAuiLayout(bool aShow)
Update the AUI pane to show or hide this infobar.
Definition: wx_infobar.cpp:235
std::optional< std::function< void(void)> > m_callback
Optional callback made when closing infobar.
Definition: wx_infobar.h:259
int m_showTime
The time to show the infobar. 0 = don't auto hide.
Definition: wx_infobar.h:253
bool m_updateLock
True if this infobar requested the UI update.
Definition: wx_infobar.h:254
void onShowInfoBar(wxCommandEvent &aEvent)
Event handler for showing the infobar using a wxCommandEvent of the type KIEVT_SHOW_INFOBAR.
Definition: wx_infobar.cpp:344
void onDismissInfoBar(wxCommandEvent &aEvent)
Event handler for dismissing the infobar using a wxCommandEvent of the type KIEVT_DISMISS_INFOBAR.
Definition: wx_infobar.cpp:352
void AddButton(wxButton *aButton)
Add an already created button to the infobar.
Definition: wx_infobar.cpp:263
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:358
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
Definition: wx_infobar.cpp:190
void AddCloseButton(const wxString &aTooltip=_("Hide this message."))
Add the default close button to the infobar on the right side.
Definition: wx_infobar.cpp:294
wxTimer * m_showTimer
The timer counting the autoclose period.
Definition: wx_infobar.h:255
void onTimer(wxTimerEvent &aEvent)
Event handler for the automatic closing timer.
Definition: wx_infobar.cpp:364
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:256
void onSize(wxSizeEvent &aEvent)
Definition: wx_infobar.cpp:213
void QueueDismiss()
Send the infobar an event telling it to hide itself.
Definition: wx_infobar.cpp:132
Base window classes and related definitions.
bool IsDarkTheme()
Determine if the desktop interface is currently using a dark theme or a light theme.
Definition: wxgtk/ui.cpp:48
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