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  * MainWindow
22  *
23  * コマンド関連
24  *****************************************/
25 
26 #include "mDef.h"
27 #include "mGui.h"
28 #include "mStr.h"
29 #include "mWidget.h"
30 #include "mIconButtons.h"
31 #include "mDockWidget.h"
32 #include "mSysDialog.h"
33 #include "mMessageBox.h"
34 #include "mTrans.h"
35 
36 #include "defConfig.h"
37 #include "defDraw.h"
38 #include "defWidgets.h"
39 #include "AppErr.h"
40 #include "defCanvasKeyID.h"
41 
42 #include "TileImage.h"
43 #include "LayerItem.h"
44 #include "BrushList.h"
45 #include "Undo.h"
46 #include "AppResource.h"
47 
48 #include "defMainWindow.h"
49 #include "MainWindow.h"
50 #include "MainWindow_pv.h"
51 #include "MainWinCanvas.h"
52 #include "StatusBar.h"
53 #include "DockObject.h"
54 #include "Docks_external.h"
55 #include "CanvasDialogs.h"
56 #include "EnvOptDlg.h"
57 #include "PopupThread.h"
58 
59 #include "draw_main.h"
60 #include "draw_layer.h"
61 #include "draw_select.h"
62 #include "draw_calc.h"
63 
64 #include "trgroup.h"
65 #include "AppErr.h"
66 
67 
68 //--------------
69 
70 mBool PanelLayoutDlg_run(mWindow *owner);
71 
72 //--------------
73 
74 
75 //=======================
76 // 表示関連
77 //=======================
78 
79 
80 /** 各ペインをレイアウト */
81 
MainWindow_pane_layout(MainWindow * p)82 void MainWindow_pane_layout(MainWindow *p)
83 {
84 	char *pc;
85 	mWidget *wg,*next;
86 	int i,no,pane_have[3],spno,pane_cnt;
87 
88 	//各ペイン、格納するパネルがあるか
89 
90 	mMemzero(pane_have, sizeof(int) * 3);
91 
92 	for(i = 0; i < DOCKWIDGET_NUM; i++)
93 	{
94 		no = DockObject_getPaneNo_fromNo(i);
95 		pane_have[no] = 1;
96 	}
97 
98 	//リンクを外す
99 
100 	for(wg = p->ct_main->first; wg; wg = next)
101 	{
102 		next = wg->next;
103 		mWidgetTreeRemove(wg);
104 	}
105 
106 	//再リンク
107 
108 	spno = 0;
109 	pane_cnt = 0;
110 
111 	for(pc = APP_CONF->pane_layout; *pc; pc++)
112 	{
113 		no = *pc - '0';
114 
115 		//パネルがないペインは除外
116 
117 		if(no == 0 || pane_have[no - 1])
118 		{
119 			//キャンバス/ペイン
120 
121 			wg = (no == 0)? (mWidget *)APP_WIDGETS->canvas: APP_WIDGETS->pane[no - 1];
122 
123 			mWidgetTreeAppend(wg, p->ct_main);
124 
125 			if(no != 0) pane_cnt++;
126 
127 			//スプリッター
128 
129 			if(spno < 3)
130 				mWidgetTreeAppend(p->splitter[spno++], p->ct_main);
131 		}
132 	}
133 
134 	//非表示のペインがある場合、最後に余分なスプリッターが付くので、外す
135 
136 	if(pane_cnt != 3)
137 		mWidgetTreeRemove(p->ct_main->last);
138 }
139 
140 /** ペインとスプリッターの表示反転 */
141 
MainWindow_toggle_show_pane_splitter(MainWindow * p)142 void MainWindow_toggle_show_pane_splitter(MainWindow *p)
143 {
144 	int i;
145 
146 	//切り離されているものは除外
147 
148 	for(i = 0; i < 3; i++)
149 	{
150 		if(APP_WIDGETS->pane[i]->parent)
151 			mWidgetShow(APP_WIDGETS->pane[i], -1);
152 
153 		if(p->splitter[i]->parent)
154 			mWidgetShow(p->splitter[i], -1);
155 	}
156 }
157 
158 /** パネルすべてを表示/非表示 */
159 
MainWindow_cmd_show_panel_all(MainWindow * p)160 void MainWindow_cmd_show_panel_all(MainWindow *p)
161 {
162 	int i;
163 
164 	//各パレット表示状態反転
165 
166 	for(i = 0; i < DOCKWIDGET_NUM; i++)
167 	{
168 		if(APP_WIDGETS->dockobj[i])
169 			mDockWidgetSetVisible(APP_WIDGETS->dockobj[i]->dockwg, -1);
170 	}
171 
172 	//ペインとスプリッターの表示反転
173 
174 	MainWindow_toggle_show_pane_splitter(p);
175 
176 	mWidgetReLayout(M_WIDGET(p));
177 
178 	//
179 
180 	APP_CONF->fView ^= CONFIG_VIEW_F_DOCKS;
181 }
182 
183 /** 各パネルの表示状態を反転 */
184 
MainWindow_cmd_show_panel_toggle(int no)185 void MainWindow_cmd_show_panel_toggle(int no)
186 {
187 	if(APP_CONF->fView & CONFIG_VIEW_F_DOCKS)
188 		mDockWidgetShow(APP_WIDGETS->dockobj[no]->dockwg, -1);
189 }
190 
191 
192 //=======================
193 // ダイアログ
194 //=======================
195 
196 
197 /** DPI 値変更 */
198 
MainWindow_cmd_changeDPI(MainWindow * p)199 void MainWindow_cmd_changeDPI(MainWindow *p)
200 {
201 	int n;
202 
203 	M_TR_G(TRGROUP_DLG_CHANGE_DPI);
204 
205 	n = APP_DRAW->imgdpi;
206 
207 	if(mSysDlgInputNum(M_WINDOW(p), M_TR_T(0), M_TR_T(1), &n,
208 		1, 10000, MSYSDLG_INPUTNUM_F_DEFAULT))
209 	{
210 		APP_DRAW->imgdpi = n;
211 
212 		StatusBar_setImageInfo();
213 	}
214 }
215 
216 /** 選択範囲の拡張/縮小 */
217 
MainWindow_cmd_selectExpand(MainWindow * p)218 void MainWindow_cmd_selectExpand(MainWindow *p)
219 {
220 	int n;
221 
222 	//選択範囲なし
223 
224 	if(!drawSel_isHave()) return;
225 
226 	//
227 
228 	M_TR_G(TRGROUP_DLG_SELECT_EXPAND);
229 
230 	n = 1;
231 
232 	if(mSysDlgInputNum(M_WINDOW(p), M_TR_T(0), M_TR_T(1), &n,
233 		-500, 500, MSYSDLG_INPUTNUM_F_DEFAULT))
234 	{
235 		if(n != 0)
236 			drawSel_expand(APP_DRAW, n);
237 	}
238 }
239 
240 /** マスク類の状態をチェック */
241 
_checkmasks_set(mStr * str,int trid,int on)242 static void _checkmasks_set(mStr *str,int trid,int on)
243 {
244 	mStrAppendFormat(str, "[%c]  %s\n", (on)? 'O':'-', M_TR_T(trid));
245 }
246 
MainWindow_cmd_checkMaskState(MainWindow * p)247 void MainWindow_cmd_checkMaskState(MainWindow *p)
248 {
249 	mStr str = MSTR_INIT;
250 	int i,lf;
251 
252 	M_TR_G(TRGROUP_CHECK_MASKS);
253 
254 	//レイヤ名
255 
256 	mStrSetFormat(&str, "< %s >\n\n", APP_DRAW->curlayer->name);
257 
258 	//選択範囲
259 
260 	_checkmasks_set(&str, 1, drawSel_isHave());
261 
262 	//レイヤ (ロック、下レイヤマスク、アルファマスク)
263 
264 	lf = LayerItem_checkMasks(APP_DRAW->curlayer);
265 
266 	for(i = 0; i < 3; i++)
267 		_checkmasks_set(&str, i + 2, lf & (1<<i));
268 
269 	//マスクレイヤ
270 
271 	_checkmasks_set(&str, 5, (APP_DRAW->masklayer != 0));
272 
273 	if(APP_DRAW->masklayer)
274 		mStrAppendFormat(&str, "    < %s >\n", APP_DRAW->masklayer->name);
275 
276 	//色マスク
277 
278 	_checkmasks_set(&str, 6, APP_DRAW->col.colmask_type);
279 
280 	//
281 
282 	mMessageBox(M_WINDOW(p), M_TR_T(0), str.buf, MMESBOX_OK, MMESBOX_OK);
283 
284 	mStrFree(&str);
285 }
286 
287 /** 環境設定 */
288 
MainWindow_cmd_envoption(MainWindow * p)289 void MainWindow_cmd_envoption(MainWindow *p)
290 {
291 	int f;
292 
293 	f = EnvOptionDlg_run(M_WINDOW(p));
294 
295 	//テーマ
296 
297 	if(f & ENVOPTDLG_F_THEME)
298 	{
299 		mAppLoadThemeFile(APP_CONF->strThemeFile.buf);
300 
301 		DockColor_changeTheme();
302 		DockColorPalette_changeTheme();
303 		DockColorWheel_changeTheme();
304 	}
305 
306 	//キャンバス
307 
308 	if(f & ENVOPTDLG_F_UPDATE_ALL)
309 		//イメージ全体変更 (チェック柄背景色変更)
310 		/* キャンバス背景色も変わっている場合あり */
311 		drawUpdate_all();
312 	else if(f & ENVOPTDLG_F_UPDATE_CANVAS)
313 	{
314 		//キャンバス背景色変更
315 
316 		drawUpdate_canvasArea();
317 		DockCanvasView_update();
318 	}
319 
320 	//描画カーソル変更
321 
322 	if(f & ENVOPTDLG_F_CURSOR)
323 		MainWinCanvasArea_changeDrawCursor();
324 
325 	//ツールバーボタン
326 
327 	if(f & ENVOPTDLG_F_TOOLBAR_BTT)
328 		MainWindow_createToolBar(p, FALSE);
329 
330 	//アイコンサイズ
331 
332 	if(f & ENVOPTDLG_F_ICONSIZE)
333 	{
334 		//ツールバー
335 		mIconButtonsReplaceImageList(M_ICONBUTTONS(p->toolbar),
336 			AppResource_loadIconImage("toolbar.png", APP_CONF->iconsize_toolbar));
337 
338 		//dock
339 		DockTool_changeIconSize();
340 		DockLayer_changeIconSize();
341 		DockCanvasView_changeIconSize();
342 		DockImageViewer_changeIconSize();
343 
344 		mWidgetReLayout(M_WIDGET(p));
345 	}
346 }
347 
348 /** パネル配置設定 */
349 
MainWindow_cmd_panelLayout(MainWindow * p)350 void MainWindow_cmd_panelLayout(MainWindow *p)
351 {
352 	if(PanelLayoutDlg_run(M_WINDOW(p)))
353 	{
354 		//ペインの再配置
355 
356 		MainWindow_pane_layout(p);
357 
358 		//ペイン内のパネルを再配置
359 
360 		DockObjects_relocate();
361 
362 		//レイアウト
363 
364 		mWidgetReLayout(p->ct_main);
365 	}
366 }
367 
368 /** キャンバスサイズ変更 */
369 
MainWindow_cmd_resizeCanvas(MainWindow * p)370 void MainWindow_cmd_resizeCanvas(MainWindow *p)
371 {
372 	CanvasResizeInfo info;
373 	int sw,sh,topx,topy,n;
374 
375 	sw = APP_DRAW->imgw;
376 	sh = APP_DRAW->imgh;
377 
378 	//ダイアログ
379 
380 	info.w = sw;
381 	info.h = sh;
382 
383 	if(!CanvasResizeDlg_run(M_WINDOW(p), &info))
384 		return;
385 
386 	//サイズ変更なし
387 
388 	if(info.w == sw && info.h == sh) return;
389 
390 	//左上位置
391 
392 	n = info.align % 3;
393 
394 	if(n == 0) topx = 0;
395 	else if(n == 1) topx = (info.w - sw) >> 1;
396 	else topx = info.w - sw;
397 
398 	n = info.align / 3;
399 
400 	if(n == 0) topy = 0;
401 	else if(n == 1) topy = (info.h - sh) >> 1;
402 	else topy = info.h - sh;
403 
404 	//実行
405 
406 	if(!drawImage_resizeCanvas(APP_DRAW, info.w, info.h, topx, topy, info.crop))
407 		MainWindow_apperr(APPERR_ALLOC, NULL);
408 
409 	MainWindow_updateNewCanvas(p, NULL);
410 }
411 
412 /** キャンバス拡大縮小 */
413 
MainWindow_cmd_scaleCanvas(MainWindow * p)414 void MainWindow_cmd_scaleCanvas(MainWindow *p)
415 {
416 	CanvasScaleInfo info;
417 
418 	//ダイアログ
419 
420 	info.w = APP_DRAW->imgw;
421 	info.h = APP_DRAW->imgh;
422 	info.dpi = APP_DRAW->imgdpi;
423 	info.have_dpi = TRUE;
424 
425 	if(!CanvasScaleDlg_run(M_WINDOW(p), &info))
426 		return;
427 
428 	//サイズ変更なし
429 
430 	if(info.w == APP_DRAW->imgw && info.h == APP_DRAW->imgh)
431 		return;
432 
433 	//実行
434 
435 	if(!drawImage_scaleCanvas(APP_DRAW, info.w, info.h, info.dpi, info.type))
436 		MainWindow_apperr(APPERR_ALLOC, NULL);
437 
438 	MainWindow_updateNewCanvas(p, NULL);
439 }
440 
441 
442 //==========================
443 
444 
445 /** アンドゥ/リドゥ */
446 
MainWindow_undoredo(MainWindow * p,mBool redo)447 void MainWindow_undoredo(MainWindow *p,mBool redo)
448 {
449 	UndoUpdateInfo info;
450 	mBool ret;
451 
452 	if(!Undo_isHave(redo)) return;
453 
454 	//実行 (ret は更新を行うかどうか。失敗したかではない)
455 
456 	MainWinCanvasArea_setCursor_wait();
457 
458 	ret = Undo_runUndoRedo(redo, &info);
459 
460 	MainWinCanvasArea_restoreCursor();
461 
462 	if(!ret) return;
463 
464 	//更新
465 
466 	switch(info.type)
467 	{
468 		//イメージ範囲 (単体レイヤ)
469 		case UNDO_UPDATE_RECT:
470 			drawUpdate_rect_imgcanvas_canvasview_fromRect(APP_DRAW, &info.rc);
471 			DockLayer_update_layer(info.layer);
472 			break;
473 		//イメージ範囲 + レイヤ一覧
474 		case UNDO_UPDATE_RECT_AND_LAYERLIST:
475 			drawUpdate_rect_imgcanvas_canvasview_fromRect(APP_DRAW, &info.rc);
476 			DockLayer_update_all();
477 			break;
478 		//イメージ範囲 + レイヤ一覧の指定レイヤのみ
479 		case UNDO_UPDATE_RECT_AND_LAYERLIST_ONE:
480 			drawUpdate_rect_imgcanvas_canvasview_fromRect(APP_DRAW, &info.rc);
481 			DockLayer_update_layer(info.layer);
482 			break;
483 		//イメージ範囲 + レイヤ一覧の指定レイヤとその下レイヤ (下レイヤに移す時)
484 		case UNDO_UPDATE_RECT_AND_LAYERLIST_DOUBLE:
485 			drawUpdate_rect_imgcanvas_canvasview_fromRect(APP_DRAW, &info.rc);
486 
487 			DockLayer_update_layer(info.layer);
488 			DockLayer_update_layer(LayerItem_getNext(info.layer));
489 			break;
490 		//レイヤ一覧全体
491 		case UNDO_UPDATE_LAYERLIST:
492 			DockLayer_update_all();
493 			break;
494 		//レイヤ一覧の指定レイヤのみ
495 		case UNDO_UPDATE_LAYERLIST_ONE:
496 			DockLayer_update_layer(info.layer);
497 			break;
498 		//すべて + レイヤ一覧
499 		case UNDO_UPDATE_ALL_AND_LAYERLIST:
500 			drawUpdate_all_layer();
501 			break;
502 		//キャンバスサイズ変更
503 		case UNDO_UPDATE_CANVAS_RESIZE:
504 			drawImage_changeImageSize(APP_DRAW, info.rc.x1, info.rc.y1);
505 			MainWindow_updateNewCanvas(p, NULL);
506 			break;
507 	}
508 }
509 
510 /** キャンバスキー押し時 */
511 
MainWindow_onCanvasKeyCommand(int id)512 void MainWindow_onCanvasKeyCommand(int id)
513 {
514 	DrawData *p = APP_DRAW;
515 
516 	if(id == 0) return;
517 
518 	if(id >= CANVASKEYID_CMD_TOOL && id < CANVASKEYID_CMD_TOOL + TOOL_NUM)
519 	{
520 		//ツール変更
521 
522 		drawTool_setTool(p, id - CANVASKEYID_CMD_TOOL);
523 	}
524 	else if(id >= CANVASKEYID_CMD_DRAWTYPE && id < CANVASKEYID_CMD_DRAWTYPE + TOOLSUB_DRAW_NUM)
525 	{
526 		//描画タイプ変更 (ブラシツール時)
527 
528 		if(p->tool.no == TOOL_BRUSH)
529 			drawTool_setToolSubtype(p, id - CANVASKEYID_CMD_DRAWTYPE);
530 	}
531 	else if(id >= CANVASKEYID_CMD_OTHER && id < CANVASKEYID_CMD_OTHER + CANVASKEY_CMD_OTHER_NUM)
532 	{
533 		//他コマンド
534 
535 		id -= CANVASKEYID_CMD_OTHER;
536 
537 		switch(id)
538 		{
539 			//一つ上/下のレイヤを選択
540 			case 0:
541 			case 1:
542 				drawLayer_currentSelUpDown(p, (id == 0));
543 				break;
544 			//カレントレイヤ表示/非表示
545 			case 2:
546 				drawLayer_revVisible(p, p->curlayer);
547 				DockLayer_update_curlayer(FALSE);
548 				break;
549 			//描画色/背景色切り替え
550 			case 3:
551 				drawColor_toggleDrawCol(p);
552 				DockColor_changeDrawColor();
553 				break;
554 			//一段階拡大/縮小
555 			case 4:
556 			case 5:
557 				drawCanvas_zoomStep(APP_DRAW, (id == 4));
558 				break;
559 			//キャンバス回転リセット
560 			case 6:
561 				drawCanvas_setZoomAndAngle(p, 0, 0, 2, FALSE);
562 				break;
563 			//元に戻す/やり直す
564 			case 7:
565 			case 8:
566 				MainWindow_undoredo(APP_WIDGETS->mainwin, (id == 8));
567 				break;
568 			//直前のブラシと切り替え
569 			case 9:
570 				if(BrushList_toggleLastItem())
571 					DockBrush_changeBrushSel();
572 				break;
573 			//一つ前/次のブラシ選択
574 			case 10:
575 			case 11:
576 				if(BrushList_moveSelect((id == 11)))
577 					DockBrush_changeBrushSel();
578 				break;
579 		}
580 	}
581 }
582 
583 
584 //=================================
585 // 選択範囲内イメージをPNG出力
586 //=================================
587 
588 
589 typedef struct
590 {
591 	char *filename;
592 	mRect rc;
593 }_thdata_selimgpng;
594 
595 
596 /** スレッド */
597 
_thread_seloutputpng(mPopupProgress * prog,void * data)598 static int _thread_seloutputpng(mPopupProgress *prog,void *data)
599 {
600 	_thdata_selimgpng *p = (_thdata_selimgpng *)data;
601 
602 	return TileImage_savePNG_select_rgba(
603 		APP_DRAW->curlayer->img, APP_DRAW->tileimgSel,
604 		p->filename, APP_DRAW->imgdpi, &p->rc, prog);
605 }
606 
607 /** 選択範囲内イメージをPNG出力 */
608 
MainWindow_cmd_selectOutputPNG(MainWindow * p)609 void MainWindow_cmd_selectOutputPNG(MainWindow *p)
610 {
611 	mStr str = MSTR_INIT;
612 	mRect rc;
613 	_thdata_selimgpng dat;
614 
615 	//選択範囲なし、またはフォルダレイヤの場合
616 
617 	if(!drawSel_isHave()
618 		|| LAYERITEM_IS_FOLDER(APP_DRAW->curlayer))
619 		return;
620 
621 	//範囲 (キャンバス範囲外は除く)
622 
623 	TileImage_getSelectHaveRect_real(APP_DRAW->tileimgSel, &rc);
624 
625 	if(!drawCalc_clipImageRect(APP_DRAW, &rc))
626 		return;
627 
628 	//ファイル名取得
629 
630 	if(mSysDlgSaveFile(M_WINDOW(p),
631 		"PNG file (*.png)\t*.png",
632 		0, APP_CONF->strSelectFileDir.buf, 0, &str, NULL))
633 	{
634 		//拡張子
635 
636 		mStrPathSetExt(&str, "png");
637 
638 		//ディレクトリ記録
639 
640 		mStrPathGetDir(&APP_CONF->strSelectFileDir, str.buf);
641 
642 		//保存
643 
644 		dat.filename = str.buf;
645 		dat.rc = rc;
646 
647 		if(PopupThread_run(&dat, _thread_seloutputpng) != 1)
648 			MainWindow_apperr(APPERR_FAILED, NULL);
649 	}
650 
651 	mStrFree(&str);
652 }
653