The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
cursor.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2003 - 2025
3 by David White <dave@whitevine.net>
4 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY.
12
13 See the COPYING file for more details.
14*/
15
16/**
17 * @file
18 * Support for different cursors-shapes.
19 */
20
21#include "cursor.hpp"
22
23#include "picture.hpp"
25#include "sdl/utils.hpp"
26
27#include <boost/logic/tribool.hpp>
28
29#include <SDL3/SDL_mouse.h>
30
31#include <array>
32#include <memory>
33
34namespace cursor
35{
36namespace
37{
38struct cursor_data
39{
40 std::string image_bw;
41 std::string image_color;
42
43 int hot_x{0};
44 int hot_y{0};
45
46 boost::tribool is_color{boost::indeterminate};
47
48 using cursor_ptr = std::unique_ptr<SDL_Cursor, void(*)(SDL_Cursor*)>;
49 cursor_ptr cursor{nullptr, SDL_DestroyCursor};
50};
51
52// Array with each available cursor type.
53auto available_cursors = std::array
54{
55 cursor_data{ "normal.png", "normal.png", 0, 0 },
56 cursor_data{ "wait.png", "wait.png", 0, 0 },
57 cursor_data{ "ibeam.png", "ibeam.png", 14, 14 },
58 cursor_data{ "move.png", "move.png", 0, 0 },
59 cursor_data{ "attack.png", "attack.png", 0, 0 },
60 cursor_data{ "select.png", "select.png", 0, 0 },
61 cursor_data{ "move_drag.png", "move_drag.png", 2, 20 },
62 cursor_data{ "attack_drag.png", "attack_drag.png", 3, 22 },
63 cursor_data{ "no_cursor.png", "", 0, 0 }
64};
65
66static_assert(available_cursors.size() == cursor::NUM_CURSORS);
67
68cursor::CURSOR_TYPE current_cursor = cursor::NORMAL;
69bool have_focus = true;
70
71bool use_color_cursors()
72{
74}
75
76SDL_Cursor* create_cursor(const surface& surf)
77{
78 if(surf == nullptr) {
79 return nullptr;
80 }
81
82 // The width must be a multiple of 8 (SDL requirement)
83 std::size_t cursor_width = surf->w;
84 if((cursor_width % 8) != 0) {
85 cursor_width += 8 - (cursor_width % 8);
86 }
87
88 std::vector<uint8_t> data((cursor_width * surf->h) / 8, 0);
89 std::vector<uint8_t> mask(data.size(), 0);
90
91 // See https://wiki.libsdl.org/SDL_CreateCursor for documentation
92 // on the format that data has to be in to pass to SDL_CreateCursor
94 const utils::span pixels = lock.pixel_span();
95
96 for(int y = 0; y != surf->h; ++y) {
97 for(int x = 0; x != surf->w; ++x) {
98 if(static_cast<std::size_t>(x) < cursor_width) {
99 uint8_t r, g, b, a;
100 SDL_GetRGBA(pixels[y * surf->w + x], SDL_GetPixelFormatDetails(surf->format), SDL_GetSurfacePalette(surf), &r, &g, &b, &a);
101
102 const std::size_t index = y * cursor_width + x;
103 const std::size_t shift = 7 - (index % 8);
104
105 const uint8_t trans = (a < 128 ? 0 : 1) << shift;
106 const uint8_t black = (trans == 0 || (r + g + b) / 3 > 128 ? 0 : 1) << shift;
107
108 data[index / 8] |= black;
109 mask[index / 8] |= trans;
110 }
111 }
112 }
113
114 return SDL_CreateCursor(&data[0], &mask[0], cursor_width, surf->h, 0, 0);
115}
116
117SDL_Cursor* get_cursor(cursor::CURSOR_TYPE type)
118{
119 const bool use_color = use_color_cursors();
120 cursor_data& data = available_cursors[type];
121
122 if(data.cursor == nullptr || boost::indeterminate(data.is_color) || data.is_color != use_color) {
123 static const std::string color_prefix = "cursors/";
124 static const std::string bw_prefix = "cursors-bw/";
125
126 if(use_color) {
127 surface surf = image::get_surface(color_prefix + data.image_color);
128 data.cursor.reset(SDL_CreateColorCursor(surf, data.hot_x, data.hot_y));
129 } else {
130 surface surf = image::get_surface(bw_prefix + data.image_bw);
131 data.cursor.reset(create_cursor(surf));
132 }
133
134 data.is_color = use_color;
135 }
136
137 return data.cursor.get();
138}
139
140} // end anon namespace
141
143{
144 set();
145}
146
150
151void set(CURSOR_TYPE type)
152{
153 // Change only if it's a valid cursor
154 if(type != NUM_CURSORS) {
155 current_cursor = type;
156 } else if(current_cursor == NUM_CURSORS) {
157 // Except if the current one is also invalid.
158 // In this case, change to a valid one.
159 current_cursor = NORMAL;
160 }
161
162 SDL_SetCursor(get_cursor(current_cursor));
163}
164
165void set_dragging(bool drag)
166{
167 switch(current_cursor) {
168 case MOVE:
169 if(drag) cursor::set(MOVE_DRAG);
170 break;
171 case ATTACK:
172 if(drag) cursor::set(ATTACK_DRAG);
173 break;
174 case MOVE_DRAG:
175 if(!drag) cursor::set(MOVE);
176 break;
177 case ATTACK_DRAG:
178 if(!drag) cursor::set(ATTACK);
179 break;
180 default:
181 break;
182 }
183}
184
186{
187 return current_cursor;
188}
189
190void set_focus(bool focus)
191{
192 have_focus = focus;
193
194 if(!focus) {
195 set();
196 }
197}
198
200 : old_(current_cursor)
201{
202 set(type);
203}
204
206{
207 set(old_);
208}
209
210} // end namespace cursor
static prefs & get()
bool use_color_cursors()
Helper class for pinning SDL surfaces into memory.
Definition surface.hpp:98
std::string image_bw
Definition cursor.cpp:40
boost::tribool is_color
Definition cursor.cpp:46
int hot_x
Definition cursor.cpp:43
std::string image_color
Definition cursor.cpp:41
int hot_y
Definition cursor.cpp:44
CURSOR_TYPE get()
Definition cursor.cpp:185
void set_dragging(bool drag)
Definition cursor.cpp:165
CURSOR_TYPE
Definition cursor.hpp:28
@ ATTACK
Definition cursor.hpp:28
@ MOVE_DRAG
Definition cursor.hpp:28
@ NORMAL
Definition cursor.hpp:28
@ ATTACK_DRAG
Definition cursor.hpp:28
@ NUM_CURSORS
Definition cursor.hpp:28
@ MOVE
Definition cursor.hpp:28
void set(CURSOR_TYPE type)
Use the default parameter to reset cursors.
Definition cursor.cpp:151
void set_focus(bool focus)
Definition cursor.cpp:190
surface get_surface(const image::locator &i_locator, TYPE type, bool skip_cache)
Returns an image surface suitable for software manipulation.
Definition picture.cpp:691
std::size_t index(std::string_view str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition unicode.cpp:70
std::string_view data
Definition picture.cpp:188
surface surf
Image.
setter(CURSOR_TYPE type)
Definition cursor.cpp:199
CURSOR_TYPE old_
Definition cursor.hpp:46
#define g
#define b