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 * mButton [ボタン]
22 *****************************************/
23
24 #include <string.h>
25
26 #include "mDef.h"
27
28 #include "mButton.h"
29 #include "mWidget.h"
30 #include "mFont.h"
31 #include "mPixbuf.h"
32 #include "mEvent.h"
33 #include "mSysCol.h"
34 #include "mKeyDef.h"
35
36
37 //-----------------------
38
39 #define BTT_DEFW 64
40 #define BTT_DEFH 21
41
42 enum MBUTTON_FLAGS
43 {
44 MBUTTON_FLAGS_PRESSED = 1<<0,
45 MBUTTON_FLAGS_GRAB = 1<<1
46 };
47
48 //-----------------------
49
50
51 /******************//**
52
53 @defgroup button mButton
54 @brief ボタン
55
56 <h3>継承</h3>
57 mWidget \> mButton
58
59 @ingroup group_widget
60
61 @{
62
63 @file mButton.h
64 @struct _mButton
65 @struct mButtonData
66 @enum MBUTTON_STYLE
67 @enum MBUTTON_NOTIFY
68
69 @var MBUTTON_NOTIFY::MBUTTON_N_PRESS
70 ボタンが押された
71
72 ********************/
73
74
75 //==========================
76
77
78 /** グラブ状態解除 */
79
_grab_release(mButton * p,mBool pressed)80 static void _grab_release(mButton *p,mBool pressed)
81 {
82 //押し状態解除
83
84 if(p->btt.flags & MBUTTON_FLAGS_GRAB)
85 {
86 mWidgetUngrabPointer(M_WIDGET(p));
87
88 p->btt.flags &= ~MBUTTON_FLAGS_GRAB;
89 p->btt.press_key = 0;
90
91 mButtonSetPress(p, FALSE);
92 }
93
94 //ハンドラ実行
95
96 if(pressed)
97 (p->btt.onPressed)(p);
98 }
99
100 /** ボタン/キー押し時 */
101
_pressed(mButton * p)102 static void _pressed(mButton *p)
103 {
104 p->btt.flags |= MBUTTON_FLAGS_GRAB;
105
106 mButtonSetPress(p, TRUE);
107 }
108
109 /** onPress() デフォルト */
110
_handle_pressed(mButton * p)111 static void _handle_pressed(mButton *p)
112 {
113 mWidgetAppendEvent_notify(NULL, M_WIDGET(p), MBUTTON_N_PRESS, 0, 0);
114 }
115
116
117 //==========================
118
119
120 /** 解放処理 */
121
mButtonDestroyHandle(mWidget * p)122 void mButtonDestroyHandle(mWidget *p)
123 {
124 mButton *btt = M_BUTTON(p);
125
126 M_FREE_NULL(btt->btt.text);
127 }
128
129 /** ボタン作成 */
130
mButtonCreate(mWidget * parent,int id,uint32_t style,uint32_t fLayout,uint32_t marginB4,const char * text)131 mButton *mButtonCreate(mWidget *parent,int id,uint32_t style,
132 uint32_t fLayout,uint32_t marginB4,const char *text)
133 {
134 mButton *p;
135
136 p = mButtonNew(0, parent, style);
137 if(!p) return NULL;
138
139 p->wg.id = id;
140 p->wg.fLayout = fLayout;
141
142 mWidgetSetMargin_b4(M_WIDGET(p), marginB4);
143
144 mButtonSetText(p, text);
145
146 return p;
147 }
148
149 /** ボタン作成 */
150
mButtonNew(int size,mWidget * parent,uint32_t style)151 mButton *mButtonNew(int size,mWidget *parent,uint32_t style)
152 {
153 mButton *p;
154
155 if(size < sizeof(mButton)) size = sizeof(mButton);
156
157 p = (mButton *)mWidgetNew(size, parent);
158 if(!p) return NULL;
159
160 p->wg.destroy = mButtonDestroyHandle;
161 p->wg.calcHint = mButtonCalcHintHandle;
162 p->wg.draw = mButtonDrawHandle;
163 p->wg.event = mButtonEventHandle;
164
165 p->wg.fState |= MWIDGET_STATE_TAKE_FOCUS;
166 p->wg.fEventFilter |= MWIDGET_EVENTFILTER_POINTER | MWIDGET_EVENTFILTER_KEY;
167 p->wg.fAcceptKeys = MWIDGET_ACCEPTKEY_ENTER;
168
169 p->btt.style = style;
170 p->btt.onPressed = _handle_pressed;
171
172 return p;
173 }
174
175 /** テキストセット */
176
mButtonSetText(mButton * p,const char * text)177 void mButtonSetText(mButton *p,const char *text)
178 {
179 mFree(p->btt.text);
180
181 p->btt.text = mStrdup(text);
182
183 mWidgetCalcHintSize(M_WIDGET(p));
184 mWidgetUpdate(M_WIDGET(p));
185 }
186
187 /** 押し状態変更 */
188
mButtonSetPress(mButton * p,mBool press)189 void mButtonSetPress(mButton *p,mBool press)
190 {
191 int now;
192
193 now = ((p->btt.flags & MBUTTON_FLAGS_PRESSED) != 0);
194
195 if(!now != !press)
196 {
197 if(press)
198 p->btt.flags |= MBUTTON_FLAGS_PRESSED;
199 else
200 p->btt.flags &= ~MBUTTON_FLAGS_PRESSED;
201
202 mWidgetUpdate(M_WIDGET(p));
203 }
204 }
205
206 /** 押された状態か */
207
mButtonIsPressed(mButton * p)208 mBool mButtonIsPressed(mButton *p)
209 {
210 return ((p->btt.flags & MBUTTON_FLAGS_PRESSED) != 0);
211 }
212
213 /** ボタンのベースを描画 */
214
mButtonDrawBase(mButton * p,mPixbuf * pixbuf,mBool pressed)215 void mButtonDrawBase(mButton *p,mPixbuf *pixbuf,mBool pressed)
216 {
217 uint32_t flags = 0;
218
219 if(pressed) flags |= MPIXBUF_DRAWBTT_PRESS;
220 if(p->wg.fState & MWIDGET_STATE_FOCUSED) flags |= MPIXBUF_DRAWBTT_FOCUS;
221 if(!(p->wg.fState & MWIDGET_STATE_ENABLED)) flags |= MPIXBUF_DRAWBTT_DISABLE;
222 if(p->wg.fState & MWIDGET_STATE_ENTER_DEFAULT) flags |= MPIXBUF_DRAWBTT_DEFAULT_BUTTON;
223
224 mPixbufDrawButton(pixbuf, 0, 0, p->wg.w, p->wg.h, flags);
225 }
226
227
228 //========================
229 // ハンドラ
230 //========================
231
232
233 /** サイズ計算 */
234
mButtonCalcHintHandle(mWidget * p)235 void mButtonCalcHintHandle(mWidget *p)
236 {
237 mButton *btt = M_BUTTON(p);
238 mFont *font = mWidgetGetFont(p);
239 int w,h;
240
241 //幅
242
243 w = mFontGetTextWidth(font, btt->btt.text, -1);
244
245 btt->btt.textW = w;
246
247 if(btt->btt.style & MBUTTON_S_REAL_W)
248 w += 8;
249 else
250 {
251 w += 10;
252
253 if(w < BTT_DEFW)
254 {
255 w = BTT_DEFW;
256 if((w - btt->btt.textW) & 1) w++;
257 }
258 }
259
260 //高さ
261
262 h = font->height;
263
264 if(btt->btt.style & MBUTTON_S_REAL_H)
265 h += 6;
266 else
267 {
268 h += 8;
269
270 if(h < BTT_DEFH)
271 {
272 h = BTT_DEFH;
273 if((h - font->height) & 1) h++;
274 }
275 }
276
277 //REAL_W 時は高さが最小
278
279 if((btt->btt.style & MBUTTON_S_REAL_W) && w < h)
280 w = h;
281
282 p->hintW = w;
283 p->hintH = h;
284 }
285
286 /** イベント */
287
mButtonEventHandle(mWidget * wg,mEvent * ev)288 int mButtonEventHandle(mWidget *wg,mEvent *ev)
289 {
290 mButton *btt = M_BUTTON(wg);
291
292 switch(ev->type)
293 {
294 case MEVENT_POINTER:
295 if(ev->pt.type == MEVENT_POINTER_TYPE_PRESS
296 || ev->pt.type == MEVENT_POINTER_TYPE_DBLCLK)
297 {
298 //押し
299
300 if(ev->pt.btt == M_BTT_LEFT
301 && !(btt->btt.flags & MBUTTON_FLAGS_GRAB))
302 {
303 mWidgetSetFocus_update(wg, FALSE);
304 mWidgetGrabPointer(wg);
305
306 _pressed(btt);
307 }
308 }
309 else if(ev->pt.type == MEVENT_POINTER_TYPE_RELEASE)
310 {
311 //離し
312
313 if(ev->pt.btt == M_BTT_LEFT
314 && (btt->btt.flags & MBUTTON_FLAGS_GRAB)
315 && btt->btt.press_key == 0)
316 _grab_release(btt, TRUE);
317 }
318 return TRUE;
319
320 //キー
321 case MEVENT_KEYDOWN:
322 if((ev->key.code == MKEY_SPACE || ev->key.code == MKEY_ENTER)
323 && !(btt->btt.flags & MBUTTON_FLAGS_GRAB))
324 {
325 btt->btt.press_key = ev->key.code;
326
327 _pressed(btt);
328
329 return TRUE;
330 }
331 break;
332 case MEVENT_KEYUP:
333 if((btt->btt.flags & MBUTTON_FLAGS_GRAB)
334 && btt->btt.press_key == ev->key.code)
335 {
336 _grab_release(btt, TRUE);
337 return TRUE;
338 }
339 break;
340
341 case MEVENT_FOCUS:
342 //フォーカスアウト時、グラブ状態解除
343 if(ev->focus.bOut)
344 _grab_release(btt, FALSE);
345
346 mWidgetUpdate(wg);
347 return TRUE;
348 }
349
350 return FALSE;
351 }
352
353 /** 描画 */
354
mButtonDrawHandle(mWidget * p,mPixbuf * pixbuf)355 void mButtonDrawHandle(mWidget *p,mPixbuf *pixbuf)
356 {
357 mButton *btt = M_BUTTON(p);
358 mFont *font;
359 int tx,ty,press;
360
361 font = mWidgetGetFont(p);
362
363 press = ((btt->btt.flags & MBUTTON_FLAGS_PRESSED) != 0);
364
365 //テキスト位置
366
367 tx = (p->w - btt->btt.textW) >> 1;
368 ty = (p->h - font->height) >> 1;
369
370 if(press) tx++, ty++;
371
372 //ボタン
373
374 mButtonDrawBase(btt, pixbuf, press);
375
376 //テキスト
377
378 mFontDrawText(font, pixbuf, tx, ty, btt->btt.text, -1,
379 (p->fState & MWIDGET_STATE_ENABLED)? MSYSCOL_RGB(TEXT): MSYSCOL_RGB(TEXT_DISABLE));
380 }
381
382 /** @} */
383