KiCad PCB EDA Suite
ui_common.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) 2018-2022 KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <wx/dcclient.h>
21#include <wx/checkbox.h>
22#include <wx/choice.h>
23#include <wx/listbox.h>
24#include <wx/dataview.h>
25#include <wx/radiobut.h>
26#include <wx/slider.h>
27#include <wx/spinctrl.h>
28#include <wx/srchctrl.h>
29#include <wx/stc/stc.h>
30#include <wx/scrolbar.h>
31#include <wx/grid.h>
32#include <widgets/ui_common.h>
33
34#include <algorithm>
35#include <dialog_shim.h>
36#include <pgm_base.h>
37#include <wx/settings.h>
39#include <string_utils.h>
40
42{
43 // This is the value used in (most) wxFB dialogs
44 return 5;
45}
46
47
48SEVERITY SeverityFromString( const wxString& aSeverity )
49{
50 if( aSeverity == wxT( "warning" ) )
52 else if( aSeverity == wxT( "ignore" ) )
54 else
55 return RPT_SEVERITY_ERROR;
56}
57
58
59wxString SeverityToString( const SEVERITY& aSeverity )
60{
61 if( aSeverity == RPT_SEVERITY_IGNORE )
62 return wxT( "ignore" );
63 else if( aSeverity == RPT_SEVERITY_WARNING )
64 return wxT( "warning" );
65 else
66 return wxT( "error" );
67}
68
69
70wxSize KIUI::GetTextSize( const wxString& aSingleLine, wxWindow* aWindow )
71{
72 wxCoord width;
73 wxCoord height;
74
75 {
76 wxClientDC dc( aWindow );
77 dc.SetFont( aWindow->GetFont() );
78 dc.GetTextExtent( aSingleLine, &width, &height );
79 }
80
81 return wxSize( width, height );
82}
83
84
86{
87 static int guiFontSize = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ).GetPointSize();
88
89 wxFont font( guiFontSize, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL );
90
91#ifdef __WXMAC__
92 // https://trac.wxwidgets.org/ticket/19210
93 if( font.GetFaceName().IsEmpty() )
94 font.SetFaceName( "Menlo" );
95#endif
96
97 return font;
98}
99
100
101wxFont getGUIFont( wxWindow* aWindow, int aRelativeSize )
102{
103 wxFont font = aWindow->GetFont();
104
105 font.SetPointSize( font.GetPointSize() + aRelativeSize );
106
107 if( Pgm().GetCommonSettings()->m_Appearance.apply_icon_scale_to_fonts )
108 {
109 double icon_scale_fourths;
110
111 if( Pgm().GetCommonSettings()->m_Appearance.icon_scale <= 0 )
112 icon_scale_fourths = KiIconScale( aWindow );
113 else
114 icon_scale_fourths = Pgm().GetCommonSettings()->m_Appearance.icon_scale;
115
116 font.SetPointSize( KiROUND( icon_scale_fourths * font.GetPointSize() / 4.0 ) );
117 }
118
119#ifdef __WXMAC__
120 // https://trac.wxwidgets.org/ticket/19210
121 if( font.GetFaceName().IsEmpty() )
122 font.SetFaceName( "San Francisco" );
123 // OSX 10.1 .. 10.9: Lucida Grande
124 // OSX 10.10: Helvetica Neue
125 // OSX 10.11 .. : San Francisco
126#endif
127
128 return font;
129}
130
131
132wxFont KIUI::GetStatusFont( wxWindow* aWindow )
133{
134#ifdef __WXMAC__
135 int scale = -2;
136#else
137 int scale = 0;
138#endif
139
140 return getGUIFont( aWindow, scale );
141}
142
143
144wxFont KIUI::GetInfoFont( wxWindow* aWindow )
145{
146 return getGUIFont( aWindow, -1 );
147}
148
149
150wxFont KIUI::GetControlFont( wxWindow* aWindow )
151{
152 return getGUIFont( aWindow, 0 );
153}
154
155
156bool KIUI::EnsureTextCtrlWidth( wxTextCtrl* aCtrl, const wxString* aString )
157{
158 wxWindow* window = aCtrl->GetParent();
159
160 if( !window )
161 window = aCtrl;
162
163 wxString ctrlText;
164
165 if( !aString )
166 {
167 ctrlText = aCtrl->GetValue();
168 aString = &ctrlText;
169 }
170
171 wxSize textz = GetTextSize( *aString, window );
172 wxSize ctrlz = aCtrl->GetSize();
173
174 if( ctrlz.GetWidth() < textz.GetWidth() + 10 )
175 {
176 ctrlz.SetWidth( textz.GetWidth() + 10 );
177 aCtrl->SetSizeHints( ctrlz );
178 return true;
179 }
180
181 return false;
182}
183
184
185wxString KIUI::EllipsizeStatusText( wxWindow* aWindow, const wxString& aString )
186{
187 wxString msg = UnescapeString( aString );
188
189 msg.Replace( wxT( "\n" ), wxT( " " ) );
190 msg.Replace( wxT( "\r" ), wxT( " " ) );
191 msg.Replace( wxT( "\t" ), wxT( " " ) );
192
193 wxClientDC dc( aWindow );
194 int statusWidth = aWindow->GetSize().GetWidth();
195
196 // 30% of the first 800 pixels plus 60% of the remaining width
197 int textWidth = std::min( statusWidth, 800 ) * 0.3 + std::max( statusWidth - 800, 0 ) * 0.6;
198
199 return wxControl::Ellipsize( msg, dc, wxELLIPSIZE_END, textWidth );
200}
201
202
203wxString KIUI::EllipsizeMenuText( const wxString& aString )
204{
205 wxString msg = UnescapeString( aString );
206
207 msg.Replace( wxT( "\n" ), wxT( " " ) );
208 msg.Replace( wxT( "\r" ), wxT( " " ) );
209 msg.Replace( wxT( "\t" ), wxT( " " ) );
210
211 if( msg.Length() > 36 )
212 msg = msg.Left( 34 ) + wxT( "..." );
213
214 return msg;
215}
216
217
218void KIUI::SelectReferenceNumber( wxTextEntry* aTextEntry )
219{
220 wxString ref = aTextEntry->GetValue();
221
222 if( ref.find_first_of( '?' ) != ref.npos )
223 {
224 aTextEntry->SetSelection( ref.find_first_of( '?' ), ref.find_last_of( '?' ) + 1 );
225 }
226 else if( ref.find_first_of( '*' ) != ref.npos )
227 {
228 aTextEntry->SetSelection( ref.find_first_of( '*' ), ref.find_last_of( '*' ) + 1 );
229 }
230 else
231 {
232 wxString num = ref;
233
234 while( !num.IsEmpty() && ( !isdigit( num.Last() ) || !isdigit( num.GetChar( 0 ) ) ) )
235 {
236 // Trim non-digit from end
237 if( !isdigit( num.Last() ) )
238 num.RemoveLast();
239
240 // Trim non-digit from the start
241 if( !num.IsEmpty() && !isdigit( num.GetChar( 0 ) ) )
242 num = num.Right( num.Length() - 1 );
243 }
244
245 aTextEntry->SetSelection( ref.Find( num ), ref.Find( num ) + num.Length() );
246
247 if( num.IsEmpty() )
248 aTextEntry->SetSelection( -1, -1 );
249 }
250}
251
252
253bool KIUI::IsInputControlFocused( wxWindow* aFocus )
254{
255 if( aFocus == nullptr )
256 aFocus = wxWindow::FindFocus();
257
258 if( !aFocus )
259 return false;
260
261 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( aFocus );
262 wxStyledTextCtrl* styledText = dynamic_cast<wxStyledTextCtrl*>( aFocus );
263 wxListBox* listBox = dynamic_cast<wxListBox*>( aFocus );
264 wxSearchCtrl* searchCtrl = dynamic_cast<wxSearchCtrl*>( aFocus );
265 wxCheckBox* checkboxCtrl = dynamic_cast<wxCheckBox*>( aFocus );
266 wxChoice* choiceCtrl = dynamic_cast<wxChoice*>( aFocus );
267 wxRadioButton* radioBtn = dynamic_cast<wxRadioButton*>( aFocus );
268 wxSpinCtrl* spinCtrl = dynamic_cast<wxSpinCtrl*>( aFocus );
269 wxSpinCtrlDouble* spinDblCtrl = dynamic_cast<wxSpinCtrlDouble*>( aFocus );
270 wxSlider* sliderCtl = dynamic_cast<wxSlider*>( aFocus );
271
272 // Data view control is annoying, the focus is on a "wxDataViewCtrlMainWindow" class that
273 // is not formally exported via the header.
274 wxDataViewCtrl* dataViewCtrl = nullptr;
275
276 wxWindow* parent = aFocus->GetParent();
277
278 if( parent )
279 dataViewCtrl = dynamic_cast<wxDataViewCtrl*>( parent );
280
281 return ( textEntry || styledText || listBox || searchCtrl || checkboxCtrl || choiceCtrl
282 || radioBtn || spinCtrl || spinDblCtrl || sliderCtl || dataViewCtrl );
283}
284
285
286bool KIUI::IsInputControlEditable( wxWindow* aFocus )
287{
288 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( aFocus );
289 wxStyledTextCtrl* styledText = dynamic_cast<wxStyledTextCtrl*>( aFocus );
290 wxSearchCtrl* searchCtrl = dynamic_cast<wxSearchCtrl*>( aFocus );
291
292 if( textEntry )
293 return textEntry->IsEditable();
294 else if( styledText )
295 return styledText->IsEditable();
296 else if( searchCtrl )
297 return searchCtrl->IsEditable();
298
299 return true; // Must return true if we can't determine the state, intentionally true for non inputs as well
300}
301
302
304{
305 return Pgm().m_ModalDialogCount > 0;
306}
307
308
309void KIUI::Disable( wxWindow* aWindow )
310{
311 wxScrollBar* scrollBar = dynamic_cast<wxScrollBar*>( aWindow );
312 wxGrid* grid = dynamic_cast<wxGrid*>( aWindow );
313 wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( aWindow );
314 wxControl* control = dynamic_cast<wxControl*>( aWindow );
315
316 if( scrollBar )
317 {
318 // Leave a scroll bar active
319 }
320 else if( grid )
321 {
322 for( int row = 0; row < grid->GetNumberRows(); ++row )
323 {
324 for( int col = 0; col < grid->GetNumberCols(); ++col )
325 grid->SetReadOnly( row, col );
326 }
327 }
328 else if( scintilla )
329 {
330 scintilla->SetReadOnly( true );
331 }
332 else if( control )
333 {
334 control->Disable();
335 }
336 else
337 {
338 for( wxWindow* child : aWindow->GetChildren() )
339 Disable( child );
340 }
341}
int KiIconScale(wxWindow *aWindow)
Return the automatic scale factor that would be used for a given window by KiScaledBitmap and KiScale...
Definition: bitmap.cpp:122
wxFont GetMonospacedUIFont()
Definition: ui_common.cpp:85
int GetStdMargin()
Get the standard margin around a widget in the KiCad UI.
Definition: ui_common.cpp:41
wxFont GetStatusFont(wxWindow *aWindow)
Definition: ui_common.cpp:132
bool IsInputControlFocused(wxWindow *aFocus=nullptr)
Check if a input control has focus.
Definition: ui_common.cpp:253
bool IsInputControlEditable(wxWindow *aControl)
Check if a input control has focus.
Definition: ui_common.cpp:286
wxString EllipsizeMenuText(const wxString &aString)
Ellipsize text (at the end) to be no more than 36 characters.
Definition: ui_common.cpp:203
wxFont GetInfoFont(wxWindow *aWindow)
Definition: ui_common.cpp:144
bool IsModalDialogFocused()
Definition: ui_common.cpp:303
wxFont GetControlFont(wxWindow *aWindow)
Definition: ui_common.cpp:150
wxString EllipsizeStatusText(wxWindow *aWindow, const wxString &aString)
Ellipsize text (at the end) to be no more than 1/3 of the window width.
Definition: ui_common.cpp:185
void SelectReferenceNumber(wxTextEntry *aTextEntry)
Select the number (or "?") in a reference for ease of editing.
Definition: ui_common.cpp:218
wxSize GetTextSize(const wxString &aSingleLine, wxWindow *aWindow)
Return the size of aSingleLine of text when it is rendered in aWindow using whatever font is currentl...
Definition: ui_common.cpp:70
bool EnsureTextCtrlWidth(wxTextCtrl *aCtrl, const wxString *aString=nullptr)
Set the minimum pixel width on a text control in order to make a text string be fully visible within ...
Definition: ui_common.cpp:156
void Disable(wxWindow *aWindow)
Makes a window read-only.
Definition: ui_common.cpp:309
must_if< error >::control< Rule > control
Definition: sim_serde.h:107
see class PGM_BASE
SEVERITY
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_IGNORE
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:111
const int scale
wxString UnescapeString(const wxString &aSource)
SEVERITY SeverityFromString(const wxString &aSeverity)
Definition: ui_common.cpp:48
wxString SeverityToString(const SEVERITY &aSeverity)
Definition: ui_common.cpp:59
wxFont getGUIFont(wxWindow *aWindow, int aRelativeSize)
Definition: ui_common.cpp:101
Functions to provide common constants and other functions to assist in making a consistent UI.
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:85