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  * NewImageDlg
22  *
23  * イメージ新規作成ダイアログ
24  *****************************************/
25 
26 #include "mDef.h"
27 #include "mStr.h"
28 #include "mWidget.h"
29 #include "mWindow.h"
30 #include "mDialog.h"
31 #include "mContainer.h"
32 #include "mLabel.h"
33 #include "mComboBox.h"
34 #include "mLineEdit.h"
35 #include "mListView.h"
36 #include "mTab.h"
37 #include "mEvent.h"
38 #include "mWidgetBuilder.h"
39 #include "mMessageBox.h"
40 #include "mTrans.h"
41 
42 #include "defMacros.h"
43 #include "defConfig.h"
44 
45 #include "trgroup.h"
46 
47 
48 //------------------------
49 
50 static const char *g_builder =
51 "ct#h:sep=12:lf=wh;"
52   "ct#v:lf=m;"
53     "ct#g3:sep=6,7;"
54       //幅
55       "lb:lf=rm:TR=0,0;"
56       "le#c:id=100:wlen=8;"
57       "sp;"
58       //高さ
59       "lb:lf=rm:TR=0,1;"
60       "le#c:id=101:wlen=8;"
61       "cb:id=102:t=px\tcm\tinch;"
62       //解像度
63       "lb:lf=rm:tr=1;"
64       "le#cs:id=103:wlen=6;"
65       "lb:lf=m:t=dpi;"
66     "-;"
67     //レイヤタイプ
68     "ct#h:sep=6:mg=t15;"
69       "lb:lf=m:tr=2;"
70       "cb:id=104;"
71     "-;"
72     //pxプレビュー
73     "lb#cB:id=105:lf=w:mg=t18;"
74   "-;"
75   //リスト
76   "ct#v:sep=4:lf=wh;"
77     "tab#ts:id=106:lf=w;"
78     "lv#,fv:id=107:lf=wh;"
79     "ct#h:sep=3:lf=r;"
80       "bt:id=108:tr=3;"
81       "bt:id=109:tr=4;";
82 
83 //------------------------
84 
85 #define TABNO_RECENT  0
86 #define TABNO_RECORD  1
87 #define TABNO_DEFINED 2
88 
89 #define WIDGETID_TOP 100
90 #define TRID_MES_LIMIT 1000
91 
92 enum
93 {
94 	WNO_WIDTH,
95 	WNO_HEIGHT,
96 	WNO_UNIT,
97 	WNO_DPI,
98 	WNO_LAYERTYPE,
99 	WNO_LABEL_PX,
100 	WNO_TAB,
101 	WNO_LIST,
102 	WNO_BTT_ADD,
103 	WNO_BTT_DEL,
104 
105 	WIDGET_NUM
106 };
107 
108 //------------------------
109 
110 typedef struct
111 {
112 	mWidget wg;
113 	mContainerData ct;
114 	mWindowData win;
115 	mDialogData dlg;
116 
117 	mWidget *widgets[WIDGET_NUM];
118 	int tabno;
119 }NewImageDlg;
120 
121 //------------------------
122 
123 
124 //========================
125 // 設定データ
126 //========================
127 
128 
129 /** 新規作成の履歴に追加 */
130 
_set_config_recent(ImageSizeData * src)131 static void _set_config_recent(ImageSizeData *src)
132 {
133 	ImageSizeData *dst = APP_CONF->imgsize_recent;
134 	int i,del;
135 
136 	del = CONFIG_IMAGESIZE_NUM - 1;
137 
138 	//同じ値が存在するか
139 
140 	for(i = 0; i < CONFIG_IMAGESIZE_NUM; i++)
141 	{
142 		if(dst[i].unit == 255) break;
143 
144 		if(src->unit == dst[i].unit && src->dpi == dst[i].dpi
145 			&& src->w == dst[i].w && src->h == dst[i].h)
146 		{
147 			del = i;
148 			break;
149 		}
150 	}
151 
152 	//挿入位置を空ける
153 
154 	for(i = del; i > 0; i--)
155 		dst[i] = dst[i - 1];
156 
157 	//先頭にセット
158 
159 	dst[0] = *src;
160 }
161 
162 
163 //========================
164 // リストにデータセット
165 //========================
166 
167 
168 /** 履歴/登録リストセット */
169 
_set_list_recent_record(mListView * lv,ImageSizeData * p)170 static void _set_list_recent_record(mListView *lv,ImageSizeData *p)
171 {
172 	mStr str = MSTR_INIT;
173 	int i;
174 
175 	for(i = 0; i < CONFIG_IMAGESIZE_NUM; i++, p++)
176 	{
177 		if(p->unit == 255) break;
178 
179 		if(p->unit == 0)
180 			//px
181 			mStrSetFormat(&str, "%d x %d px : %ddpi", p->w, p->h, p->dpi);
182 		else
183 		{
184 			//cm,inch
185 
186 			mStrSetFormat(&str, "%d.%02d x %d.%02d %s : %ddpi",
187 				p->w / 100, p->w % 100,
188 				p->h / 100, p->h % 100,
189 				(p->unit == 1)? "cm": "inch", p->dpi);
190 		}
191 
192 		mListViewAddItem_textparam(lv, str.buf, i);
193 	}
194 
195 	mStrFree(&str);
196 }
197 
198 /** 規定リストセット */
199 
_set_list_defined(mListView * lv)200 static void _set_list_defined(mListView *lv)
201 {
202 	int i,j;
203 	mStr str = MSTR_INIT;
204 	uint32_t num[2][7] = { //mm 単位
205 		{
206 			(594 << 16) | 841, (420 << 16) | 594, (297 << 16) | 420,
207 			(210 << 16) | 297, (148 << 16) | 210, (105 << 16) | 148,
208 			(74 << 16) | 105
209 		},
210 		{
211 			(728 << 16) | 1030, (515 << 16) | 728, (364 << 16) | 515,
212 			(257 << 16) | 364, (182 << 16) | 257, (128 << 16) | 182,
213 			(91 << 16) | 128
214 		}
215 	};
216 
217 	for(i = 0; i < 2; i++)
218 	{
219 		for(j = 0; j < 7; j++)
220 		{
221 			mStrSetFormat(&str, "%c%d : %d x %d mm",
222 				'A' + i, j + 1, num[i][j] >> 16, num[i][j] & 0xffff);
223 
224 			mListViewAddItem_textparam(lv, str.buf, num[i][j]);
225 		}
226 	}
227 
228 	mStrFree(&str);
229 }
230 
231 /** タブ番号からリストセット */
232 
_set_list(NewImageDlg * p,int no)233 static void _set_list(NewImageDlg *p,int no)
234 {
235 	mListView *lv;
236 
237 	lv = M_LISTVIEW(p->widgets[WNO_LIST]);
238 
239 	mListViewDeleteAllItem(lv);
240 
241 	if(no == TABNO_RECENT)
242 		_set_list_recent_record(lv, APP_CONF->imgsize_recent);
243 	else if(no == TABNO_RECORD)
244 		_set_list_recent_record(lv, APP_CONF->imgsize_record);
245 	else
246 		_set_list_defined(lv);
247 }
248 
249 
250 //========================
251 // sub
252 //========================
253 
254 
255 /** ウィジェットに幅・高さの値セット */
256 
_set_width_height(NewImageDlg * p,int wno,int size,int unit)257 static void _set_width_height(NewImageDlg *p,int wno,int size,int unit)
258 {
259 	if(unit == 0)
260 		mLineEditSetInt(M_LINEEDIT(p->widgets[wno]), size);
261 	else
262 		mLineEditSetDouble(M_LINEEDIT(p->widgets[wno]), size * 0.01, 2);
263 }
264 
265 /** 履歴/登録リストからウィジェットに値セット */
266 
_set_from_data(NewImageDlg * p,ImageSizeData * dat)267 static void _set_from_data(NewImageDlg *p,ImageSizeData *dat)
268 {
269 	mComboBoxSetSel_index(M_COMBOBOX(p->widgets[WNO_UNIT]), dat->unit);
270 
271 	_set_width_height(p, WNO_WIDTH, dat->w, dat->unit);
272 	_set_width_height(p, WNO_HEIGHT, dat->h, dat->unit);
273 
274 	mLineEditSetInt(M_LINEEDIT(p->widgets[WNO_DPI]), dat->dpi);
275 }
276 
277 /** リストボタンの有効/無効 */
278 
_enable_list_button(NewImageDlg * p)279 static void _enable_list_button(NewImageDlg *p)
280 {
281 	int f = (p->tabno == TABNO_RECORD);
282 
283 	mWidgetEnable(p->widgets[WNO_BTT_ADD], f);
284 	mWidgetEnable(p->widgets[WNO_BTT_DEL], f);
285 }
286 
287 /** 幅か高さ取得 */
288 
_get_width_height(NewImageDlg * p,int wno,int unit)289 static int _get_width_height(NewImageDlg *p,int wno,int unit)
290 {
291 	int n;
292 
293 	if(unit == 0)
294 		n = mLineEditGetInt(M_LINEEDIT(p->widgets[wno]));
295 	else
296 		n = mLineEditGetDouble(M_LINEEDIT(p->widgets[wno])) * 100 + 0.5;
297 
298 	return (n < 1)? 1: n;
299 }
300 
301 /** ウィジェットからデータ取得 */
302 
_get_data_from_widget(NewImageDlg * p,ImageSizeData * dat)303 static void _get_data_from_widget(NewImageDlg *p,ImageSizeData *dat)
304 {
305 	int n;
306 
307 	n = mComboBoxGetSelItemIndex(M_COMBOBOX(p->widgets[WNO_UNIT]));
308 
309 	dat->unit = n;
310 	dat->w = _get_width_height(p, WNO_WIDTH, n);
311 	dat->h = _get_width_height(p, WNO_HEIGHT, n);
312 	dat->dpi = mLineEditGetNum(M_LINEEDIT(p->widgets[WNO_DPI]));
313 }
314 
315 /** 登録リストに追加 */
316 
_add_record(NewImageDlg * p)317 static void _add_record(NewImageDlg *p)
318 {
319 	int i;
320 
321 	//空き位置取得
322 
323 	for(i = 0; i < CONFIG_IMAGESIZE_NUM; i++)
324 	{
325 		if(APP_CONF->imgsize_record[i].unit == 255) break;
326 	}
327 
328 	if(i == CONFIG_IMAGESIZE_NUM) return;
329 
330 	//セット
331 
332 	_get_data_from_widget(p, APP_CONF->imgsize_record + i);
333 
334 	if(i != CONFIG_IMAGESIZE_NUM - 1)
335 		APP_CONF->imgsize_record[i + 1].unit = 255;
336 
337 	//リスト
338 
339 	_set_list(p, p->tabno);
340 }
341 
342 /** 登録リストから削除 */
343 
_del_record(NewImageDlg * p)344 static void _del_record(NewImageDlg *p)
345 {
346 	mListView *lv;
347 	int i,no;
348 
349 	lv = M_LISTVIEW(p->widgets[WNO_LIST]);
350 
351 	no = mListViewGetItemIndex(lv, NULL);
352 	if(no == -1) return;
353 
354 	mListViewDeleteItem_sel(lv, NULL);
355 
356 	//データ削除
357 
358 	for(i = no; i < CONFIG_IMAGESIZE_NUM - 1; i++)
359 		APP_CONF->imgsize_record[i] = APP_CONF->imgsize_record[i + 1];
360 
361 	APP_CONF->imgsize_record[CONFIG_IMAGESIZE_NUM - 1].unit = 255;
362 }
363 
364 /** px サイズを取得 */
365 
_get_pxsize(mSize * size,ImageSizeData * dat)366 static void _get_pxsize(mSize *size,ImageSizeData *dat)
367 {
368 	double dw,dh;
369 	int w,h;
370 
371 	w = dat->w;
372 	h = dat->h;
373 
374 	if(dat->unit != 0)
375 	{
376 		dw = dat->w * 0.01 * dat->dpi;
377 		dh = dat->h * 0.01 * dat->dpi;
378 
379 		if(dat->unit == 1)
380 		{
381 			dw /= 2.54;
382 			dh /= 2.54;
383 		}
384 
385 		w = (int)(dw + 0.5);
386 		h = (int)(dh + 0.5);
387 
388 		if(w < 1) w = 1;
389 		if(h < 1) h = 1;
390 	}
391 
392 	size->w = w;
393 	size->h = h;
394 }
395 
396 /** px サイズをセット */
397 
_set_label_pxsize(NewImageDlg * p)398 static void _set_label_pxsize(NewImageDlg *p)
399 {
400 	ImageSizeData dat;
401 	mSize size;
402 	mStr str = MSTR_INIT;
403 
404 	_get_data_from_widget(p, &dat);
405 	_get_pxsize(&size, &dat);
406 
407 	mStrSetFormat(&str, "%d x %d px", size.w, size.h);
408 
409 	mLabelSetText(M_LABEL(p->widgets[WNO_LABEL_PX]), str.buf);
410 
411 	mStrFree(&str);
412 }
413 
414 
415 //========================
416 // イベント
417 //========================
418 
419 
420 /** OK 終了時 */
421 
_end_ok(NewImageDlg * p)422 static void _end_ok(NewImageDlg *p)
423 {
424 	ImageSizeData dat;
425 	mSize size;
426 
427 	_get_data_from_widget(p, &dat);
428 	_get_pxsize(&size, &dat);
429 
430 	//サイズ制限チェック
431 
432 	if(size.w > IMAGE_SIZE_MAX || size.h > IMAGE_SIZE_MAX)
433 	{
434 		mStr str = MSTR_INIT;
435 
436 		mStrSetFormat(&str, M_TR_T2(TRGROUP_DLG_NEWIMAGE, TRID_MES_LIMIT), IMAGE_SIZE_MAX);
437 
438 		mMessageBox(M_WINDOW(p), NULL, str.buf, MMESBOX_OK, MMESBOX_OK);
439 
440 		mStrFree(&str);
441 
442 		return;
443 	}
444 
445 	//履歴の先頭にセット
446 
447 	_set_config_recent(&dat);
448 
449 	mDialogEnd(M_DIALOG(p), TRUE);
450 }
451 
452 /** リスト項目選択時 */
453 
_change_list_sel(NewImageDlg * p,int param)454 static void _change_list_sel(NewImageDlg *p,int param)
455 {
456 	if(p->tabno == TABNO_RECENT)
457 		//履歴
458 		_set_from_data(p, APP_CONF->imgsize_recent + param);
459 	else if(p->tabno == TABNO_RECORD)
460 		//登録
461 		_set_from_data(p, APP_CONF->imgsize_record + param);
462 	else
463 	{
464 		//規定
465 
466 		mComboBoxSetSel_index(M_COMBOBOX(p->widgets[WNO_UNIT]), 1);
467 
468 		mLineEditSetDouble(M_LINEEDIT(p->widgets[WNO_WIDTH]), (param >> 16) * 0.1, 1);
469 		mLineEditSetDouble(M_LINEEDIT(p->widgets[WNO_HEIGHT]), (param & 0xffff) * 0.1, 1);
470 	}
471 
472 	//px
473 
474 	_set_label_pxsize(p);
475 }
476 
477 /** イベント */
478 
_event_handle(mWidget * wg,mEvent * ev)479 static int _event_handle(mWidget *wg,mEvent *ev)
480 {
481 	NewImageDlg *p = (NewImageDlg *)wg;
482 
483 	if(ev->type == MEVENT_NOTIFY)
484 	{
485 		switch(ev->notify.id)
486 		{
487 			//幅、高さ、DPI
488 			case WIDGETID_TOP + WNO_WIDTH:
489 			case WIDGETID_TOP + WNO_HEIGHT:
490 			case WIDGETID_TOP + WNO_DPI:
491 				if(ev->notify.type == MLINEEDIT_N_CHANGE)
492 					_set_label_pxsize(p);
493 				break;
494 			//単位
495 			case WIDGETID_TOP + WNO_UNIT:
496 				if(ev->notify.type == MCOMBOBOX_N_CHANGESEL)
497 					_set_label_pxsize(p);
498 				break;
499 
500 			//リスト項目選択時
501 			case WIDGETID_TOP + WNO_LIST:
502 				if(ev->notify.type == MLISTVIEW_N_CHANGE_FOCUS
503 					|| ev->notify.type == MLISTVIEW_N_CLICK_ON_FOCUS)
504 					_change_list_sel(p, (int)ev->notify.param2);
505 				break;
506 			//タブ変更時
507 			case WIDGETID_TOP + WNO_TAB:
508 				if(ev->notify.type == MTAB_N_CHANGESEL)
509 				{
510 					p->tabno = ev->notify.param1;
511 
512 					_enable_list_button(p);
513 
514 					_set_list(p, p->tabno);
515 				}
516 				break;
517 			//追加
518 			case WIDGETID_TOP + WNO_BTT_ADD:
519 				_add_record(p);
520 				break;
521 			//削除
522 			case WIDGETID_TOP + WNO_BTT_DEL:
523 				_del_record(p);
524 				break;
525 
526 			//OK
527 			case M_WID_OK:
528 				_end_ok(p);
529 				break;
530 			//CANCEL
531 			case M_WID_CANCEL:
532 				mDialogEnd(M_DIALOG(wg), FALSE);
533 				break;
534 		}
535 	}
536 
537 	return mDialogEventHandle(wg, ev);
538 }
539 
540 
541 //========================
542 // 作成
543 //========================
544 
545 
546 /** ウィジェット初期化 */
547 
_init_widget(NewImageDlg * p)548 static void _init_widget(NewImageDlg *p)
549 {
550 	int i;
551 	ImageSizeData dat;
552 
553 	for(i = 0; i < WIDGET_NUM; i++)
554 		p->widgets[i] = mWidgetFindByID(M_WIDGET(p), WIDGETID_TOP + i);
555 
556 	//解像度
557 
558 	mLineEditSetNumStatus(M_LINEEDIT(p->widgets[WNO_DPI]), 1, 9999, 0);
559 
560 	//レイヤタイプ
561 
562 	M_TR_G(TRGROUP_LAYERTYPE);
563 	mComboBoxAddTrItems(M_COMBOBOX(p->widgets[WNO_LAYERTYPE]), 4, 0, 0);
564 	M_TR_G(TRGROUP_DLG_NEWIMAGE);
565 
566 	mComboBoxSetWidthAuto(M_COMBOBOX(p->widgets[WNO_LAYERTYPE]));
567 	mComboBoxSetSel_index(M_COMBOBOX(p->widgets[WNO_LAYERTYPE]), 0);
568 
569 	//最新の履歴から値セット
570 
571 	if(APP_CONF->imgsize_recent[0].unit != 255)
572 		dat = APP_CONF->imgsize_recent[0];
573 	else
574 	{
575 		dat.unit = 0;
576 		dat.dpi = 300;
577 		dat.w = dat.h = 500;
578 	}
579 
580 	_set_from_data(p, &dat);
581 
582 	//px
583 
584 	_set_label_pxsize(p);
585 
586 	//----------
587 
588 	//タブ
589 
590 	for(i = 0; i < 3; i++)
591 		mTabAddItemText(M_TAB(p->widgets[WNO_TAB]), M_TR_T(100 + i));
592 
593 	mTabSetSel_index(M_TAB(p->widgets[WNO_TAB]), TABNO_RECENT);
594 
595 	//リスト
596 
597 	_set_list(p, TABNO_RECENT);
598 
599 	mWidgetSetInitSize_fontHeight(p->widgets[WNO_LIST], 16, 12);
600 
601 	//ボタン無効
602 
603 	_enable_list_button(p);
604 }
605 
606 /** 作成 */
607 
_create_dlg(mWindow * owner)608 static NewImageDlg *_create_dlg(mWindow *owner)
609 {
610 	NewImageDlg *p;
611 
612 	//作成
613 
614 	p = (NewImageDlg *)mDialogNew(sizeof(NewImageDlg), owner, MWINDOW_S_DIALOG_NORMAL);
615 	if(!p) return NULL;
616 
617 	p->wg.event = _event_handle;
618 
619 	//
620 
621 	M_TR_G(TRGROUP_DLG_NEWIMAGE);
622 
623 	mContainerSetPadding_one(M_CONTAINER(p), 8);
624 	p->ct.sepW = 15;
625 
626 	mWindowSetTitle(M_WINDOW(p), M_TR_T(0));
627 
628 	//ウィジェット
629 
630 	mWidgetBuilderCreateFromText(M_WIDGET(p), g_builder);
631 
632 	_init_widget(p);
633 
634 	//OK/Cancel
635 
636 	mContainerCreateOkCancelButton(M_WIDGET(p));
637 
638 	return p;
639 }
640 
641 
642 //=====================
643 
644 
645 /** 新規作成ダイアログ実行 */
646 
NewImageDialog_run(mWindow * owner,mSize * size,int * dpi,int * layertype)647 mBool NewImageDialog_run(mWindow *owner,mSize *size,int *dpi,int *layertype)
648 {
649 	NewImageDlg *p;
650 	mBool ret;
651 
652 	p = _create_dlg(owner);
653 	if(!p) return FALSE;
654 
655 	mWindowMoveResizeShow_hintSize(M_WINDOW(p));
656 
657 	ret = mDialogRun(M_DIALOG(p), FALSE);
658 
659 	if(ret)
660 	{
661 		_get_pxsize(size, APP_CONF->imgsize_recent);
662 
663 		*dpi = APP_CONF->imgsize_recent[0].dpi;
664 
665 		*layertype = mComboBoxGetSelItemIndex(M_COMBOBOX(p->widgets[WNO_LAYERTYPE]));
666 	}
667 
668 	mWidgetDestroy(M_WIDGET(p));
669 
670 	return ret;
671 }
672