KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_shim.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) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
5 * Copyright (C) 2023 CERN
6 * Copyright (C) 2012-2023 KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <dialog_shim.h>
27#include <core/ignore.h>
28#include <kiway_player.h>
29#include <kiway.h>
30#include <pgm_base.h>
31#include <tool/tool_manager.h>
32#include <kiplatform/ui.h>
33
34#include <wx/display.h>
35#include <wx/evtloop.h>
36#include <wx/app.h>
37#include <wx/event.h>
38#include <wx/grid.h>
39#include <wx/bmpbuttn.h>
40#include <wx/textctrl.h>
41#include <wx/stc/stc.h>
42
43#include <algorithm>
44
47{
48 wxWindow* m_win;
49
50public:
51
52 WDO_ENABLE_DISABLE( wxWindow* aWindow ) :
53 m_win( aWindow )
54 {
55 if( m_win )
56 m_win->Disable();
57 }
58
60 {
61 if( m_win )
62 {
63 m_win->Enable();
64 m_win->Raise(); // let's focus back on the parent window
65 }
66 }
67};
68
69
70BEGIN_EVENT_TABLE( DIALOG_SHIM, wxDialog )
71 EVT_CHAR_HOOK( DIALOG_SHIM::OnCharHook )
72END_EVENT_TABLE()
73
74
75DIALOG_SHIM::DIALOG_SHIM( wxWindow* aParent, wxWindowID id, const wxString& title,
76 const wxPoint& pos, const wxSize& size, long style,
77 const wxString& name ) :
78 wxDialog( aParent, id, title, pos, size, style, name ),
79 KIWAY_HOLDER( nullptr, KIWAY_HOLDER::DIALOG ),
80 m_units( EDA_UNITS::MILLIMETRES ),
81 m_useCalculatedSize( false ),
82 m_firstPaintEvent( true ),
83 m_initialFocusTarget( nullptr ),
84 m_isClosing( false ),
85 m_qmodal_loop( nullptr ),
86 m_qmodal_showing( false ),
87 m_qmodal_parent_disabler( nullptr ),
88 m_parentFrame( nullptr )
89{
90 KIWAY_HOLDER* kiwayHolder = nullptr;
91 m_initialSize = size;
92
93 if( aParent )
94 {
95 kiwayHolder = dynamic_cast<KIWAY_HOLDER*>( aParent );
96
97 while( !kiwayHolder && aParent->GetParent() )
98 {
99 aParent = aParent->GetParent();
100 kiwayHolder = dynamic_cast<KIWAY_HOLDER*>( aParent );
101 }
102 }
103
104 // Inherit units from parent
105 if( kiwayHolder && kiwayHolder->GetType() == KIWAY_HOLDER::FRAME )
106 m_units = static_cast<EDA_BASE_FRAME*>( kiwayHolder )->GetUserUnits();
107 else if( kiwayHolder && kiwayHolder->GetType() == KIWAY_HOLDER::DIALOG )
108 m_units = static_cast<DIALOG_SHIM*>( kiwayHolder )->GetUserUnits();
109
110 // Don't mouse-warp after a dialog run from the context menu
111 if( kiwayHolder && kiwayHolder->GetType() == KIWAY_HOLDER::FRAME )
112 {
113 m_parentFrame = static_cast<EDA_BASE_FRAME*>( kiwayHolder );
114 TOOL_MANAGER* toolMgr = m_parentFrame->GetToolManager();
115
116 if( toolMgr && toolMgr->IsContextMenuActive() )
117 toolMgr->VetoContextMenuMouseWarp();
118 }
119
120 // Set up the message bus
121 if( kiwayHolder )
122 SetKiway( this, &kiwayHolder->Kiway() );
123
124 if( HasKiway() )
125 Kiway().SetBlockingDialog( this );
126
127 Bind( wxEVT_CLOSE_WINDOW, &DIALOG_SHIM::OnCloseWindow, this );
128 Bind( wxEVT_BUTTON, &DIALOG_SHIM::OnButton, this );
129
130#ifdef __WINDOWS__
131 // On Windows, the app top windows can be brought to the foreground (at least temporarily)
132 // in certain circumstances such as when calling an external tool in Eeschema BOM generation.
133 // So set the parent frame (if exists) to top window to avoid this annoying behavior.
134 if( kiwayHolder && kiwayHolder->GetType() == KIWAY_HOLDER::FRAME )
135 Pgm().App().SetTopWindow( (EDA_BASE_FRAME*) kiwayHolder );
136#endif
137
138 Bind( wxEVT_PAINT, &DIALOG_SHIM::OnPaint, this );
139}
140
141
143{
144 m_isClosing = true;
145
146 Unbind( wxEVT_CLOSE_WINDOW, &DIALOG_SHIM::OnCloseWindow, this );
147 Unbind( wxEVT_BUTTON, &DIALOG_SHIM::OnButton, this );
148 Unbind( wxEVT_PAINT, &DIALOG_SHIM::OnPaint, this );
149
150 std::function<void( wxWindowList& )> disconnectFocusHandlers = [&]( wxWindowList& children )
151 {
152 for( wxWindow* child : children )
153 {
154 if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( child ) )
155 {
156 textCtrl->Disconnect( wxEVT_SET_FOCUS,
157 wxFocusEventHandler( DIALOG_SHIM::onChildSetFocus ),
158 nullptr, this );
159 }
160 else if( wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( child ) )
161 {
162 scintilla->Disconnect( wxEVT_SET_FOCUS,
163 wxFocusEventHandler( DIALOG_SHIM::onChildSetFocus ),
164 nullptr, this );
165 }
166 else
167 {
168 disconnectFocusHandlers( child->GetChildren() );
169 }
170 }
171 };
172
173 disconnectFocusHandlers( GetChildren() );
174
175 // if the dialog is quasi-modal, this will end its event loop
176 if( IsQuasiModal() )
177 EndQuasiModal( wxID_CANCEL );
178
179 if( HasKiway() )
180 Kiway().SetBlockingDialog( nullptr );
181
183}
184
185
187{
188 // must be called from the constructor of derived classes,
189 // when all widgets are initialized, and therefore their size fixed
190
191 // SetSizeHints fixes the minimal size of sizers in the dialog
192 // (SetSizeHints calls Fit(), so no need to call it)
193 GetSizer()->SetSizeHints( this );
194}
195
196
197void DIALOG_SHIM::setSizeInDU( int x, int y )
198{
199 wxSize sz( x, y );
200 SetSize( ConvertDialogToPixels( sz ) );
201}
202
203
205{
206 wxSize sz( x, 0 );
207 return ConvertDialogToPixels( sz ).x;
208}
209
210
212{
213 wxSize sz( 0, y );
214 return ConvertDialogToPixels( sz ).y;
215}
216
217
218// our hashtable is an implementation secret, don't need or want it in a header file
219#include <hashtables.h>
220#include <typeinfo>
221
222static std::unordered_map<std::string, wxRect> class_map;
223
224
225void DIALOG_SHIM::SetPosition( const wxPoint& aNewPosition )
226{
227 wxDialog::SetPosition( aNewPosition );
228
229 // Now update the stored position:
230 const char* hash_key;
231
232 if( m_hash_key.size() )
233 {
234 // a special case like EDA_LIST_DIALOG, which has multiple uses.
235 hash_key = m_hash_key.c_str();
236 }
237 else
238 {
239 hash_key = typeid(*this).name();
240 }
241
242 std::unordered_map<std::string, wxRect>::iterator it = class_map.find( hash_key );
243
244 if( it == class_map.end() )
245 return;
246
247 wxRect rect = it->second;
248 rect.SetPosition( aNewPosition );
249
250 class_map[ hash_key ] = rect;
251}
252
253
254bool DIALOG_SHIM::Show( bool show )
255{
256 bool ret;
257 const char* hash_key;
258
259 if( m_hash_key.size() )
260 {
261 // a special case like EDA_LIST_DIALOG, which has multiple uses.
262 hash_key = m_hash_key.c_str();
263 }
264 else
265 {
266 hash_key = typeid(*this).name();
267 }
268
269 // Show or hide the window. If hiding, save current position and size.
270 // If showing, use previous position and size.
271 if( show )
272 {
273#ifndef __WINDOWS__
274 wxDialog::Raise(); // Needed on OS X and some other window managers (i.e. Unity)
275#endif
276 ret = wxDialog::Show( show );
277
278 // classname is key, returns a zeroed-out default wxRect if none existed before.
279 wxRect savedDialogRect = class_map[ hash_key ];
280
281 if( savedDialogRect.GetSize().x != 0 && savedDialogRect.GetSize().y != 0 )
282 {
284 {
285 SetSize( savedDialogRect.GetPosition().x, savedDialogRect.GetPosition().y,
286 wxDialog::GetSize().x, wxDialog::GetSize().y, 0 );
287 }
288 else
289 {
290 SetSize( savedDialogRect.GetPosition().x, savedDialogRect.GetPosition().y,
291 std::max( wxDialog::GetSize().x, savedDialogRect.GetSize().x ),
292 std::max( wxDialog::GetSize().y, savedDialogRect.GetSize().y ),
293 0 );
294 }
295#ifdef __WXMAC__
296 if( m_parent != nullptr )
297 {
298 if( wxDisplay::GetFromPoint( m_parent->GetPosition() )
299 != wxDisplay::GetFromPoint( savedDialogRect.GetPosition() ) )
300 Centre();
301 }
302#endif
303 }
304 else if( m_initialSize != wxDefaultSize )
305 {
306 SetSize( m_initialSize );
307 Centre();
308 }
309
310 // Be sure that the dialog appears in a visible area
311 // (the dialog position might have been stored at the time when it was
312 // shown on another display)
313 if( wxDisplay::GetFromWindow( this ) == wxNOT_FOUND )
314 Centre();
315 }
316 else
317 {
318 // Save the dialog's position & size before hiding, using classname as key
319 class_map[ hash_key ] = wxRect( wxDialog::GetPosition(), wxDialog::GetSize() );
320
321#ifdef __WXMAC__
322 if ( m_eventLoop )
323 m_eventLoop->Exit( GetReturnCode() ); // Needed for APP-MODAL dlgs on OSX
324#endif
325
326 ret = wxDialog::Show( show );
327
328 if( m_parent )
329 m_parent->SetFocus();
330 }
331
332 return ret;
333}
334
335
337{
338 const char* hash_key;
339
340 if( m_hash_key.size() )
341 {
342 // a special case like EDA_LIST_DIALOG, which has multiple uses.
343 hash_key = m_hash_key.c_str();
344 }
345 else
346 {
347 hash_key = typeid(*this).name();
348 }
349
350 std::unordered_map<std::string, wxRect>::iterator it = class_map.find( hash_key );
351
352 if( it == class_map.end() )
353 return;
354
355 wxRect rect = it->second;
356 rect.SetSize( wxSize( 0, 0 ) );
357 class_map[ hash_key ] = rect;
358}
359
360
361bool DIALOG_SHIM::Enable( bool enable )
362{
363 // so we can do logging of this state change:
364 return wxDialog::Enable( enable );
365}
366
367
368// Recursive descent doing a SelectAll() in wxTextCtrls.
369// MacOS User Interface Guidelines state that when tabbing to a text control all its
370// text should be selected. Since wxWidgets fails to implement this, we do it here.
371void DIALOG_SHIM::SelectAllInTextCtrls( wxWindowList& children )
372{
373 for( wxWindow* child : children )
374 {
375 if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( child ) )
376 {
377 m_beforeEditValues[ textCtrl ] = textCtrl->GetValue();
378 textCtrl->Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( DIALOG_SHIM::onChildSetFocus ),
379 nullptr, this );
380
381 // We don't currently run this on GTK because some window managers don't hide the
382 // selection in non-active controls, and other window managers do the selection
383 // automatically anyway.
384#if defined( __WXMAC__ ) || defined( __WXMSW__ )
385 if( !textCtrl->GetStringSelection().IsEmpty() )
386 {
387 // Respect an existing selection
388 }
389 else if( textCtrl->IsEditable() )
390 {
391 textCtrl->SelectAll();
392 }
393#else
394 ignore_unused( textCtrl );
395#endif
396 }
397 else if( wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( child ) )
398 {
399 m_beforeEditValues[ scintilla ] = scintilla->GetText();
400 scintilla->Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( DIALOG_SHIM::onChildSetFocus ),
401 nullptr, this );
402
403 if( !scintilla->GetSelectedText().IsEmpty() )
404 {
405 // Respect an existing selection
406 }
407 else if( scintilla->GetMarginWidth( 0 ) > 0 )
408 {
409 // Don't select-all in Custom Rules, etc.
410 }
411 else if( scintilla->IsEditable() )
412 {
413 scintilla->SelectAll();
414 }
415 }
416#ifdef __WXMAC__
417 // Temp hack for square (looking) buttons on OSX. Will likely be made redundant
418 // by the image store....
419 else if( dynamic_cast<wxBitmapButton*>( child ) != nullptr )
420 {
421 wxSize minSize( 29, 27 );
422 wxRect rect = child->GetRect();
423
424 child->ConvertDialogToPixels( minSize );
425
426 rect.Inflate( std::max( 0, minSize.x - rect.GetWidth() ),
427 std::max( 0, minSize.y - rect.GetHeight() ) );
428
429 child->SetMinSize( rect.GetSize() );
430 child->SetSize( rect );
431 }
432#endif
433 else
434 {
435 SelectAllInTextCtrls( child->GetChildren() );
436 }
437 }
438}
439
440
441void DIALOG_SHIM::OnPaint( wxPaintEvent &event )
442{
444 {
446
447 SelectAllInTextCtrls( GetChildren() );
448
451 else
452 KIPLATFORM::UI::ForceFocus( this ); // Focus the dialog itself
453
454 m_firstPaintEvent = false;
455 }
456
457 event.Skip();
458}
459
460
462{
463 if( !GetTitle().StartsWith( wxS( "*" ) ) )
464 SetTitle( wxS( "*" ) + GetTitle() );
465}
466
467
469{
470 if( GetTitle().StartsWith( wxS( "*" ) ) )
471 SetTitle( GetTitle().AfterFirst( '*' ) );
472}
473
475{
476 // Apple in its infinite wisdom will raise a disabled window before even passing
477 // us the event, so we have no way to stop it. Instead, we must set an order on
478 // the windows so that the modal will be pushed in front of the disabled
479 // window when it is raised.
481
482 // Call the base class ShowModal() method
483 return wxDialog::ShowModal();
484}
485
486/*
487 Quasi-Modal Mode Explained:
488
489 The gtk calls in wxDialog::ShowModal() cause event routing problems if that
490 modal dialog then tries to use KIWAY_PLAYER::ShowModal(). The latter shows up
491 and mostly works but does not respond to the window decoration close button.
492 There is no way to get around this without reversing the gtk calls temporarily.
493
494 Quasi-Modal mode is our own almost modal mode which disables only the parent
495 of the DIALOG_SHIM, leaving other frames operable and while staying captured in the
496 nested event loop. This avoids the gtk calls and leaves event routing pure
497 and sufficient to operate the KIWAY_PLAYER::ShowModal() properly. When using
498 ShowQuasiModal() you have to use EndQuasiModal() in your dialogs and not
499 EndModal(). There is also IsQuasiModal() but its value can only be true
500 when the nested event loop is active. Do not mix the modal and quasi-modal
501 functions. Use one set or the other.
502
503 You might find this behavior preferable over a pure modal mode, and it was said
504 that only the Mac has this natively, but now other platforms have something
505 similar. You CAN use it anywhere for any dialog. But you MUST use it when
506 you want to use KIWAY_PLAYER::ShowModal() from a dialog event.
507*/
508
510{
511 // This is an exception safe way to zero a pointer before returning.
512 // Yes, even though DismissModal() clears this first normally, this is
513 // here in case there's an exception before the dialog is dismissed.
514 struct NULLER
515 {
516 void*& m_what;
517 NULLER( void*& aPtr ) : m_what( aPtr ) {}
518 ~NULLER() { m_what = nullptr; } // indeed, set it to NULL on destruction
519 } clear_this( (void*&) m_qmodal_loop );
520
521 // release the mouse if it's currently captured as the window having it
522 // will be disabled when this dialog is shown -- but will still keep the
523 // capture making it impossible to do anything in the modal dialog itself
524 wxWindow* win = wxWindow::GetCapture();
525 if( win )
526 win->ReleaseMouse();
527
528 // Get the optimal parent
529 wxWindow* parent = GetParentForModalDialog( GetParent(), GetWindowStyle() );
530
531 wxASSERT_MSG( !m_qmodal_parent_disabler, wxT( "Caller using ShowQuasiModal() twice on same "
532 "window?" ) );
533
534 // quasi-modal: disable only my "optimal" parent
536
537 // Apple in its infinite wisdom will raise a disabled window before even passing
538 // us the event, so we have no way to stop it. Instead, we must set an order on
539 // the windows so that the quasi-modal will be pushed in front of the disabled
540 // window when it is raised.
542
543 Show( true );
544
545 m_qmodal_showing = true;
546
547 wxGUIEventLoop event_loop;
548
549 m_qmodal_loop = &event_loop;
550
551 event_loop.Run();
552
553 m_qmodal_showing = false;
554
555 if( parent )
556 parent->SetFocus();
557
558 return GetReturnCode();
559}
560
561
562void DIALOG_SHIM::EndQuasiModal( int retCode )
563{
564 // Hook up validator and transfer data from controls handling so quasi-modal dialogs
565 // handle validation in the same way as other dialogs.
566 if( ( retCode == wxID_OK ) && ( !Validate() || !TransferDataFromWindow() ) )
567 return;
568
569 SetReturnCode( retCode );
570
571 if( !IsQuasiModal() )
572 {
573 wxFAIL_MSG( wxT( "Either DIALOG_SHIM::EndQuasiModal was called twice, or ShowQuasiModal"
574 "wasn't called" ) );
575 return;
576 }
577
578 if( m_qmodal_loop )
579 {
580 if( m_qmodal_loop->IsRunning() )
581 m_qmodal_loop->Exit( 0 );
582 else
583 m_qmodal_loop->ScheduleExit( 0 );
584
585 m_qmodal_loop = nullptr;
586 }
587
589 m_qmodal_parent_disabler = nullptr;
590
591 Show( false );
592}
593
594
595void DIALOG_SHIM::OnCloseWindow( wxCloseEvent& aEvent )
596{
597 if( IsQuasiModal() )
598 {
599 EndQuasiModal( wxID_CANCEL );
600 return;
601 }
602
603 // This is mandatory to allow wxDialogBase::OnCloseWindow() to be called.
604 aEvent.Skip();
605}
606
607
608void DIALOG_SHIM::OnButton( wxCommandEvent& aEvent )
609{
610 const int id = aEvent.GetId();
611
612 if( IsQuasiModal() )
613 {
614 if( id == GetAffirmativeId() )
615 {
616 EndQuasiModal( id );
617 }
618 else if( id == wxID_APPLY )
619 {
620 // Dialogs that provide Apply buttons should make sure data is valid before
621 // allowing a transfer, as there is no other way to indicate failure
622 // (i.e. the dialog can't refuse to close as it might with OK, because it
623 // isn't closing anyway)
624 if( Validate() )
625 {
626 ignore_unused( TransferDataFromWindow() );
627 }
628 }
629 else if( id == wxID_CANCEL )
630 {
631 EndQuasiModal( wxID_CANCEL );
632 }
633 else // not a standard button
634 {
635 aEvent.Skip();
636 }
637
638 return;
639 }
640
641 // This is mandatory to allow wxDialogBase::OnButton() to be called.
642 aEvent.Skip();
643}
644
645
646void DIALOG_SHIM::onChildSetFocus( wxFocusEvent& aEvent )
647{
648 // When setting focus to a text control reset the before-edit value.
649
650 if( !m_isClosing )
651 {
652 if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( aEvent.GetEventObject() ) )
653 m_beforeEditValues[ textCtrl ] = textCtrl->GetValue();
654 else if( wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( aEvent.GetEventObject() ) )
655 m_beforeEditValues[ scintilla ] = scintilla->GetText();
656 }
657
658 aEvent.Skip();
659}
660
661
662void DIALOG_SHIM::OnCharHook( wxKeyEvent& aEvt )
663{
664 if( aEvt.GetKeyCode() == 'U' && aEvt.GetModifiers() == wxMOD_CONTROL )
665 {
666 if( m_parentFrame )
667 {
669 return;
670 }
671 }
672 // shift-return (Mac default) or Ctrl-Return (GTK) for OK
673 else if( ( aEvt.GetKeyCode() == WXK_RETURN || aEvt.GetKeyCode() == WXK_NUMPAD_ENTER )
674 && ( aEvt.ShiftDown() || aEvt.ControlDown() ) )
675 {
676 wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
677 return;
678 }
679 else if( aEvt.GetKeyCode() == WXK_TAB && !aEvt.ControlDown() )
680 {
681 wxWindow* currentWindow = wxWindow::FindFocus();
682 int currentIdx = -1;
683 int delta = aEvt.ShiftDown() ? -1 : 1;
684
685 auto advance =
686 [&]( int& idx )
687 {
688 // Wrap-around modulus
689 int size = (int) m_tabOrder.size();
690 idx = ( ( idx + delta ) % size + size ) % size;
691 };
692
693 for( size_t i = 0; i < m_tabOrder.size(); ++i )
694 {
695 if( m_tabOrder[i] == currentWindow )
696 {
697 currentIdx = (int) i;
698 break;
699 }
700 }
701
702 if( currentIdx >= 0 )
703 {
704 advance( currentIdx );
705
706 //todo: We don't currently have non-textentry dialog boxes but this will break if
707 // we add them.
708#ifdef __APPLE__
709 while( dynamic_cast<wxTextEntry*>( m_tabOrder[ currentIdx ] ) == nullptr )
710 advance( currentIdx );
711#endif
712
713 m_tabOrder[ currentIdx ]->SetFocus();
714 return;
715 }
716 }
717 else if( aEvt.GetKeyCode() == WXK_ESCAPE )
718 {
719 wxObject* eventSource = aEvt.GetEventObject();
720
721 if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( eventSource ) )
722 {
723 // First escape after an edit cancels edit
724 if( textCtrl->GetValue() != m_beforeEditValues[ textCtrl ] )
725 {
726 textCtrl->SetValue( m_beforeEditValues[ textCtrl ] );
727 textCtrl->SelectAll();
728 return;
729 }
730 }
731 else if( wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( eventSource ) )
732 {
733 // First escape after an edit cancels edit
734 if( scintilla->GetText() != m_beforeEditValues[ scintilla ] )
735 {
736 scintilla->SetText( m_beforeEditValues[ scintilla ] );
737 scintilla->SelectAll();
738 return;
739 }
740 }
741 }
742
743 aEvt.Skip();
744}
745
746
747static void recursiveDescent( wxSizer* aSizer, std::map<int, wxString>& aLabels )
748{
749 wxStdDialogButtonSizer* sdbSizer = dynamic_cast<wxStdDialogButtonSizer*>( aSizer );
750
751 auto setupButton =
752 [&]( wxButton* aButton )
753 {
754 if( aLabels.count( aButton->GetId() ) > 0 )
755 {
756 aButton->SetLabel( aLabels[ aButton->GetId() ] );
757 }
758 else
759 {
760 // wxWidgets has an uneven track record when the language is changed on
761 // the fly so we set them even when they don't appear in the label map
762 switch( aButton->GetId() )
763 {
764 case wxID_OK: aButton->SetLabel( _( "&OK" ) ); break;
765 case wxID_CANCEL: aButton->SetLabel( _( "&Cancel" ) ); break;
766 case wxID_YES: aButton->SetLabel( _( "&Yes" ) ); break;
767 case wxID_NO: aButton->SetLabel( _( "&No" ) ); break;
768 case wxID_APPLY: aButton->SetLabel( _( "&Apply" ) ); break;
769 case wxID_SAVE: aButton->SetLabel( _( "&Save" ) ); break;
770 case wxID_HELP: aButton->SetLabel( _( "&Help" ) ); break;
771 case wxID_CONTEXT_HELP: aButton->SetLabel( _( "&Help" ) ); break;
772 }
773 }
774 };
775
776 if( sdbSizer )
777 {
778 if( sdbSizer->GetAffirmativeButton() )
779 setupButton( sdbSizer->GetAffirmativeButton() );
780
781 if( sdbSizer->GetApplyButton() )
782 setupButton( sdbSizer->GetApplyButton() );
783
784 if( sdbSizer->GetNegativeButton() )
785 setupButton( sdbSizer->GetNegativeButton() );
786
787 if( sdbSizer->GetCancelButton() )
788 setupButton( sdbSizer->GetCancelButton() );
789
790 if( sdbSizer->GetHelpButton() )
791 setupButton( sdbSizer->GetHelpButton() );
792
793 sdbSizer->Layout();
794
795 if( sdbSizer->GetAffirmativeButton() )
796 sdbSizer->GetAffirmativeButton()->SetDefault();
797 }
798
799 for( wxSizerItem* item : aSizer->GetChildren() )
800 {
801 if( item->GetSizer() )
802 recursiveDescent( item->GetSizer(), aLabels );
803 }
804}
805
806
807void DIALOG_SHIM::SetupStandardButtons( std::map<int, wxString> aLabels )
808{
809 recursiveDescent( GetSizer(), aLabels );
810}
const char * name
Definition: DXF_plotter.cpp:57
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition: dialog_shim.h:88
void SelectAllInTextCtrls(wxWindowList &children)
bool m_isClosing
Definition: dialog_shim.h:224
std::vector< wxWindow * > m_tabOrder
Definition: dialog_shim.h:233
void OnPaint(wxPaintEvent &event)
bool m_qmodal_showing
Definition: dialog_shim.h:228
int vertPixelsFromDU(int y) const
Convert an integer number of dialog units to pixels, vertically.
bool Show(bool show) override
wxGUIEventLoop * m_qmodal_loop
Definition: dialog_shim.h:226
void onChildSetFocus(wxFocusEvent &aEvent)
void SetupStandardButtons(std::map< int, wxString > aLabels={})
int ShowQuasiModal()
std::string m_hash_key
Definition: dialog_shim.h:213
bool m_firstPaintEvent
Definition: dialog_shim.h:222
int horizPixelsFromDU(int x) const
Convert an integer number of dialog units to pixels, horizontally.
void resetSize()
Clear the existing dialog size and position.
void ClearModify()
std::map< wxWindow *, wxString > m_beforeEditValues
Definition: dialog_shim.h:239
void setSizeInDU(int x, int y)
Set the dialog to the given dimensions in "dialog units".
bool IsQuasiModal() const
Definition: dialog_shim.h:113
WDO_ENABLE_DISABLE * m_qmodal_parent_disabler
Definition: dialog_shim.h:229
bool m_useCalculatedSize
Definition: dialog_shim.h:217
void EndQuasiModal(int retCode)
void OnModify()
void OnButton(wxCommandEvent &aEvent)
Properly handle the default button events when in the quasimodal mode when not calling EndQuasiModal ...
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
wxWindow * m_initialFocusTarget
Definition: dialog_shim.h:223
bool Enable(bool enable) override
void SetPosition(const wxPoint &aNewPosition)
Force the position of the dialog to a new position.
void OnCloseWindow(wxCloseEvent &aEvent)
Properly handle the wxCloseEvent when in the quasimodal mode when not calling EndQuasiModal which is ...
wxSize m_initialSize
Definition: dialog_shim.h:236
EDA_BASE_FRAME * m_parentFrame
Definition: dialog_shim.h:231
virtual void OnCharHook(wxKeyEvent &aEvt)
EDA_UNITS GetUserUnits() const
Definition: dialog_shim.h:130
int ShowModal() override
The base frame for deriving all KiCad main window classes.
virtual void ToggleUserUnits()
A mix in class which holds the location of a wxWindow's KIWAY.
Definition: kiway_holder.h:39
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
Definition: kiway_holder.h:55
bool HasKiway() const
Safety check before asking for the Kiway reference.
Definition: kiway_holder.h:65
HOLDER_TYPE GetType() const
Definition: kiway_holder.h:48
void SetBlockingDialog(wxWindow *aWin)
Definition: kiway.cpp:674
virtual wxApp & App()
Returns a bare naked wxApp which may come from wxPython, SINGLE_TOP, or kicad.exe.
Definition: pgm_base.cpp:182
Master controller class:
Definition: tool_manager.h:62
bool IsContextMenuActive() const
True while processing a context menu.
Definition: tool_manager.h:500
void VetoContextMenuMouseWarp()
Disable mouse warping after the current context menu is closed.
Definition: tool_manager.h:511
EDA_UNITS GetUserUnits() const
Toggle a window's "enable" status to disabled, then enabled on destruction.
Definition: dialog_shim.cpp:47
WDO_ENABLE_DISABLE(wxWindow *aWindow)
Definition: dialog_shim.cpp:52
static void recursiveDescent(wxSizer *aSizer, std::map< int, wxString > &aLabels)
static std::unordered_map< std::string, wxRect > class_map
const int minSize
Push and Shove router track width and via size dialog.
#define _(s)
EDA_UNITS
Definition: eda_units.h:46
void ignore_unused(const T &)
Definition: ignore.h:24
void FixupCancelButtonCmdKeyCollision(wxWindow *aWindow)
Definition: wxgtk/ui.cpp:94
void ForceFocus(wxWindow *aWindow)
Pass the current focus to the window.
Definition: wxgtk/ui.cpp:67
void ReparentModal(wxNonOwnedWindow *aWindow)
Move a window's parent to be the top-level window and force the window to be on top.
Definition: wxgtk/ui.cpp:88
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: pgm_base.cpp:1060
see class PGM_BASE
KIWAY Kiway(KFCTL_STANDALONE)
constexpr int delta