1 /*$
2 Copyright (C) 2013-2020 Azel.
3
4 This file is part of AzPainter.
5
6 AzPainter 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 3 of the License, or
9 (at your option) any later version.
10
11 AzPainter 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 <http://www.gnu.org/licenses/>.
18 $*/
19
20 /*****************************************
21 * ValueBar
22 *
23 * スピンと数値表示付きの値選択バー
24 *****************************************/
25 /*
26 * [Ctrl+左右ドラッグ] で相対移動
27 *
28 * <通知>
29 * param1: 位置。
30 * param2: 値が確定した時1。押し時やドラッグ中は0。
31 *
32 */
33
34 #include "mDef.h"
35 #include "mWidgetDef.h"
36 #include "mWidget.h"
37 #include "mPixbuf.h"
38 #include "mEvent.h"
39 #include "mSysCol.h"
40 #include "mUtilStr.h"
41
42 #include "ValueBar.h"
43 #include "dataImagePattern.h"
44
45
46 //-------------------------
47
48 struct _ValueBar
49 {
50 mWidget wg;
51
52 int min,max,pos,dig,
53 fpress,lastx;
54 };
55
56 //-------------------------
57
58
59 //========================
60 // sub
61 //========================
62
63
64 /** 通知 */
65
_notify(ValueBar * p,int flag)66 static void _notify(ValueBar *p,int flag)
67 {
68 mWidgetAppendEvent_notify(NULL, M_WIDGET(p), 0, p->pos, flag);
69 }
70
71 /** 位置変更 */
72
_change_pos(ValueBar * p,int x)73 static void _change_pos(ValueBar *p,int x)
74 {
75 int pos;
76
77 pos = (int)((double)x * (p->max - p->min) / (p->wg.w - 2 - 8) + 0.5) + p->min;
78
79 if(pos < p->min)
80 pos = p->min;
81 else if(pos > p->max)
82 pos = p->max;
83
84 if(pos != p->pos)
85 {
86 p->pos = pos;
87
88 mWidgetUpdate(M_WIDGET(p));
89
90 _notify(p, 0);
91 }
92 }
93
94 /** 押し時 */
95
_event_press(ValueBar * p,mEvent * ev)96 static void _event_press(ValueBar *p,mEvent *ev)
97 {
98 if(ev->pt.x >= p->wg.w - 8)
99 {
100 //スピン
101
102 if(ValueBar_setPos(p, p->pos + ((ev->pt.y >= p->wg.h / 2)? -1: 1)))
103 _notify(p, 1);
104 }
105 else
106 {
107 //バー部分
108
109 p->fpress = (ev->pt.state & M_MODS_CTRL)? 2: 1;
110 p->lastx = ev->pt.x;
111
112 mWidgetGrabPointer(M_WIDGET(p));
113
114 if(p->fpress == 1)
115 _change_pos(p, ev->pt.x);
116 }
117 }
118
119 /** グラブ解除 */
120
_release_grab(ValueBar * p)121 static void _release_grab(ValueBar *p)
122 {
123 if(p->fpress)
124 {
125 p->fpress = 0;
126 mWidgetUngrabPointer(M_WIDGET(p));
127
128 _notify(p, 1);
129 }
130 }
131
132
133 //========================
134
135
136 /** イベント */
137
_event_handle(mWidget * wg,mEvent * ev)138 static int _event_handle(mWidget *wg,mEvent *ev)
139 {
140 ValueBar *p = VALUEBAR(wg);
141
142 switch(ev->type)
143 {
144 case MEVENT_POINTER:
145 if(ev->pt.type == MEVENT_POINTER_TYPE_MOTION)
146 {
147 //移動
148
149 if(p->fpress == 1)
150 _change_pos(p, ev->pt.x);
151 else if(p->fpress == 2)
152 {
153 //+Ctrl 相対移動
154
155 if(ValueBar_setPos(p, ev->pt.x - p->lastx + p->pos))
156 _notify(p, 0);
157
158 p->lastx = ev->pt.x;
159 }
160 }
161 else if(ev->pt.type == MEVENT_POINTER_TYPE_PRESS
162 || ev->pt.type == MEVENT_POINTER_TYPE_DBLCLK)
163 {
164 //押し
165
166 if(ev->pt.btt == M_BTT_LEFT && !p->fpress)
167 _event_press(p, ev);
168 }
169 else if(ev->pt.type == MEVENT_POINTER_TYPE_RELEASE)
170 {
171 //離し
172
173 if(ev->pt.btt == M_BTT_LEFT)
174 _release_grab(p);
175 }
176 break;
177 //ホイール
178 case MEVENT_SCROLL:
179 if(ev->scr.dir == MEVENT_SCROLL_DIR_UP
180 || ev->scr.dir == MEVENT_SCROLL_DIR_DOWN)
181 {
182 if(ValueBar_setPos(p, p->pos + (ev->scr.dir == MEVENT_SCROLL_DIR_UP? 1: -1)))
183 _notify(p, 1);
184 }
185 break;
186
187 case MEVENT_FOCUS:
188 if(ev->focus.bOut)
189 _release_grab(p);
190 break;
191 default:
192 return FALSE;
193 }
194
195 return TRUE;
196 }
197
198 /** 描画 */
199
_draw_handle(mWidget * wg,mPixbuf * pixbuf)200 static void _draw_handle(mWidget *wg,mPixbuf *pixbuf)
201 {
202 ValueBar *p = VALUEBAR(wg);
203 int n,n2;
204 char m[32],*pc;
205 mBool enabled;
206 mPixCol colframe;
207
208 enabled = ((wg->fState & MWIDGET_STATE_ENABLED) != 0);
209
210 colframe = (enabled)? MSYSCOL(FRAME_DARK): MSYSCOL(FRAME);
211
212 //枠
213
214 mPixbufBox(pixbuf, 0, 0, wg->w, wg->h, colframe);
215
216 //---- スピン
217
218 //背景
219
220 mPixbufFillBox(pixbuf, wg->w - 8, 1, 7, wg->h - 2, MSYSCOL(FACE_DARKER));
221
222 //縦線
223
224 mPixbufLineV(pixbuf, wg->w - 9, 1, wg->h - 2, colframe);
225
226 //矢印
227
228 mPixbufDrawArrowUp_small(pixbuf, wg->w - 5, 3, MSYSCOL(TEXT));
229 mPixbufDrawArrowDown_small(pixbuf, wg->w - 5, wg->h - 5, MSYSCOL(TEXT));
230
231 //---- バー
232
233 if(enabled)
234 n = (int)((double)(p->pos - p->min) * (wg->w - 2 - 8) / (p->max - p->min) + 0.5);
235 else
236 n = 0; //無効時はバー無し
237
238 if(n)
239 {
240 mPixbufFillBox(pixbuf, 1, 1, n, wg->h - 2,
241 (enabled)? MSYSCOL(FACE_FOCUS): MSYSCOL(FACE_DARKER));
242 }
243
244 //バー残り
245
246 n2 = wg->w - 2 - 8 - n;
247
248 if(n2 > 0)
249 {
250 mPixbufFillBox(pixbuf, 1 + n, 1, n2, wg->h - 2,
251 (enabled)? MSYSCOL(FACE_LIGHTEST): MSYSCOL(FACE));
252 }
253
254 //------ 数値
255
256 mFloatIntToStr(m, p->pos, p->dig);
257
258 for(pc = m; *pc; pc++)
259 {
260 if(*pc == '-')
261 *pc = 10;
262 else if(*pc == '.')
263 *pc = 11;
264 else
265 *pc -= '0';
266 }
267
268 *pc = -1;
269
270 mPixbufDrawBitPatternSum(pixbuf,
271 wg->w - 4 - 8 - (pc - m) * 5, 3,
272 g_imgpat_number_5x9, IMGPAT_NUMBER_5x9_PATW, 9, 5,
273 (uint8_t *)m, (enabled)? MSYSCOL(TEXT): MSYSCOL(TEXT_DISABLE));
274 }
275
276
277 //====================
278
279
280 /** 作成 */
281
ValueBar_new(mWidget * parent,int id,uint32_t fLayout,int dig,int min,int max,int pos)282 ValueBar *ValueBar_new(mWidget *parent,int id,uint32_t fLayout,
283 int dig,int min,int max,int pos)
284 {
285 ValueBar *p;
286
287 p = (ValueBar *)mWidgetNew(sizeof(ValueBar), parent);
288 if(!p) return NULL;
289
290 p->wg.id = id;
291 p->wg.fLayout = fLayout;
292 p->wg.fEventFilter |= MWIDGET_EVENTFILTER_POINTER | MWIDGET_EVENTFILTER_SCROLL;
293 p->wg.event = _event_handle;
294 p->wg.draw = _draw_handle;
295 p->wg.hintW = 15;
296 p->wg.hintH = 14;
297
298 if(pos < min) pos = min;
299 else if(pos > max) pos = max;
300
301 p->dig = dig;
302 p->min = min;
303 p->max = max;
304 p->pos = pos;
305
306 return p;
307 }
308
309 /** 位置を取得 */
310
ValueBar_getPos(ValueBar * p)311 int ValueBar_getPos(ValueBar *p)
312 {
313 return p->pos;
314 }
315
316 /** 位置をセット */
317
ValueBar_setPos(ValueBar * p,int pos)318 mBool ValueBar_setPos(ValueBar *p,int pos)
319 {
320 if(pos < p->min)
321 pos = p->min;
322 else if(pos > p->max)
323 pos = p->max;
324
325 if(pos == p->pos)
326 return FALSE;
327 else
328 {
329 p->pos = pos;
330
331 mWidgetUpdate(M_WIDGET(p));
332
333 return TRUE;
334 }
335 }
336
337 /** 範囲と位置をセット */
338
ValueBar_setStatus(ValueBar * p,int min,int max,int pos)339 void ValueBar_setStatus(ValueBar *p,int min,int max,int pos)
340 {
341 p->min = min;
342 p->max = max;
343 p->pos = pos;
344
345 mWidgetUpdate(M_WIDGET(p));
346 }
347
348 /** 全ステータスセット */
349
ValueBar_setStatus_dig(ValueBar * p,int dig,int min,int max,int pos)350 void ValueBar_setStatus_dig(ValueBar *p,int dig,int min,int max,int pos)
351 {
352 p->dig = dig;
353 p->min = min;
354 p->max = max;
355 p->pos = pos;
356
357 mWidgetUpdate(M_WIDGET(p));
358 }
359