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 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/scrolwin.h>
32 #include <wx/grid.h>
33 #include <widgets/ui_common.h>
34 
35 #include <algorithm>
36 #include <dialog_shim.h>
37 #include <pgm_base.h>
38 #include <wx/settings.h>
39 #include <bitmaps/bitmap_types.h>
40 
42 {
43  // This is the value used in (most) wxFB dialogs
44  return 5;
45 }
46 
47 
48 SEVERITY SeverityFromString( const wxString& aSeverity )
49 {
50  if( aSeverity == wxT( "warning" ) )
51  return RPT_SEVERITY_WARNING;
52  else if( aSeverity == wxT( "ignore" ) )
53  return RPT_SEVERITY_IGNORE;
54  else
55  return RPT_SEVERITY_ERROR;
56 }
57 
58 
59 wxString 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 
70 wxSize 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( wxT( "Menlo" ) );
95 #endif
96 
97  return font;
98 }
99 
100 
101 wxFont 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( wxT( "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 
132 wxFont 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 
144 wxFont KIUI::GetInfoFont( wxWindow* aWindow )
145 {
146  return getGUIFont( aWindow, -1 );
147 }
148 
149 
150 wxFont KIUI::GetControlFont( wxWindow* aWindow )
151 {
152  return getGUIFont( aWindow, 0 );
153 }
154 
155 
156 bool 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 
185 void KIUI::SelectReferenceNumber( wxTextEntry* aTextEntry )
186 {
187  wxString ref = aTextEntry->GetValue();
188 
189  if( ref.find_first_of( '?' ) != ref.npos )
190  {
191  aTextEntry->SetSelection( ref.find_first_of( '?' ), ref.find_last_of( '?' ) + 1 );
192  }
193  else if( ref.find_first_of( '*' ) != ref.npos )
194  {
195  aTextEntry->SetSelection( ref.find_first_of( '*' ), ref.find_last_of( '*' ) + 1 );
196  }
197  else
198  {
199  wxString num = ref;
200 
201  while( !num.IsEmpty() && ( !isdigit( num.Last() ) || !isdigit( num.GetChar( 0 ) ) ) )
202  {
203  // Trim non-digit from end
204  if( !isdigit( num.Last() ) )
205  num.RemoveLast();
206 
207  // Trim non-digit from the start
208  if( !num.IsEmpty() && !isdigit( num.GetChar( 0 ) ) )
209  num = num.Right( num.Length() - 1 );
210  }
211 
212  aTextEntry->SetSelection( ref.Find( num ), ref.Find( num ) + num.Length() );
213 
214  if( num.IsEmpty() )
215  aTextEntry->SetSelection( -1, -1 );
216  }
217 }
218 
219 
220 bool KIUI::IsInputControlFocused( wxWindow* aFocus )
221 {
222  if( aFocus == nullptr )
223  aFocus = wxWindow::FindFocus();
224 
225  if( !aFocus )
226  return false;
227 
228  wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( aFocus );
229  wxStyledTextCtrl* styledText = dynamic_cast<wxStyledTextCtrl*>( aFocus );
230  wxListBox* listBox = dynamic_cast<wxListBox*>( aFocus );
231  wxSearchCtrl* searchCtrl = dynamic_cast<wxSearchCtrl*>( aFocus );
232  wxCheckBox* checkboxCtrl = dynamic_cast<wxCheckBox*>( aFocus );
233  wxChoice* choiceCtrl = dynamic_cast<wxChoice*>( aFocus );
234  wxRadioButton* radioBtn = dynamic_cast<wxRadioButton*>( aFocus );
235  wxSpinCtrl* spinCtrl = dynamic_cast<wxSpinCtrl*>( aFocus );
236  wxSpinCtrlDouble* spinDblCtrl = dynamic_cast<wxSpinCtrlDouble*>( aFocus );
237  wxSlider* sliderCtl = dynamic_cast<wxSlider*>( aFocus );
238 
239  // Data view control is annoying, the focus is on a "wxDataViewCtrlMainWindow" class that
240  // is not formerly exported via the header.
241  wxDataViewCtrl* dataViewCtrl = nullptr;
242 
243  wxWindow* parent = aFocus->GetParent();
244 
245  if( parent )
246  dataViewCtrl = dynamic_cast<wxDataViewCtrl*>( parent );
247 
248  return ( textEntry || styledText || listBox || searchCtrl || checkboxCtrl || choiceCtrl
249  || radioBtn || spinCtrl || spinDblCtrl || sliderCtl || dataViewCtrl );
250 }
251 
252 
253 bool KIUI::IsInputControlEditable( wxWindow* aFocus )
254 {
255  wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( aFocus );
256  wxStyledTextCtrl* styledText = dynamic_cast<wxStyledTextCtrl*>( aFocus );
257  wxSearchCtrl* searchCtrl = dynamic_cast<wxSearchCtrl*>( aFocus );
258 
259  if( textEntry )
260  return textEntry->IsEditable();
261  else if( styledText )
262  return styledText->IsEditable();
263  else if( searchCtrl )
264  return searchCtrl->IsEditable();
265 
266  return true; // Must return true if we can't determine the state, intentionally true for non inputs as well
267 }
268 
269 
271 {
272  return Pgm().m_ModalDialogCount > 0;
273 }
274 
275 
276 void KIUI::Disable( wxWindow* aWindow )
277 {
278  wxScrollBar* scrollBar = dynamic_cast<wxScrollBar*>( aWindow );
279  wxGrid* grid = dynamic_cast<wxGrid*>( aWindow );
280  wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( aWindow );
281  wxControl* control = dynamic_cast<wxControl*>( aWindow );
282 
283  if( scrollBar )
284  {
285  // Leave a scroll bar active
286  }
287  else if( grid )
288  {
289  for( int row = 0; row < grid->GetNumberRows(); ++row )
290  {
291  for( int col = 0; col < grid->GetNumberCols(); ++col )
292  grid->SetReadOnly( row, col );
293  }
294  }
295  else if( scintilla )
296  {
297  scintilla->SetReadOnly( true );
298  }
299  else if( control )
300  {
301  control->Disable();
302  }
303  else
304  {
305  for( wxWindow* child : aWindow->GetChildren() )
306  Disable( child );
307  }
308 }
void SelectReferenceNumber(wxTextEntry *aTextEntry)
Select the number (or "?") in a reference for ease of editing.
Definition: ui_common.cpp:185
bool IsModalDialogFocused()
Definition: ui_common.cpp:270
bool IsInputControlEditable(wxWindow *aControl)
Check if a input control has focus.
Definition: ui_common.cpp:253
void Disable(wxWindow *aWindow)
Makes a window read-only.
Definition: ui_common.cpp:276
wxFont GetMonospacedUIFont()
Definition: ui_common.cpp:85
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 GetInfoFont(wxWindow *aWindow)
Definition: ui_common.cpp:144
int GetStdMargin()
Get the standard margin around a widget in the KiCad UI.
Definition: ui_common.cpp:41
wxFont GetControlFont(wxWindow *aWindow)
Definition: ui_common.cpp:150
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:106
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
bool IsInputControlFocused(wxWindow *aFocus=nullptr)
Check if a input control has focus.
Definition: ui_common.cpp:220
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
Functions to provide common constants and other functions to assist in making a consistent UI.
SEVERITY
wxFont GetStatusFont(wxWindow *aWindow)
Definition: ui_common.cpp:132
const int scale
see class PGM_BASE
wxString SeverityToString(const SEVERITY &aSeverity)
Definition: ui_common.cpp:59
wxFont getGUIFont(wxWindow *aWindow, int aRelativeSize)
Definition: ui_common.cpp:101
SEVERITY SeverityFromString(const wxString &aSeverity)
Definition: ui_common.cpp:48
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:73