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 = &param;
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