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, 2024 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
579
580 if( m_qmodal_loop )
581 {
582 if( m_qmodal_loop->IsRunning() )
583 m_qmodal_loop->Exit( 0 );
584 else
585 m_qmodal_loop->ScheduleExit( 0 );
586
587 m_qmodal_loop = nullptr;
588 }
589
591 m_qmodal_parent_disabler = nullptr;
592
593 Show( false );
594}
595
596
597void DIALOG_SHIM::OnCloseWindow( wxCloseEvent& aEvent )
598{
599 if( IsQuasiModal() )
600 {
601 EndQuasiModal( wxID_CANCEL );
602 return;
603 }
604
605 // This is mandatory to allow wxDialogBase::OnCloseWindow() to be called.
606 aEvent.Skip();
607}
608
609
610void DIALOG_SHIM::OnButton( wxCommandEvent& aEvent )
611{
612 const int id = aEvent.GetId();
613
614 if( IsQuasiModal() )
615 {
616 if( id == GetAffirmativeId() )
617 {
618 EndQuasiModal( id );
619 }
620 else if( id == wxID_APPLY )
621 {
622 // Dialogs that provide Apply buttons should make sure data is valid before
623 // allowing a transfer, as there is no other way to indicate failure
624 // (i.e. the dialog can't refuse to close as it might with OK, because it
625 // isn't closing anyway)
626 if( Validate() )
627 {
628 ignore_unused( TransferDataFromWindow() );
629 }
630 }
631 else if( id == wxID_CANCEL )
632 {
633 EndQuasiModal( wxID_CANCEL );
634 }
635 else // not a standard button
636 {
637 aEvent.Skip();
638 }
639
640 return;
641 }
642
643 // This is mandatory to allow wxDialogBase::OnButton() to be called.
644 aEvent.Skip();
645}
646
647
648void DIALOG_SHIM::onChildSetFocus( wxFocusEvent& aEvent )
649{
650 // When setting focus to a text control reset the before-edit value.
651
652 if( !m_isClosing )
653 {
654 if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( aEvent.GetEventObject() ) )
655 m_beforeEditValues[ textCtrl ] = textCtrl->GetValue();
656 else if( wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( aEvent.GetEventObject() ) )
657 m_beforeEditValues[ scintilla ] = scintilla->GetText();
658 }
659
660 aEvent.Skip();
661}
662
663
664void DIALOG_SHIM::OnCharHook( wxKeyEvent& aEvt )
665{
666 if( aEvt.GetKeyCode() == 'U' && aEvt.GetModifiers() == wxMOD_CONTROL )
667 {
668 if( m_parentFrame )
669 {
671 return;
672 }
673 }
674 // shift-return (Mac default) or Ctrl-Return (GTK) for OK
675 else if( ( aEvt.GetKeyCode() == WXK_RETURN || aEvt.GetKeyCode() == WXK_NUMPAD_ENTER )
676 && ( aEvt.ShiftDown() || aEvt.ControlDown() ) )
677 {
678 wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
679 return;
680 }
681 else if( aEvt.GetKeyCode() == WXK_TAB && !aEvt.ControlDown() )
682 {
683 wxWindow* currentWindow = wxWindow::FindFocus();
684 int currentIdx = -1;
685 int delta = aEvt.ShiftDown() ? -1 : 1;
686
687 auto advance =
688 [&]( int& idx )
689 {
690 // Wrap-around modulus
691 int size = (int) m_tabOrder.size();
692 idx = ( ( idx + delta ) % size + size ) % size;
693 };
694
695 for( size_t i = 0; i < m_tabOrder.size(); ++i )
696 {
697 if( m_tabOrder[i] == currentWindow )
698 {
699 currentIdx = (int) i;
700 break;
701 }
702 }
703
704 if( currentIdx >= 0 )
705 {
706 advance( currentIdx );
707
708 //todo: We don't currently have non-textentry dialog boxes but this will break if
709 // we add them.
710#ifdef __APPLE__
711 while( dynamic_cast<wxTextEntry*>( m_tabOrder[ currentIdx ] ) == nullptr )
712 advance( currentIdx );
713#endif
714
715 m_tabOrder[ currentIdx ]->SetFocus();
716 return;
717 }
718 }
719 else if( aEvt.GetKeyCode() == WXK_ESCAPE )
720 {
721 wxObject* eventSource = aEvt.GetEventObject();
722
723 if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( eventSource ) )
724 {
725 // First escape after an edit cancels edit
726 if( textCtrl->GetValue() != m_beforeEditValues[ textCtrl ] )
727 {
728 textCtrl->SetValue( m_beforeEditValues[ textCtrl ] );
729 textCtrl->SelectAll();
730 return;
731 }
732 }
733 else if( wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( eventSource ) )
734 {
735 // First escape after an edit cancels edit
736 if( scintilla->GetText() != m_beforeEditValues[ scintilla ] )
737 {
738 scintilla->SetText( m_beforeEditValues[ scintilla ] );
739 scintilla->SelectAll();
740 return;
741 }
742 }
743 }
744
745 aEvt.Skip();
746}
747
748
749static void recursiveDescent( wxSizer* aSizer, std::map<int, wxString>& aLabels )
750{
751 wxStdDialogButtonSizer* sdbSizer = dynamic_cast<wxStdDialogButtonSizer*>( aSizer );
752
753 auto setupButton =
754 [&]( wxButton* aButton )
755 {
756 if( aLabels.count( aButton->GetId() ) > 0 )
757 {
758 aButton->SetLabel( aLabels[ aButton->GetId() ] );
759 }
760 else
761 {
762 // wxWidgets has an uneven track record when the language is changed on
763 // the fly so we set them even when they don't appear in the label map
764 switch( aButton->GetId() )
765 {
766 case wxID_OK: aButton->SetLabel( _( "&OK" ) ); break;
767 case wxID_CANCEL: aButton->SetLabel( _( "&Cancel" ) ); break;
768 case wxID_YES: aButton->SetLabel( _( "&Yes" ) ); break;
769 case wxID_NO: aButton->SetLabel( _( "&No" ) ); break;
770 case wxID_APPLY: aButton->SetLabel( _( "&Apply" ) ); break;
771 case wxID_SAVE: aButton->SetLabel( _( "&Save" ) ); break;
772 case wxID_HELP: aButton->SetLabel( _( "&Help" ) ); break;
773 case wxID_CONTEXT_HELP: aButton->SetLabel( _( "&Help" ) ); break;
774 }
775 }
776 };
777
778 if( sdbSizer )
779 {
780 if( sdbSizer->GetAffirmativeButton() )
781 setupButton( sdbSizer->GetAffirmativeButton() );
782
783 if( sdbSizer->GetApplyButton() )
784 setupButton( sdbSizer->GetApplyButton() );
785
786 if( sdbSizer->GetNegativeButton() )
787 setupButton( sdbSizer->GetNegativeButton() );
788
789 if( sdbSizer->GetCancelButton() )
790 setupButton( sdbSizer->GetCancelButton() );
791
792 if( sdbSizer->GetHelpButton() )
793 setupButton( sdbSizer->GetHelpButton() );
794
795 sdbSizer->Layout();
796
797 if( sdbSizer->GetAffirmativeButton() )
798 sdbSizer->GetAffirmativeButton()->SetDefault();
799 }
800
801 for( wxSizerItem* item : aSizer->GetChildren() )
802 {
803 if( item->GetSizer() )
804 recursiveDescent( item->GetSizer(), aLabels );
805 }
806}
807
808
809void DIALOG_SHIM::SetupStandardButtons( std::map<int, wxString> aLabels )
810{
811 recursiveDescent( GetSizer(), aLabels );
812}
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:233
std::vector< wxWindow * > m_tabOrder
Definition: dialog_shim.h:242
void OnPaint(wxPaintEvent &event)
bool m_qmodal_showing
Definition: dialog_shim.h:237
virtual void TearDownQuasiModal()
Override this method to perform dialog tear down actions not suitable for object dtor.
Definition: dialog_shim.h:201
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:235
void onChildSetFocus(wxFocusEvent &aEvent)
void SetupStandardButtons(std::map< int, wxString > aLabels={})
int ShowQuasiModal()
std::string m_hash_key
Definition: dialog_shim.h:222
bool m_firstPaintEvent
Definition: dialog_shim.h:231
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:248
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:238
bool m_useCalculatedSize
Definition: dialog_shim.h:226
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:232
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:245
EDA_BASE_FRAME * m_parentFrame
Definition: dialog_shim.h:240
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