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