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