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