KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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
41
42const wxString KIUI::s_FocusStealableInputName = wxS( "KI_NOFOCUS");
43
44
46{
47 // This is the value used in (most) wxFB dialogs
48 return 5;
49}
50
51
52SEVERITY SeverityFromString( const wxString& aSeverity )
53{
54 if( aSeverity == wxT( "warning" ) )
56 else if( aSeverity == wxT( "ignore" ) )
58 else
59 return RPT_SEVERITY_ERROR;
60}
61
62
63wxString SeverityToString( const SEVERITY& aSeverity )
64{
65 if( aSeverity == RPT_SEVERITY_IGNORE )
66 return wxT( "ignore" );
67 else if( aSeverity == RPT_SEVERITY_WARNING )
68 return wxT( "warning" );
69 else
70 return wxT( "error" );
71}
72
73
74wxSize KIUI::GetTextSize( const wxString& aSingleLine, wxWindow* aWindow )
75{
76 wxCoord width;
77 wxCoord height;
78
79 {
80 wxClientDC dc( aWindow );
81 dc.SetFont( aWindow->GetFont() );
82 dc.GetTextExtent( aSingleLine, &width, &height );
83 }
84
85 return wxSize( width, height );
86}
87
88
90{
91 static int guiFontSize = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ).GetPointSize();
92
93 wxFont font( guiFontSize, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL );
94
95#ifdef __WXMAC__
96 // https://trac.wxwidgets.org/ticket/19210
97 if( font.GetFaceName().IsEmpty() )
98 font.SetFaceName( wxS( "Menlo" ) );
99#endif
100
101 return font;
102}
103
104
105wxFont getGUIFont( wxWindow* aWindow, int aRelativeSize )
106{
107 wxFont font = aWindow->GetFont();
108
109 font.SetPointSize( font.GetPointSize() + aRelativeSize );
110
111 if( Pgm().GetCommonSettings()->m_Appearance.apply_icon_scale_to_fonts )
112 font.SetPointSize( KiROUND( KiIconScale( aWindow ) * font.GetPointSize() / 4.0 ) );
113
114#ifdef __WXMAC__
115 // https://trac.wxwidgets.org/ticket/19210
116 if( font.GetFaceName().IsEmpty() )
117 font.SetFaceName( wxS( "San Francisco" ) );
118 // OSX 10.1 .. 10.9: Lucida Grande
119 // OSX 10.10: Helvetica Neue
120 // OSX 10.11 .. : San Francisco
121#endif
122
123 return font;
124}
125
126
127wxFont KIUI::GetStatusFont( wxWindow* aWindow )
128{
129#ifdef __WXMAC__
130 int scale = -2;
131#else
132 int scale = 0;
133#endif
134
135 return getGUIFont( aWindow, scale );
136}
137
138
139wxFont KIUI::GetDockedPaneFont( wxWindow* aWindow )
140{
141#ifdef __WXMAC__
142 int scale = -1;
143#else
144 int scale = 0;
145#endif
146
147 return getGUIFont( aWindow, scale );
148}
149
150
151wxFont KIUI::GetInfoFont( wxWindow* aWindow )
152{
153 return getGUIFont( aWindow, -1 );
154}
155
156
157wxFont KIUI::GetControlFont( wxWindow* aWindow )
158{
159 return getGUIFont( aWindow, 0 );
160}
161
162
163bool KIUI::EnsureTextCtrlWidth( wxTextCtrl* aCtrl, const wxString* aString )
164{
165 wxWindow* window = aCtrl->GetParent();
166
167 if( !window )
168 window = aCtrl;
169
170 wxString ctrlText;
171
172 if( !aString )
173 {
174 ctrlText = aCtrl->GetValue();
175 aString = &ctrlText;
176 }
177
178 wxSize textz = GetTextSize( *aString, window );
179 wxSize ctrlz = aCtrl->GetSize();
180
181 if( ctrlz.GetWidth() < textz.GetWidth() + 10 )
182 {
183 ctrlz.SetWidth( textz.GetWidth() + 10 );
184 aCtrl->SetSizeHints( ctrlz );
185 return true;
186 }
187
188 return false;
189}
190
191
192wxString KIUI::EllipsizeStatusText( wxWindow* aWindow, const wxString& aString )
193{
194 wxString msg = UnescapeString( aString );
195
196 msg.Replace( wxT( "\n" ), wxT( " " ) );
197 msg.Replace( wxT( "\r" ), wxT( " " ) );
198 msg.Replace( wxT( "\t" ), wxT( " " ) );
199
200 wxClientDC dc( aWindow );
201 int statusWidth = aWindow->GetSize().GetWidth();
202
203 // 30% of the first 800 pixels plus 60% of the remaining width
204 int textWidth = std::min( statusWidth, 800 ) * 0.3 + std::max( statusWidth - 800, 0 ) * 0.6;
205
206 return wxControl::Ellipsize( msg, dc, wxELLIPSIZE_END, textWidth );
207}
208
209
210wxString KIUI::EllipsizeMenuText( const wxString& aString )
211{
212 wxString msg = UnescapeString( aString );
213
214 msg.Replace( wxT( "\n" ), wxT( " " ) );
215 msg.Replace( wxT( "\r" ), wxT( " " ) );
216 msg.Replace( wxT( "\t" ), wxT( " " ) );
217
218 if( msg.Length() > 36 )
219 msg = msg.Left( 34 ) + wxT( "..." );
220
221 return msg;
222}
223
224
225void KIUI::SelectReferenceNumber( wxTextEntry* aTextEntry )
226{
227 wxString ref = aTextEntry->GetValue();
228
229 if( ref.find_first_of( '?' ) != ref.npos )
230 {
231 aTextEntry->SetSelection( ref.find_first_of( '?' ), ref.find_last_of( '?' ) + 1 );
232 }
233 else if( ref.find_first_of( '*' ) != ref.npos )
234 {
235 aTextEntry->SetSelection( ref.find_first_of( '*' ), ref.find_last_of( '*' ) + 1 );
236 }
237 else
238 {
239 wxString num = ref;
240
241 while( !num.IsEmpty() && ( !isdigit( num.Last() ) || !isdigit( num.GetChar( 0 ) ) ) )
242 {
243 // Trim non-digit from end
244 if( !isdigit( num.Last() ) )
245 num.RemoveLast();
246
247 // Trim non-digit from the start
248 if( !num.IsEmpty() && !isdigit( num.GetChar( 0 ) ) )
249 num = num.Right( num.Length() - 1 );
250 }
251
252 aTextEntry->SetSelection( ref.Find( num ), ref.Find( num ) + num.Length() );
253
254 if( num.IsEmpty() )
255 aTextEntry->SetSelection( -1, -1 );
256 }
257}
258
259
260bool KIUI::IsInputControlFocused( wxWindow* aFocus )
261{
262 if( aFocus == nullptr )
263 aFocus = wxWindow::FindFocus();
264
265 if( !aFocus )
266 return false;
267
268 // These widgets are never considered focused
269 if( aFocus->GetName() == s_FocusStealableInputName )
270 return false;
271
272 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( aFocus );
273 wxStyledTextCtrl* styledText = dynamic_cast<wxStyledTextCtrl*>( aFocus );
274 wxListBox* listBox = dynamic_cast<wxListBox*>( aFocus );
275 wxSearchCtrl* searchCtrl = dynamic_cast<wxSearchCtrl*>( aFocus );
276 wxCheckBox* checkboxCtrl = dynamic_cast<wxCheckBox*>( aFocus );
277 wxChoice* choiceCtrl = dynamic_cast<wxChoice*>( aFocus );
278 wxRadioButton* radioBtn = dynamic_cast<wxRadioButton*>( aFocus );
279 wxSpinCtrl* spinCtrl = dynamic_cast<wxSpinCtrl*>( aFocus );
280 wxSpinCtrlDouble* spinDblCtrl = dynamic_cast<wxSpinCtrlDouble*>( aFocus );
281 wxSlider* sliderCtl = dynamic_cast<wxSlider*>( aFocus );
282
283 // Data view control is annoying, the focus is on a "wxDataViewCtrlMainWindow" class that
284 // is not formally exported via the header.
285 wxDataViewCtrl* dataViewCtrl = nullptr;
286
287 wxWindow* parent = aFocus->GetParent();
288
289 if( parent )
290 dataViewCtrl = dynamic_cast<wxDataViewCtrl*>( parent );
291
292 return ( textEntry || styledText || listBox || searchCtrl || checkboxCtrl || choiceCtrl
293 || radioBtn || spinCtrl || spinDblCtrl || sliderCtl || dataViewCtrl );
294}
295
296
297bool KIUI::IsInputControlEditable( wxWindow* aFocus )
298{
299 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( aFocus );
300 wxStyledTextCtrl* styledText = dynamic_cast<wxStyledTextCtrl*>( aFocus );
301 wxSearchCtrl* searchCtrl = dynamic_cast<wxSearchCtrl*>( aFocus );
302
303 if( textEntry )
304 return textEntry->IsEditable();
305 else if( styledText )
306 return styledText->IsEditable();
307 else if( searchCtrl )
308 return searchCtrl->IsEditable();
309
310 return true; // Must return true if we can't determine the state, intentionally true for non inputs as well
311}
312
313
315{
316 return !Pgm().m_ModalDialogs.empty();
317}
318
319
320void KIUI::Disable( wxWindow* aWindow )
321{
322 wxScrollBar* scrollBar = dynamic_cast<wxScrollBar*>( aWindow );
323 wxGrid* grid = dynamic_cast<wxGrid*>( aWindow );
324 wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( aWindow );
325 wxControl* control = dynamic_cast<wxControl*>( aWindow );
326
327 if( scrollBar )
328 {
329 // Leave a scroll bar active
330 }
331 else if( grid )
332 {
333 for( int row = 0; row < grid->GetNumberRows(); ++row )
334 {
335 for( int col = 0; col < grid->GetNumberCols(); ++col )
336 grid->SetReadOnly( row, col );
337 }
338 }
339 else if( scintilla )
340 {
341 scintilla->SetReadOnly( true );
342 }
343 else if( control )
344 {
345 control->Disable();
346 }
347 else
348 {
349 for( wxWindow* child : aWindow->GetChildren() )
350 Disable( child );
351 }
352}
353
354
355void KIUI::AddBitmapToMenuItem( wxMenuItem* aMenu, const wxBitmap& aImage )
356{
357 // Retrieve the global application show icon option:
358 bool useImagesInMenus = Pgm().GetCommonSettings()->m_Appearance.use_icons_in_menus;
359
360 wxItemKind menu_type = aMenu->GetKind();
361
362 if( useImagesInMenus && menu_type != wxITEM_CHECK && menu_type != wxITEM_RADIO )
363 {
364 aMenu->SetBitmap( aImage );
365 }
366}
367
368
369wxMenuItem* KIUI::AddMenuItem( wxMenu* aMenu, int aId, const wxString& aText, const wxBitmap& aImage,
370 wxItemKind aType )
371{
372 wxMenuItem* item = new wxMenuItem( aMenu, aId, aText, wxEmptyString, aType );
373 AddBitmapToMenuItem( item, aImage );
374
375 aMenu->Append( item );
376
377 return item;
378}
379
380
381wxMenuItem* KIUI::AddMenuItem( wxMenu* aMenu, int aId, const wxString& aText, const wxString& aHelpText,
382 const wxBitmap& aImage, wxItemKind aType )
383{
384 wxMenuItem* item = new wxMenuItem( aMenu, aId, aText, aHelpText, aType );
385 AddBitmapToMenuItem( item, aImage );
386
387 aMenu->Append( item );
388
389 return item;
390}
391
392
393wxMenuItem* KIUI::AddMenuItem( wxMenu* aMenu, wxMenu* aSubMenu, int aId, const wxString& aText,
394 const wxBitmap& aImage )
395{
396 wxMenuItem* item = new wxMenuItem( aMenu, aId, aText );
397 item->SetSubMenu( aSubMenu );
398 AddBitmapToMenuItem( item, aImage );
399
400 aMenu->Append( item );
401
402 return item;
403}
404
405
406wxMenuItem* KIUI::AddMenuItem( wxMenu* aMenu, wxMenu* aSubMenu, int aId, const wxString& aText,
407 const wxString& aHelpText, const wxBitmap& aImage )
408{
409 wxMenuItem* item = new wxMenuItem( aMenu, aId, aText, aHelpText );
410 item->SetSubMenu( aSubMenu );
411 AddBitmapToMenuItem( item, aImage );
412
413 aMenu->Append( item );
414
415 return item;
416}
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:89
int GetStdMargin()
Get the standard margin around a widget in the KiCad UI.
Definition: ui_common.cpp:45
wxFont GetDockedPaneFont(wxWindow *aWindow)
Definition: ui_common.cpp:139
wxFont GetStatusFont(wxWindow *aWindow)
Definition: ui_common.cpp:127
bool IsInputControlFocused(wxWindow *aFocus=nullptr)
Check if a input control has focus.
Definition: ui_common.cpp:260
bool IsInputControlEditable(wxWindow *aControl)
Check if a input control has focus.
Definition: ui_common.cpp:297
void AddBitmapToMenuItem(wxMenuItem *aMenu, const wxBitmap &aImage)
Add a bitmap to a menuitem.
Definition: ui_common.cpp:355
wxString EllipsizeMenuText(const wxString &aString)
Ellipsize text (at the end) to be no more than 36 characters.
Definition: ui_common.cpp:210
wxFont GetInfoFont(wxWindow *aWindow)
Definition: ui_common.cpp:151
wxMenuItem * AddMenuItem(wxMenu *aMenu, int aId, const wxString &aText, const wxBitmap &aImage, wxItemKind aType=wxITEM_NORMAL)
Create and insert a menu item with an icon into aMenu.
Definition: ui_common.cpp:369
bool IsModalDialogFocused()
Definition: ui_common.cpp:314
wxFont GetControlFont(wxWindow *aWindow)
Definition: ui_common.cpp:157
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:192
const wxString s_FocusStealableInputName
Definition: ui_common.cpp:42
void SelectReferenceNumber(wxTextEntry *aTextEntry)
Select the number (or "?") in a reference for ease of editing.
Definition: ui_common.cpp:225
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:74
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:163
void Disable(wxWindow *aWindow)
Makes a window read-only.
Definition: ui_common.cpp:320
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:119
const int scale
wxString UnescapeString(const wxString &aSource)
SEVERITY SeverityFromString(const wxString &aSeverity)
Definition: ui_common.cpp:52
wxString SeverityToString(const SEVERITY &aSeverity)
Definition: ui_common.cpp:63
wxFont getGUIFont(wxWindow *aWindow, int aRelativeSize)
Definition: ui_common.cpp:105
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