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
GetStdMargin()41 int KIUI::GetStdMargin()
42 {
43 // This is the value used in (most) wxFB dialogs
44 return 5;
45 }
46
47
SeverityFromString(const wxString & aSeverity)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
SeverityToString(const SEVERITY & aSeverity)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
GetTextSize(const wxString & aSingleLine,wxWindow * aWindow)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
GetMonospacedUIFont()85 wxFont KIUI::GetMonospacedUIFont()
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
getGUIFont(wxWindow * aWindow,int aRelativeSize)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( "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
GetStatusFont(wxWindow * aWindow)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
GetInfoFont(wxWindow * aWindow)144 wxFont KIUI::GetInfoFont( wxWindow* aWindow )
145 {
146 return getGUIFont( aWindow, -1 );
147 }
148
149
GetControlFont(wxWindow * aWindow)150 wxFont KIUI::GetControlFont( wxWindow* aWindow )
151 {
152 return getGUIFont( aWindow, 0 );
153 }
154
155
EnsureTextCtrlWidth(wxTextCtrl * aCtrl,const wxString * aString)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
SelectReferenceNumber(wxTextEntry * aTextEntry)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
IsInputControlFocused(wxWindow * aFocus)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
IsInputControlEditable(wxWindow * aFocus)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
IsModalDialogFocused()270 bool KIUI::IsModalDialogFocused()
271 {
272 return Pgm().m_ModalDialogCount > 0;
273 }
274
275
Disable(wxWindow * aWindow)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 }