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