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