KiCad PCB EDA Suite
Loading...
Searching...
No Matches
cursors.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
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <vector>
21#include <map>
22
23#include <gal/cursors.h>
24#include <kiplatform/ui.h>
25#include <pgm_base.h>
27
28// Cursor files
29#include <cursors/cursor-add.xpm>
30#include <cursors/cursor-component.xpm>
31#include <cursors/cursor-eraser.xpm>
32#include <cursors/cursor-label-global.xpm>
33#include <cursors/cursor-label-hier.xpm>
34#include <cursors/cursor-label-net.xpm>
35#include <cursors/cursor-line-bus.xpm>
36#include <cursors/cursor-line-graphic.xpm>
37#include <cursors/cursor-line-wire.xpm>
38#include <cursors/cursor-measure.xpm>
39#include <cursors/cursor-pencil.xpm>
40#include <cursors/cursor-select-lasso.xpm>
41#include <cursors/cursor-select-window.xpm>
42#include <cursors/cursor-subtract.xpm>
43#include <cursors/cursor-text.xpm>
44#include <cursors/cursor-xor.xpm>
45#include <cursors/cursor-zoom-in.xpm>
46#include <cursors/cursor-zoom-out.xpm>
47// Under MSW, the standard cursor is white on black. Elsewhere it is black on white
48#ifdef __WINDOWS__
49#include <cursors/cursor_tune.xpm>
50#include <cursors/voltage_probe_win.xpm>
51#include <cursors/current_probe_win.xpm>
52#else
53#include <cursors/cursor_tune_black.xpm>
54#include <cursors/voltage_probe_black.xpm>
55#include <cursors/current_probe_black.xpm>
56#endif
57
58// HiDPI cursor files
59#include <cursors/cursor-add64.xpm>
60#include <cursors/cursor-component64.xpm>
61#include <cursors/cursor-eraser64.xpm>
62#include <cursors/cursor-label-global64.xpm>
63#include <cursors/cursor-label-hier64.xpm>
64#include <cursors/cursor-label-net64.xpm>
65#include <cursors/cursor-line-bus64.xpm>
66#include <cursors/cursor-line-graphic64.xpm>
67#include <cursors/cursor-line-wire64.xpm>
68#include <cursors/cursor-measure64.xpm>
69#include <cursors/cursor-pencil64.xpm>
70#include <cursors/cursor-select-lasso64.xpm>
71#include <cursors/cursor-select-window64.xpm>
72#include <cursors/cursor-subtract64.xpm>
73#include <cursors/cursor-text64.xpm>
74#include <cursors/cursor-xor64.xpm>
75#include <cursors/cursor-zoom-in64.xpm>
76#include <cursors/cursor-zoom-out64.xpm>
77#ifdef __WINDOWS__
78#include <cursors/cursor_tune64.xpm>
79#include <cursors/voltage_probe_win64.xpm>
80#include <cursors/current_probe_win64.xpm>
81#else
82#include <cursors/cursor_tune_black64.xpm>
83#include <cursors/voltage_probe_black64.xpm>
84#include <cursors/current_probe_black64.xpm>
85#endif
86
87
88// Under MSW, the standard cursor is white on black. Elsewhere it is black on white
89#ifdef __WINDOWS__
90#include <cursors/cursor-place.xpm>
91#include <cursors/cursor-place64.xpm>
92#include <cursors/cursor-select-m.xpm>
93#include <cursors/cursor-select-m64.xpm>
94#include <cursors/cursor-warning.xpm>
95#include <cursors/cursor-warning64.xpm>
96#else
97#include <cursors/cursor-place-black.xpm>
98#include <cursors/cursor-place-black64.xpm>
99#include <cursors/cursor-select-m-black.xpm>
100#include <cursors/cursor-select-m-black64.xpm>
101#include <cursors/cursor-warning-black.xpm>
102#include <cursors/cursor-warning-black64.xpm>
103#endif
104
105#include <wx/bitmap.h>
106#include <wx/debug.h>
107#include <wx/bmpbndl.h>
108
109
110static const std::map<KICURSOR, std::vector<CURSOR_STORE::CURSOR_DEF>> cursors_defs = {
111 {
113 {
114 { voltage_probe_xpm, { 1, 31 } },
115 { voltage_probe64_xpm, { 1, 62 } }
116 }
117 },
118 {
120 {
121 { current_probe_xpm, { 4, 27 } },
122 { current_probe64_xpm, { 8, 54 } }
123 }
124 },
125 {
127 {
128 { cursor_tune_xpm, { 1, 30 } },
129 { cursor_tune64_xpm, { 2, 60 } }
130 }
131 },
132 {
134 {
135 { cursor_pencil_xpm, { 4, 27 } },
136 { cursor_pencil64_xpm, { 8, 54 } }
137 }
138 },
139 {
141 {
142 {
143#ifdef __WINDOWS__
144 cursor_select_m_xpm,
145#else
146 cursor_select_m_black_xpm,
147#endif
148 { 1, 1 }
149 },
150 {
151#ifdef __WINDOWS__
152 cursor_select_m64_xpm,
153#else
154 cursor_select_m_black64_xpm,
155#endif
156 { 2, 2 }
157 }
158 }
159 },
160 {
162 {
163 {
164#ifdef __WINDOWS__
165 cursor_warning_xpm,
166#else
167 cursor_warning_black_xpm,
168#endif
169 { 1, 1 }
170 },
171 {
172#ifdef __WINDOWS__
173 cursor_warning64_xpm,
174#else
175 cursor_warning_black64_xpm,
176#endif
177 { 2, 2 }
178 }
179 }
180 },
181 {
183 {
184 { cursor_eraser_xpm, { 4, 4 } },
185 { cursor_eraser64_xpm, { 8, 8 } }
186 }
187 },
188 {
190 {
191 { cursor_text_xpm, { 7, 7 } },
192 { cursor_text64_xpm, { 14, 14 } }
193 }
194 },
195 {
197 {
198 { cursor_measure_xpm, { 4, 4 } },
199 { cursor_measure64_xpm, { 8, 8 } }
200 }
201 },
202 {
204 {
205 { cursor_add_xpm, { 7, 7 } },
206 { cursor_add64_xpm, { 14, 14 } }
207 }
208 },
209 {
211 {
212 { cursor_subtract_xpm, { 7, 7 } },
213 { cursor_subtract64_xpm, { 14, 14 } }
214 }
215 },
216 {
218 {
219 { cursor_xor_xpm, { 7, 7 } },
220 { cursor_xor64_xpm, { 14, 14 } }
221 }
222 },
223 {
225 {
226 { cursor_zoom_in_xpm, { 6, 6 } },
227 { cursor_zoom_in64_xpm, { 12, 12 } }
228 }
229 },
230 {
232 {
233 { cursor_zoom_out_xpm, { 6, 6 } },
234 { cursor_zoom_out64_xpm, { 12, 12 } }
235 }
236 },
237 {
239 {
240 { cursor_label_net_xpm, { 7, 7 } },
241 { cursor_label_net64_xpm, { 14, 14 } }
242 }
243 },
244 {
246 {
247 { cursor_label_global_xpm, { 7, 7 } },
248 { cursor_label_global64_xpm, { 14, 14 } }
249 }
250 },
251 {
253 {
254 { cursor_component_xpm, { 7, 7 } },
255 { cursor_component64_xpm, { 14, 14 } }
256 }
257 },
258 {
260 {
261 { cursor_select_lasso_xpm, { 7, 7 } },
262 { cursor_select_lasso64_xpm, { 14, 14 } }
263 }
264 },
265 {
267 {
268 { cursor_select_window_xpm, { 7, 10 } },
269 { cursor_select_window64_xpm, { 14, 20 } }
270 }
271 },
272 {
274 {
275 { cursor_line_bus_xpm, { 5, 26 } },
276 { cursor_line_bus64_xpm, { 10, 52 } }
277 }
278 },
279 {
281 {
282 { cursor_line_wire_xpm, { 5, 26 } },
283 { cursor_line_wire64_xpm, { 10, 52 } }
284 }
285 },
286 {
288 {
289 { cursor_line_graphic_xpm, { 5, 26 } },
290 { cursor_line_graphic64_xpm, { 10, 52 } }
291 }
292 },
293 {
295 {
296 { cursor_label_hier_xpm, { 7, 7 } },
297 { cursor_label_hier64_xpm, { 14, 14 } }
298 }
299 },
300 {
302 {
303 {
304#ifdef __WINDOWS__
305 cursor_place_xpm,
306#else
307 cursor_place_black_xpm,
308#endif
309 { 1, 1 }
310 },
311 {
312#ifdef __WINDOWS__
313 cursor_place64_xpm,
314#else
315 cursor_place_black64_xpm,
316#endif
317 { 2, 2 }
318 }
319 }
320 }
321};
322
323
325{
326 for( const auto& [cursorId, defs] : cursors_defs )
327 {
328 wxCHECK2( !defs.empty(), continue );
329
330#if wxCHECK_VERSION( 3, 3, 0 )
331 // For wx 3.3+, create cursor bundles from the cursor definitions
332 std::vector<wxBitmap> bitmaps;
333
334 for( const auto& [xpm, hotspot_def] : defs )
335 {
336 wxCHECK2( xpm, continue );
337 bitmaps.push_back( wxBitmap( xpm ) );
338 }
339
340 wxBitmapBundle bitmapBundle = wxBitmapBundle::FromBitmaps( bitmaps );
341
342 wxPoint hotspot = defs[0].m_hotspot; // Use hotspot from standard cursor
343 m_bundleMap[cursorId] = wxCursorBundle( bitmapBundle, hotspot );
344#else
345 auto constructCursor = []( const CURSOR_STORE::CURSOR_DEF& aDef ) -> wxCursor
346 {
347 wxCHECK( aDef.m_xpm, wxNullCursor );
348 wxImage xpmImage = wxImage( aDef.m_xpm );
349
350 xpmImage.SetOption( wxIMAGE_OPTION_CUR_HOTSPOT_X, aDef.m_hotspot.x );
351 xpmImage.SetOption( wxIMAGE_OPTION_CUR_HOTSPOT_Y, aDef.m_hotspot.y );
352
353 return wxCursor( xpmImage );
354 };
355
356 // Add standard cursor (first definition)
357 m_standardCursorMap[cursorId] = constructCursor( defs[0] );
358
359 // Add HiDPI cursor (second definition if available, otherwise fallback to standard)
360 if( defs.size() > 1 )
361 m_hidpiCursorMap[cursorId] = constructCursor( defs[1] );
362 else
363 m_hidpiCursorMap[cursorId] = m_standardCursorMap[cursorId];
364#endif
365 }
366}
367
368#if wxCHECK_VERSION( 3, 3, 0 )
369const wxCursorBundle& CURSOR_STORE::storeGetBundle( KICURSOR aIdKey ) const
370{
371 const auto find_iter = m_bundleMap.find( aIdKey );
372
373 if( find_iter != m_bundleMap.end() )
374 return find_iter->second;
375
376 wxASSERT_MSG( false, wxString::Format( "Could not find cursor bundle with ID %d",
377 static_cast<int>( aIdKey ) ) );
378
379 static const wxCursorBundle invalid;
380
381 return invalid;
382}
383#else
384const wxCursor& CURSOR_STORE::storeGetCursor( KICURSOR aIdKey, bool aHiDPI ) const
385{
386 const auto& store = aHiDPI ? m_hidpiCursorMap : m_standardCursorMap;
387 const auto find_iter = store.find( aIdKey );
388
389 if( find_iter != store.end() )
390 return find_iter->second;
391
392 wxASSERT_MSG( false, wxString::Format( "Could not find cursor with ID %d", static_cast<int>( aIdKey ) ) );
393
394 return wxNullCursor;
395}
396#endif
397
398/* static */
399const WX_CURSOR_TYPE CURSOR_STORE::GetCursor( KICURSOR aCursorType, bool aHiDPI )
400{
401 // Use a single cursor store instance
402 static CURSOR_STORE store;
403
404 bool useCustomCursors = true;
405
406 if( COMMON_SETTINGS* commonSettings = Pgm().GetCommonSettings() )
407 useCustomCursors = commonSettings->m_Appearance.use_custom_cursors;
408
409 if( !useCustomCursors )
410 {
411 wxStockCursor stock = GetStockCursor( aCursorType );
412
413 if( stock == wxCURSOR_MAX )
414 stock = wxCURSOR_ARROW;
415
416 return WX_CURSOR_TYPE( stock );
417 }
418
419 wxStockCursor stock = GetStockCursor( aCursorType );
420
421 if( stock != wxCURSOR_MAX )
422 return WX_CURSOR_TYPE( stock );
423
424#if wxCHECK_VERSION( 3, 3, 0 )
425 // For wx 3.3+, return the pre-built cursor bundle (aHiDPI is ignored as bundles contain both)
426 return store.storeGetBundle( aCursorType );
427#else
428 return store.storeGetCursor( aCursorType, aHiDPI );
429#endif
430}
431
432/* static */
433wxStockCursor CURSOR_STORE::GetStockCursor( KICURSOR aCursorType )
434{
435 wxStockCursor stockCursor;
436 switch( aCursorType )
437 {
438 case KICURSOR::MOVING:
439 stockCursor = wxCURSOR_SIZING;
440 break;
442 stockCursor = wxCURSOR_BULLSEYE;
443 break;
444 case KICURSOR::HAND:
445 stockCursor = wxCURSOR_HAND;
446 break;
447 case KICURSOR::ARROW:
448 stockCursor = wxCURSOR_ARROW;
449 break;
450 default:
451 stockCursor = wxCURSOR_MAX;
452 break;
453 }
454
455 if( !KIPLATFORM::UI::IsStockCursorOk( stockCursor ) )
456 stockCursor = wxCURSOR_MAX;
457
458 return stockCursor;
459}
std::map< KICURSOR, wxCursor > m_hidpiCursorMap
Definition cursors.h:162
static const WX_CURSOR_TYPE GetCursor(KICURSOR aCursorType, bool aHiDPI=false)
Get a cursor bundle (wx 3.3+) or appropriate cursor (older versions)
Definition cursors.cpp:399
static wxStockCursor GetStockCursor(KICURSOR aCursorType)
Get stock cursor type for the given cursor.
Definition cursors.cpp:433
CURSOR_STORE()
Construct a store with cursors for all defined types.
Definition cursors.cpp:324
const wxCursor & storeGetCursor(KICURSOR aIdKey, bool aHiDPI=false) const
Get a cursor by its ID, automatically selecting the appropriate resolution.
Definition cursors.cpp:384
std::map< KICURSOR, wxCursor > m_standardCursorMap
Definition cursors.h:161
static const std::map< KICURSOR, std::vector< CURSOR_STORE::CURSOR_DEF > > cursors_defs
Definition cursors.cpp:110
KICURSOR
Definition cursors.h:40
@ LINE_BUS
Definition cursors.h:86
@ WARNING
Definition cursors.h:46
@ LINE_WIRE
Definition cursors.h:90
@ SUBTRACT
Definition cursors.h:68
@ VOLTAGE_PROBE
Definition cursors.h:56
@ SELECT_WINDOW
Definition cursors.h:82
@ REMOVE
Definition cursors.h:50
@ COMPONENT
Definition cursors.h:80
@ MEASURE
Definition cursors.h:64
@ PLACE
Definition cursors.h:94
@ SELECT_LASSO
Definition cursors.h:84
@ ZOOM_IN
Definition cursors.h:72
@ ZOOM_OUT
Definition cursors.h:74
@ LABEL_GLOBAL
Definition cursors.h:78
@ MOVING
Definition cursors.h:44
@ CURRENT_PROBE
Definition cursors.h:58
@ LABEL_NET
Definition cursors.h:76
@ ARROW
Definition cursors.h:42
@ LINE_GRAPHIC
Definition cursors.h:88
@ LABEL_HIER
Definition cursors.h:92
@ BULLSEYE
Definition cursors.h:54
@ PENCIL
Definition cursors.h:48
wxCursor WX_CURSOR_TYPE
Represents either a wxCursorBundle for wx 3.3+ or a wxCursor for older versions.
Definition cursors.h:35
bool IsStockCursorOk(wxStockCursor aCursor)
Checks if we designated a stock cursor for this OS as "OK" or else we may need to load a custom one.
Definition wxgtk/ui.cpp:199
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
Definition of a cursor.
Definition cursors.h:111