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
474
475/*
476 Quasi-Modal Mode Explained:
477
478 The gtk calls in wxDialog::ShowModal() cause event routing problems if that
479 modal dialog then tries to use KIWAY_PLAYER::ShowModal(). The latter shows up
480 and mostly works but does not respond to the window decoration close button.
481 There is no way to get around this without reversing the gtk calls temporarily.
482
483 Quasi-Modal mode is our own almost modal mode which disables only the parent
484 of the DIALOG_SHIM, leaving other frames operable and while staying captured in the
485 nested event loop. This avoids the gtk calls and leaves event routing pure
486 and sufficient to operate the KIWAY_PLAYER::ShowModal() properly. When using
487 ShowQuasiModal() you have to use EndQuasiModal() in your dialogs and not
488 EndModal(). There is also IsQuasiModal() but its value can only be true
489 when the nested event loop is active. Do not mix the modal and quasi-modal
490 functions. Use one set or the other.
491
492 You might find this behavior preferable over a pure modal mode, and it was said
493 that only the Mac has this natively, but now other platforms have something
494 similar. You CAN use it anywhere for any dialog. But you MUST use it when
495 you want to use KIWAY_PLAYER::ShowModal() from a dialog event.
496*/
497
499{
500 // This is an exception safe way to zero a pointer before returning.
501 // Yes, even though DismissModal() clears this first normally, this is
502 // here in case there's an exception before the dialog is dismissed.
503 struct NULLER
504 {
505 void*& m_what;
506 NULLER( void*& aPtr ) : m_what( aPtr ) {}
507 ~NULLER() { m_what = nullptr; } // indeed, set it to NULL on destruction
508 } clear_this( (void*&) m_qmodal_loop );
509
510 // release the mouse if it's currently captured as the window having it
511 // will be disabled when this dialog is shown -- but will still keep the
512 // capture making it impossible to do anything in the modal dialog itself
513 wxWindow* win = wxWindow::GetCapture();
514 if( win )
515 win->ReleaseMouse();
516
517 // Get the optimal parent
518 wxWindow* parent = GetParentForModalDialog( GetParent(), GetWindowStyle() );
519
520 wxASSERT_MSG( !m_qmodal_parent_disabler, wxT( "Caller using ShowQuasiModal() twice on same "
521 "window?" ) );
522
523 // quasi-modal: disable only my "optimal" parent
525
526 // Apple in its infinite wisdom will raise a disabled window before even passing
527 // us the event, so we have no way to stop it. Instead, we must set an order on
528 // the windows so that the quasi-modal will be pushed in front of the disabled
529 // window when it is raised.
531
532 Show( true );
533
534 m_qmodal_showing = true;
535
536 wxGUIEventLoop event_loop;
537
538 m_qmodal_loop = &event_loop;
539
540 event_loop.Run();
541
542 m_qmodal_showing = false;
543
544 if( parent )
545 parent->SetFocus();
546
547 return GetReturnCode();
548}
549
550
551void DIALOG_SHIM::EndQuasiModal( int retCode )
552{
553 // Hook up validator and transfer data from controls handling so quasi-modal dialogs
554 // handle validation in the same way as other dialogs.
555 if( ( retCode == wxID_OK ) && ( !Validate() || !TransferDataFromWindow() ) )
556 return;
557
558 SetReturnCode( retCode );
559
560 if( !IsQuasiModal() )
561 {
562 wxFAIL_MSG( wxT( "Either DIALOG_SHIM::EndQuasiModal was called twice, or ShowQuasiModal"
563 "wasn't called" ) );
564 return;
565 }
566
567 if( m_qmodal_loop )
568 {
569 if( m_qmodal_loop->IsRunning() )
570 m_qmodal_loop->Exit( 0 );
571 else
572 m_qmodal_loop->ScheduleExit( 0 );
573
574 m_qmodal_loop = nullptr;
575 }
576
578 m_qmodal_parent_disabler = nullptr;
579
580 Show( false );
581}
582
583
584void DIALOG_SHIM::OnCloseWindow( wxCloseEvent& aEvent )
585{
586 if( IsQuasiModal() )
587 {
588 EndQuasiModal( wxID_CANCEL );
589 return;
590 }
591
592 // This is mandatory to allow wxDialogBase::OnCloseWindow() to be called.
593 aEvent.Skip();
594}
595
596
597void DIALOG_SHIM::OnButton( wxCommandEvent& aEvent )
598{
599 const int id = aEvent.GetId();
600
601 if( IsQuasiModal() )
602 {
603 if( id == GetAffirmativeId() )
604 {
605 EndQuasiModal( id );
606 }
607 else if( id == wxID_APPLY )
608 {
609 // Dialogs that provide Apply buttons should make sure data is valid before
610 // allowing a transfer, as there is no other way to indicate failure
611 // (i.e. the dialog can't refuse to close as it might with OK, because it
612 // isn't closing anyway)
613 if( Validate() )
614 {
615 ignore_unused( TransferDataFromWindow() );
616 }
617 }
618 else if( id == wxID_CANCEL )
619 {
620 EndQuasiModal( wxID_CANCEL );
621 }
622 else // not a standard button
623 {
624 aEvent.Skip();
625 }
626
627 return;
628 }
629
630 // This is mandatory to allow wxDialogBase::OnButton() to be called.
631 aEvent.Skip();
632}
633
634
635void DIALOG_SHIM::onChildSetFocus( wxFocusEvent& aEvent )
636{
637 // When setting focus to a text control reset the before-edit value.
638
639 if( !m_isClosing )
640 {
641 if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( aEvent.GetEventObject() ) )
642 m_beforeEditValues[ textCtrl ] = textCtrl->GetValue();
643 else if( wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( aEvent.GetEventObject() ) )
644 m_beforeEditValues[ scintilla ] = scintilla->GetText();
645 }
646
647 aEvent.Skip();
648}
649
650
651void DIALOG_SHIM::OnCharHook( wxKeyEvent& aEvt )
652{
653 if( aEvt.GetKeyCode() == 'U' && aEvt.GetModifiers() == wxMOD_CONTROL )
654 {
655 if( m_parentFrame )
656 {
658 return;
659 }
660 }
661 // shift-return (Mac default) or Ctrl-Return (GTK) for OK
662 else if( ( aEvt.GetKeyCode() == WXK_RETURN || aEvt.GetKeyCode() == WXK_NUMPAD_ENTER )
663 && ( aEvt.ShiftDown() || aEvt.ControlDown() ) )
664 {
665 wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
666 return;
667 }
668 else if( aEvt.GetKeyCode() == WXK_TAB && !aEvt.ControlDown() )
669 {
670 wxWindow* currentWindow = wxWindow::FindFocus();
671 int currentIdx = -1;
672 int delta = aEvt.ShiftDown() ? -1 : 1;
673
674 auto advance =
675 [&]( int& idx )
676 {
677 // Wrap-around modulus
678 int size = (int) m_tabOrder.size();
679 idx = ( ( idx + delta ) % size + size ) % size;
680 };
681
682 for( size_t i = 0; i < m_tabOrder.size(); ++i )
683 {
684 if( m_tabOrder[i] == currentWindow )
685 {
686 currentIdx = (int) i;
687 break;
688 }
689 }
690
691 if( currentIdx >= 0 )
692 {
693 advance( currentIdx );
694
695 //todo: We don't currently have non-textentry dialog boxes but this will break if
696 // we add them.
697#ifdef __APPLE__
698 while( dynamic_cast<wxTextEntry*>( m_tabOrder[ currentIdx ] ) == nullptr )
699 advance( currentIdx );
700#endif
701
702 m_tabOrder[ currentIdx ]->SetFocus();
703 return;
704 }
705 }
706 else if( aEvt.GetKeyCode() == WXK_ESCAPE )
707 {
708 wxObject* eventSource = aEvt.GetEventObject();
709
710 if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( eventSource ) )
711 {
712 // First escape after an edit cancels edit
713 if( textCtrl->GetValue() != m_beforeEditValues[ textCtrl ] )
714 {
715 textCtrl->SetValue( m_beforeEditValues[ textCtrl ] );
716 textCtrl->SelectAll();
717 return;
718 }
719 }
720 else if( wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( eventSource ) )
721 {
722 // First escape after an edit cancels edit
723 if( scintilla->GetText() != m_beforeEditValues[ scintilla ] )
724 {
725 scintilla->SetText( m_beforeEditValues[ scintilla ] );
726 scintilla->SelectAll();
727 return;
728 }
729 }
730 }
731
732 aEvt.Skip();
733}
734
735
736static void recursiveDescent( wxSizer* aSizer, std::map<int, wxString>& aLabels )
737{
738 wxStdDialogButtonSizer* sdbSizer = dynamic_cast<wxStdDialogButtonSizer*>( aSizer );
739
740 auto setupButton =
741 [&]( wxButton* aButton )
742 {
743 if( aLabels.count( aButton->GetId() ) > 0 )
744 {
745 aButton->SetLabel( aLabels[ aButton->GetId() ] );
746 }
747 else
748 {
749 // wxWidgets has an uneven track record when the language is changed on
750 // the fly so we set them even when they don't appear in the label map
751 switch( aButton->GetId() )
752 {
753 case wxID_OK: aButton->SetLabel( _( "&OK" ) ); break;
754 case wxID_CANCEL: aButton->SetLabel( _( "&Cancel" ) ); break;
755 case wxID_YES: aButton->SetLabel( _( "&Yes" ) ); break;
756 case wxID_NO: aButton->SetLabel( _( "&No" ) ); break;
757 case wxID_APPLY: aButton->SetLabel( _( "&Apply" ) ); break;
758 case wxID_SAVE: aButton->SetLabel( _( "&Save" ) ); break;
759 case wxID_HELP: aButton->SetLabel( _( "&Help" ) ); break;
760 case wxID_CONTEXT_HELP: aButton->SetLabel( _( "&Help" ) ); break;
761 }
762 }
763 };
764
765 if( sdbSizer )
766 {
767 if( sdbSizer->GetAffirmativeButton() )
768 setupButton( sdbSizer->GetAffirmativeButton() );
769
770 if( sdbSizer->GetApplyButton() )
771 setupButton( sdbSizer->GetApplyButton() );
772
773 if( sdbSizer->GetNegativeButton() )
774 setupButton( sdbSizer->GetNegativeButton() );
775
776 if( sdbSizer->GetCancelButton() )
777 setupButton( sdbSizer->GetCancelButton() );
778
779 if( sdbSizer->GetHelpButton() )
780 setupButton( sdbSizer->GetHelpButton() );
781
782 sdbSizer->Layout();
783
784 if( sdbSizer->GetAffirmativeButton() )
785 sdbSizer->GetAffirmativeButton()->SetDefault();
786 }
787
788 for( wxSizerItem* item : aSizer->GetChildren() )
789 {
790 if( item->GetSizer() )
791 recursiveDescent( item->GetSizer(), aLabels );
792 }
793}
794
795
796void DIALOG_SHIM::SetupStandardButtons( std::map<int, wxString> aLabels )
797{
798 recursiveDescent( GetSizer(), aLabels );
799}
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:222
std::vector< wxWindow * > m_tabOrder
Definition: dialog_shim.h:231
void OnPaint(wxPaintEvent &event)
bool m_qmodal_showing
Definition: dialog_shim.h:226
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:224
void onChildSetFocus(wxFocusEvent &aEvent)
void SetupStandardButtons(std::map< int, wxString > aLabels={})
int ShowQuasiModal()
std::string m_hash_key
Definition: dialog_shim.h:211
bool m_firstPaintEvent
Definition: dialog_shim.h:220
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:237
void setSizeInDU(int x, int y)
Set the dialog to the given dimensions in "dialog units".
bool IsQuasiModal() const
Definition: dialog_shim.h:111
WDO_ENABLE_DISABLE * m_qmodal_parent_disabler
Definition: dialog_shim.h:227
bool m_useCalculatedSize
Definition: dialog_shim.h:215
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:221
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:234
EDA_BASE_FRAME * m_parentFrame
Definition: dialog_shim.h:229
virtual void OnCharHook(wxKeyEvent &aEvt)
EDA_UNITS GetUserUnits() const
Definition: dialog_shim.h:128
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:181
Master controller class:
Definition: tool_manager.h:62
bool IsContextMenuActive() const
True while processing a context menu.
Definition: tool_manager.h:519
void VetoContextMenuMouseWarp()
Disable mouse warping after the current context menu is closed.
Definition: tool_manager.h:530
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 ReparentQuasiModal(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
void ForceFocus(wxWindow *aWindow)
Pass the current focus to the window.
Definition: wxgtk/ui.cpp:67
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: pgm_base.cpp:1059
see class PGM_BASE
KIWAY Kiway(KFCTL_STANDALONE)
constexpr int delta