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 * DockCanvasViewArea
22 *
23 * [dock] キャンバスビューの表示エリア
24 *****************************************/
25
26 #include "mDef.h"
27 #include "mWidgetDef.h"
28 #include "mWidget.h"
29 #include "mEvent.h"
30 #include "mPixbuf.h"
31
32 #include "defConfig.h"
33 #include "defDraw.h"
34 #include "defCanvasInfo.h"
35
36 #include "ImageBufRGB16.h"
37 #include "PixbufDraw.h"
38
39 #include "draw_main.h"
40
41 #include "DockCanvasView.h"
42
43
44 //-------------------
45
46 typedef struct _DockCanvasViewArea
47 {
48 mWidget wg;
49
50 DockCanvasView *canvasview;
51 int dragbtt, //ドラッグ時の操作ボタン
52 optype, //現在の操作タイプ
53 lastx,lasty;
54 }DockCanvasViewArea;
55
56 //-------------------
57
58 #define _CVAREA(p) ((DockCanvasViewArea *)(p))
59 #define _IS_LOUPE_MODE (APP_CONF->canvasview_flags & CONFIG_CANVASVIEW_F_LOUPE_MODE)
60 #define _IS_ZOOM_FIT (APP_CONF->canvasview_flags & CONFIG_CANVASVIEW_F_FIT)
61
62 enum
63 {
64 _OPTYPE_VIEW_SCROLL,
65 _OPTYPE_CANVAS_SCROLL,
66 _OPTYPE_VIEW_ZOOM
67 };
68
69 //-------------------
70
71
72 //==========================
73 // sub
74 //==========================
75
76
77 /** ボタンから操作タイプ取得 */
78
_get_optype_from_button(int btt,uint32_t state)79 static int _get_optype_from_button(int btt,uint32_t state)
80 {
81 int no = -1;
82
83 if(btt == M_BTT_LEFT)
84 {
85 //左ボタン
86
87 if(state & M_MODS_CTRL)
88 no = 1;
89 else if(state & M_MODS_SHIFT)
90 no = 2;
91 else
92 no = 0;
93 }
94 else if(btt == M_BTT_RIGHT)
95 no = 3;
96 else if(btt == M_BTT_MIDDLE)
97 no = 4;
98
99 if(no < 0) return -1;
100
101 //設定データ
102
103 no = APP_CONF->canvasview_btt[no];
104
105 //全体表示時は、キャンバススクロールのみ
106
107 if(_IS_ZOOM_FIT && no != _OPTYPE_CANVAS_SCROLL)
108 return -1;
109
110 return no;
111 }
112
113 /** キャンバススクロール */
114
_canvas_scroll(DockCanvasViewArea * p,int x,int y)115 static void _canvas_scroll(DockCanvasViewArea *p,int x,int y)
116 {
117 DockCanvasView *cv = p->canvasview;
118 mDoublePoint pt;
119
120 pt.x = (x + cv->ptScroll.x - (p->wg.w >> 1)) * cv->dscalediv + cv->originX;
121 pt.y = (y + cv->ptScroll.y - (p->wg.h >> 1)) * cv->dscalediv + cv->originY;
122
123 drawCanvas_setScrollReset_update(APP_DRAW, &pt);
124 }
125
126
127 //==========================
128 // ハンドラ
129 //==========================
130
131
132 /** ボタン押し時 */
133
_event_press(DockCanvasViewArea * p,mEvent * ev)134 static void _event_press(DockCanvasViewArea *p,mEvent *ev)
135 {
136 int type;
137
138 type = _get_optype_from_button(ev->pt.btt, ev->pt.state);
139 if(type < 0) return;
140
141 p->dragbtt = ev->pt.btt;
142 p->optype = type;
143 p->lastx = ev->pt.x;
144 p->lasty = ev->pt.y;
145
146 mWidgetGrabPointer(M_WIDGET(p));
147
148 //キャンバススクロール
149
150 if(type == _OPTYPE_CANVAS_SCROLL)
151 {
152 drawCanvas_lowQuality();
153
154 _canvas_scroll(p, ev->pt.x, ev->pt.y);
155 }
156 }
157
158 /** 移動時 - 倍率変更 */
159
_motion_zoom(DockCanvasViewArea * p,int y)160 static void _motion_zoom(DockCanvasViewArea *p,int y)
161 {
162 int n,dir;
163
164 n = p->canvasview->zoom;
165
166 dir = p->lasty - y;
167 if(dir == 0) return;
168
169 n += dir * ((n < 100)? 2: 10);
170
171 if(n < 2) n = 2;
172 else if(n > 1000) n = 1000;
173
174 if(n < 100)
175 n &= ~1;
176 else
177 n = n / 10 * 10;
178
179 //セット
180
181 if(DockCanvasView_setZoom(p->canvasview, n))
182 mWidgetUpdate(M_WIDGET(p));
183 }
184
185 /** ポインタ移動時 */
186
_event_motion(DockCanvasViewArea * p,mEvent * ev)187 static void _event_motion(DockCanvasViewArea *p,mEvent *ev)
188 {
189 switch(p->optype)
190 {
191 //ビュー内スクロール
192 case _OPTYPE_VIEW_SCROLL:
193 p->canvasview->ptScroll.x += p->lastx - ev->pt.x;
194 p->canvasview->ptScroll.y += p->lasty - ev->pt.y;
195
196 DockCanvasView_adjustScroll(p->canvasview);
197
198 mWidgetUpdate(M_WIDGET(p));
199 break;
200
201 //キャンバススクロール
202 case _OPTYPE_CANVAS_SCROLL:
203 _canvas_scroll(p, ev->pt.x, ev->pt.y);
204 break;
205
206 //倍率変更
207 case _OPTYPE_VIEW_ZOOM:
208 _motion_zoom(p, ev->pt.y);
209 break;
210 }
211
212 p->lastx = ev->pt.x;
213 p->lasty = ev->pt.y;
214 }
215
216 /** ドラッグ解除 */
217
_release_drag(DockCanvasViewArea * p)218 static void _release_drag(DockCanvasViewArea *p)
219 {
220 if(p->dragbtt)
221 {
222 p->dragbtt = 0;
223
224 mWidgetUngrabPointer(M_WIDGET(p));
225 mWidgetUpdate(M_WIDGET(p));
226
227 //キャンバス、元の品質に戻す
228
229 if(p->optype == _OPTYPE_CANVAS_SCROLL)
230 {
231 drawCanvas_normalQuality();
232 drawUpdate_canvasArea();
233 }
234 }
235 }
236
237 /** イベント */
238
_event_handle(mWidget * wg,mEvent * ev)239 static int _event_handle(mWidget *wg,mEvent *ev)
240 {
241 DockCanvasViewArea *p = _CVAREA(wg);
242
243 switch(ev->type)
244 {
245 case MEVENT_POINTER:
246 if(ev->pt.type == MEVENT_POINTER_TYPE_MOTION)
247 {
248 //移動
249
250 if(p->dragbtt)
251 _event_motion(p, ev);
252 }
253 else if(ev->pt.type == MEVENT_POINTER_TYPE_PRESS)
254 {
255 //押し (ルーペ時は無効)
256
257 if(!p->dragbtt && !_IS_LOUPE_MODE)
258 _event_press(p, ev);
259 }
260 else if(ev->pt.type == MEVENT_POINTER_TYPE_RELEASE)
261 {
262 //離し
263
264 if(ev->pt.btt == p->dragbtt)
265 _release_drag(p);
266 }
267 break;
268
269 case MEVENT_FOCUS:
270 if(ev->focus.bOut)
271 _release_drag(p);
272 break;
273 }
274
275 return 1;
276 }
277
278 /** サイズ変更時 */
279
_onsize_handle(mWidget * wg)280 static void _onsize_handle(mWidget *wg)
281 {
282 DockCanvasView_setZoom_fit(_CVAREA(wg)->canvasview);
283 DockCanvasView_adjustScroll(_CVAREA(wg)->canvasview);
284 }
285
286
287 //==========================
288 // 描画
289 //==========================
290
291
292 /** ルーペ時の十字線描画 */
293
_draw_loupe_cross(DockCanvasViewArea * p,DockCanvasView * cv,mPixbuf * pixbuf,mBox * box)294 static void _draw_loupe_cross(DockCanvasViewArea *p,
295 DockCanvasView *cv,mPixbuf *pixbuf,mBox *box)
296 {
297 double d;
298
299 if(cv->zoom >= 400)
300 {
301 //400% 以上の場合、破線
302
303 d = -0.5 * cv->dscale;
304
305 pixbufDraw_cross_dash(pixbuf,
306 (p->wg.w >> 1) + d + 0.5, (p->wg.h >> 1) + d + 0.5,
307 cv->zoom / 100, box);
308 }
309 else
310 {
311 //400% 未満の場合、1px 合成線
312
313 mPixbufLineH_blend(pixbuf, box->x, p->wg.h >> 1, box->w, 0x0000ff, 100);
314 mPixbufLineV_blend(pixbuf, p->wg.w >> 1, box->y, box->h, 0x0000ff, 100);
315 }
316 }
317
318 /** キャンバス描画 */
319
_draw_canvas(DockCanvasViewArea * p,mPixbuf * pixbuf,mBox * box)320 static void _draw_canvas(DockCanvasViewArea *p,mPixbuf *pixbuf,mBox *box)
321 {
322 DockCanvasView *cv = p->canvasview;
323 CanvasDrawInfo info;
324 CanvasViewParam param;
325
326 info.boxdst = *box;
327 info.originx = cv->originX;
328 info.originy = cv->originY;
329 info.scrollx = cv->ptScroll.x - p->wg.w / 2;
330 info.scrolly = cv->ptScroll.y - p->wg.h / 2;
331 info.mirror = 0;
332 info.imgw = APP_DRAW->imgw;
333 info.imgh = APP_DRAW->imgh;
334 info.bkgndcol = APP_CONF->colCanvasBkgnd;
335 info.param = ¶m;
336
337 param.scalediv = cv->dscalediv;
338
339 if(cv->zoom < 100 && p->dragbtt == 0)
340 //縮小時 (ドラッグ時は除く)
341 ImageBufRGB16_drawMainCanvas_oversamp(APP_DRAW->blendimg, pixbuf, &info);
342 else
343 ImageBufRGB16_drawMainCanvas_nearest(APP_DRAW->blendimg, pixbuf, &info);
344 }
345
346 /** (固定表示用) 範囲更新 */
347
DockCanvasViewArea_drawRect(DockCanvasViewArea * p,mBox * box)348 void DockCanvasViewArea_drawRect(DockCanvasViewArea *p,mBox *box)
349 {
350 mPixbuf *pixbuf;
351
352 pixbuf = mWidgetBeginDirectDraw(M_WIDGET(p));
353
354 if(pixbuf)
355 {
356 _draw_canvas(p, pixbuf, box);
357
358 mWidgetEndDirectDraw(M_WIDGET(p), pixbuf);
359
360 mWidgetUpdateBox_box(M_WIDGET(p), box);
361 }
362 }
363
364 /** 描画ハンドラ */
365
_draw_handle(mWidget * wg,mPixbuf * pixbuf)366 static void _draw_handle(mWidget *wg,mPixbuf *pixbuf)
367 {
368 DockCanvasViewArea *p = _CVAREA(wg);
369 mBox box;
370
371 box.x = box.y = 0;
372 box.w = wg->w;
373 box.h = wg->h;
374
375 _draw_canvas(p, pixbuf, &box);
376
377 //ルーペ十字線
378
379 if(_IS_LOUPE_MODE)
380 _draw_loupe_cross(p, p->canvasview, pixbuf, &box);
381 }
382
383
384 //==========================
385 // main
386 //==========================
387
388
389 /** 作成 */
390
DockCanvasViewArea_new(DockCanvasView * canvasview,mWidget * parent)391 DockCanvasViewArea *DockCanvasViewArea_new(DockCanvasView *canvasview,mWidget *parent)
392 {
393 DockCanvasViewArea *p;
394
395 p = (DockCanvasViewArea *)mWidgetNew(sizeof(DockCanvasViewArea), parent);
396
397 p->wg.event = _event_handle;
398 p->wg.draw = _draw_handle;
399 p->wg.onSize = _onsize_handle;
400
401 p->wg.fLayout = MLF_EXPAND_WH;
402 p->wg.fEventFilter |= MWIDGET_EVENTFILTER_POINTER;
403
404 p->canvasview = canvasview;
405
406 return p;
407 }
408