-
-
Notifications
You must be signed in to change notification settings - Fork 21
/
Copy pathspinbox.hpp
297 lines (254 loc) · 8.47 KB
/
spinbox.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
#pragma once
//=====================================================================//
/*! @file
@brief スピンボックス表示と制御 @n
通常のスピンボックスは、右端に小さい上下ボタンがあるが @n
タッチパネル操作を考慮して、左右にボタンを配置する @n
領域を三等分して、左、中央、右を判断する @n
左右のアクションにより、定数を進めたり、戻したりする。 @n
長押しの場合、加速する機能を有する。(許可/不許可)
@author 平松邦仁 ([email protected])
@copyright Copyright (C) 2019, 2024 Kunihito Hiramatsu @n
Released under the MIT license @n
https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include <functional>
#include "gui/widget.hpp"
#include "common/format.hpp"
namespace gui {
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
/*!
@brief スピンボックス・クラス
*/
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
struct spinbox : public widget {
typedef spinbox value_type;
static constexpr uint8_t ACCEL_WAIT = 75; ///< 加速開始までの遅延(フレーム数)
static constexpr uint8_t ACCEL_TICK = 4; ///< 加速遅延(フレーム数)
// 横幅を三等分した領域
enum class TOUCH_AREA : uint8_t {
LEFT, ///< 左側領域
CENTER, ///< 中心領域
RIGHT, ///< 右側領域
};
/// 数値設定構造体
struct number_t {
int16_t min; ///< 最小値
int16_t value; ///< 値
int16_t max; ///< 最大値
int16_t step; ///< 加算、減算幅
bool accel; ///< 数値変更の加速を有効にする場合「true」
/// 変数初期化は、gcc の拡張機能でー
/// { .min = -100, .value = 0, .max = 100, .step = 1, .accel = true }
void add() noexcept
{
if((value + step) <= max) {
value += step;
}
}
void sub() noexcept
{
if(min <= (value - step)) {
value -= step;
}
}
};
typedef std::function<void(TOUCH_AREA, int16_t)> SELECT_FUNC_TYPE; ///< 選択関数型
private:
SELECT_FUNC_TYPE select_func_;
TOUCH_AREA area_;
number_t number_;
uint8_t ace_wait_;
uint8_t ace_tick_;
public:
//-----------------------------------------------------------------//
/*!
@brief コンストラクター(整数版)
@param[in] loc ロケーション
@param[in] nmb 数値構造体の参照
*/
//-----------------------------------------------------------------//
spinbox(const vtx::srect& loc, const number_t& nmb) noexcept :
widget(loc, nullptr), select_func_(),
area_(TOUCH_AREA::CENTER), number_(nmb),
ace_wait_(0), ace_tick_(0)
{
if(get_location().size.y <= 0) {
at_location().size.y = DEF_SPINBOX_HEIGHT;
}
insert_widget(this);
}
spinbox(const spinbox& th) = delete;
spinbox& operator = (const spinbox& th) = delete;
//-----------------------------------------------------------------//
/*!
@brief デストラクタ
*/
//-----------------------------------------------------------------//
virtual ~spinbox() { remove_widget(this); }
//-----------------------------------------------------------------//
/*!
@brief 型整数を取得
@return 型整数
*/
//-----------------------------------------------------------------//
const char* get_name() const noexcept override { return "SpinBox"; }
//-----------------------------------------------------------------//
/*!
@brief ID を取得
@return ID
*/
//-----------------------------------------------------------------//
ID get_id() const noexcept override { return ID::SPINBOX; }
//-----------------------------------------------------------------//
/*!
@brief 初期化
*/
//-----------------------------------------------------------------//
void init() noexcept override { }
//-----------------------------------------------------------------//
/*!
@brief タッチ判定を更新
@param[in] pos 判定位置
@param[in] num タッチ数
*/
//-----------------------------------------------------------------//
void update_touch(const vtx::spos& pos, uint16_t num) noexcept override
{
update_touch_def(pos, num);
if(get_touch_state().level_) {
if(number_.accel) {
if(ace_wait_ < ACCEL_WAIT) {
++ace_wait_;
} else {
if(ace_tick_ < ACCEL_TICK) {
++ace_tick_;
} else {
ace_tick_ = 0;
set_exec_request();
}
}
}
auto pos = get_touch_state().relative_.x;
if(pos <= (get_location().size.x / 3)) {
area_ = TOUCH_AREA::LEFT;
} else if((get_location().size.x * 2 / 3) <= pos) {
area_ = TOUCH_AREA::RIGHT;
} else {
area_ = TOUCH_AREA::CENTER;
}
} else {
ace_wait_ = 0;
ace_tick_ = 0;
}
}
//-----------------------------------------------------------------//
/*!
@brief 選択推移
*/
//-----------------------------------------------------------------//
void exec_select() noexcept override
{
if(area_ == TOUCH_AREA::LEFT) {
number_.sub();
} else if(area_ == TOUCH_AREA::RIGHT) {
number_.add();
}
if(select_func_) {
select_func_(area_, number_.value);
}
}
//-----------------------------------------------------------------//
/*!
@brief 許可・不許可
@param[in] ena 不許可の場合「false」
*/
//-----------------------------------------------------------------//
void enable(bool ena = true) noexcept override
{
if(ena) {
set_state(STATE::ENABLE);
} else {
set_state(STATE::DISABLE);
reset_touch_state();
}
}
//-----------------------------------------------------------------//
/*!
@brief セレクト関数への参照
@return セレクト関数
*/
//-----------------------------------------------------------------//
SELECT_FUNC_TYPE& at_select_func() noexcept { return select_func_; }
//-----------------------------------------------------------------//
/*!
@brief 数値構造体の取得
@return 数値構造体
*/
//-----------------------------------------------------------------//
const auto& get_number() const noexcept { return number_; }
//-----------------------------------------------------------------//
/*!
@brief 数値構造体の参照
@return 数値構造体
*/
//-----------------------------------------------------------------//
auto& at_number() const noexcept { return number_; }
//-----------------------------------------------------------------//
/*!
@brief 値の変更
@param[in] value 値
*/
//-----------------------------------------------------------------//
void set_value(int16_t value) noexcept
{
if(number_.min <= value && value <= number_.max && number_.value != value) {
number_.value = value;
set_update();
}
}
//-----------------------------------------------------------------//
/*!
@brief 描画
@param[in] rdr 描画インスタンス
*/
//-----------------------------------------------------------------//
template<class RDR>
void draw(RDR& rdr) noexcept
{
auto r = vtx::srect(get_final_position(), get_location().size);
rdr.set_fore_color(get_base_color());
rdr.round_box(r, DEF_SPINBOX_ROUND_RADIUS);
uint8_t inten = 64;
if(get_touch_state().level_) { // 0.75
inten = 192;
}
graphics::share_color sc(0, 0, 0);
sc.set_color(get_base_color().rgba8, inten);
rdr.set_fore_color(sc);
r.org += DEF_SPINBOX_FRAME_WIDTH;
r.size -= DEF_SPINBOX_FRAME_WIDTH * 2;
rdr.round_box(r, DEF_SPINBOX_ROUND_RADIUS - DEF_SPINBOX_FRAME_WIDTH);
{
rdr.set_fore_color(get_font_color());
char tmp[8]; // 最大7桁(符号を入れて)
utils::sformat("%d", tmp, sizeof(tmp)) % number_.value;
auto sz = rdr.at_font().get_text_size(tmp);
rdr.draw_text(r.org + (r.size - sz) / 2, tmp);
}
// 左右のポイント描画
rdr.set_fore_color(get_base_color());
vtx::spos t[3];
t[0].x = r.org.x + DEF_SPINBOX_ARROW_SPACE;
t[0].y = r.org.y + r.size.y / 2;
t[1].x = t[2].x = r.org.x + DEF_SPINBOX_ARROW_SPACE + DEF_SPINBOX_ARROW_W;
t[1].y = r.org.y + r.size.y / 2 - DEF_SPINBOX_ARROW_H / 2;
t[2].y = r.org.y + r.size.y / 2 + DEF_SPINBOX_ARROW_H / 2;
rdr.fill_triangle(t[0], t[1], t[2]);
t[0].x = r.end_x() - DEF_SPINBOX_ARROW_SPACE - 1;
t[1].x = t[2].x = r.end_x() - DEF_SPINBOX_ARROW_SPACE - DEF_SPINBOX_ARROW_W - 1;
rdr.fill_triangle(t[0], t[2], t[1]);
}
};
}