KiCad PCB EDA Suite
Loading...
Searching...
No Matches
eda_view_switcher.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
21#include <kiplatform/ui.h>
22
23#include <wx/utils.h>
24
25
26#ifdef __WXGTK__
27#define LIST_BOX_H_PADDING 20
28#define LIST_BOX_V_PADDING 8
29#else
30#define LIST_BOX_H_PADDING 10
31#define LIST_BOX_V_PADDING 5
32#endif
33
34
35EDA_VIEW_SWITCHER::EDA_VIEW_SWITCHER( wxWindow* aParent, const wxArrayString& aItems,
36 wxKeyCode aCtrlKey ) :
37 EDA_VIEW_SWITCHER_BASE( aParent ),
38 // Start with the tab marked as "up" so the initial ctrl-tab press advances selection.
39 m_tabState( false ),
40 m_receivingEvents( false ),
41 m_ctrlKey( aCtrlKey )
42{
43 m_listBox->InsertItems( aItems, 0 );
44 m_listBox->SetSelection( std::min( 0, (int) m_listBox->GetCount() - 1 ) );
45
46 // Without key state polling the tab press that opened the switcher is never seen, so count it now.
49
50 int width = 0;
51 int height = 0;
52
53 for( const wxString& item : aItems )
54 {
55 wxSize extents = m_listBox->GetTextExtent( item );
56 width = std::max( width, extents.x );
57 height += extents.y + LIST_BOX_V_PADDING;
58 }
59
60 m_listBox->SetMinSize( wxSize( width + LIST_BOX_H_PADDING,
61 height + ( LIST_BOX_V_PADDING * 2 ) ) );
63
64 // this line fixes an issue on Linux Ubuntu using Unity (dialog not shown),
65 // and works fine on all systems
66 GetSizer()->Fit( this );
67
68 Centre();
69}
70
71
72bool EDA_VIEW_SWITCHER::Show( bool aShow )
73{
74 if( !aShow )
75 m_receivingEvents = false;
76
77#ifdef __WXGTK__
78 // On Wayland, window positions cannot be changed after mapping. DIALOG_SHIM::Show() calls
79 // Raise() -> gtk_window_present() before wxDialog::Show(), prematurely mapping the window so
80 // the compositor places it at its default position instead of centered on the parent. Centre
81 // before mapping and bypass DIALOG_SHIM::Show() since this transient popup needs no geometry
82 // save/restore.
83 if( aShow && wxGetEnv( wxT( "WAYLAND_DISPLAY" ), nullptr ) )
84 {
86 Centre();
87 m_receivingEvents = true;
88 return wxDialog::Show( true );
89 }
90#endif
91
92 bool ret = DIALOG_SHIM::Show( aShow );
93
94 if( aShow )
95 {
96 Centre();
97 m_receivingEvents = true;
98 }
99
100 return ret;
101}
102
103
105{
106 int count = (int) m_listBox->GetCount();
107
108 if( count == 0 )
109 return;
110
111 bool backward = wxGetKeyState( WXK_SHIFT ) && m_ctrlKey != WXK_SHIFT;
112 int idx = m_listBox->GetSelection() + ( backward ? -1 : 1 );
113
114 m_listBox->SetSelection( ( idx + count ) % count );
115}
116
117
118// OK, this is *really* annoying, but wxWidgets doesn't give us key-down events while the
119// control key is being held down. So we can't use OnKeyDown() or OnCharHook() and instead
120// must rely on watching key states in TryBefore().
121//
122// Just checking the state of the tab key is tempting, but then we'll think it's been hit
123// several times when it's actually just a key-down followed by a redraw or idle event.
124//
125// So we have to keep a state machine of the tab key.
126//
127// wxGetKeyState() cannot query non-modifier keys on Wayland, but char hook events do arrive there
128// with the control key held, so tab and escape come from those events instead.
129//
130bool EDA_VIEW_SWITCHER::TryBefore( wxEvent& aEvent )
131{
132 if( !m_receivingEvents )
133 {
134 return DIALOG_SHIM::TryBefore( aEvent );
135 }
136
138 {
139 if( aEvent.GetEventType() == wxEVT_CHAR_HOOK )
140 {
141 int keyCode = static_cast<wxKeyEvent&>( aEvent ).GetKeyCode();
142
143 if( keyCode == WXK_TAB )
144 {
146 return true;
147 }
148
149 if( keyCode == WXK_ESCAPE )
150 {
151 wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL ) );
152 return true;
153 }
154 }
155
156 if( !wxGetKeyState( m_ctrlKey ) )
157 wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
158
159 return DIALOG_SHIM::TryBefore( aEvent );
160 }
161
162 // Check for tab key leading edge
163 if( !m_tabState && wxGetKeyState( WXK_TAB ) )
164 {
165 m_tabState = true;
167 return true;
168 }
169
170 // Check for tab key trailing edge
171 if( m_tabState && !wxGetKeyState( WXK_TAB ) )
172 {
173 m_tabState = false;
174 }
175
176 // Check for control key trailing edge
177 if( !wxGetKeyState( m_ctrlKey ) )
178 {
179 wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
180 }
181 else if( wxGetKeyState( WXK_ESCAPE ) )
182 {
183 wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL ) );
184 }
185
186 return DIALOG_SHIM::TryBefore( aEvent );
187}
bool Show(bool show) override
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition dialog_shim.h:94
void clampToWorkArea()
Constrain the dialog's minimum size, size and position to the work area of the display it occupies,...
EDA_VIEW_SWITCHER_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("View Preset Switcher"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxSTAY_ON_TOP)
EDA_VIEW_SWITCHER(wxWindow *aParent, const wxArrayString &aItems, wxKeyCode aCtrlKey)
bool Show(bool show) override
bool TryBefore(wxEvent &aEvent) override
#define LIST_BOX_V_PADDING
#define LIST_BOX_H_PADDING
bool SupportsKeyState()
Return whether wxGetKeyState() can query ordinary keys, beyond modifiers and lock keys.
Definition wxgtk/ui.cpp:491