1%%	options
2copyright owner	=	Dirk Krause
3copyright year	=	2019-xxxx
4SPDX-License-Identifier:	BSD-3-Clause
5
6
7
8%%	wx-gui
9
10type			= 	frame
11contents		=	mainSizer
12icon			=	wximgsz_icon
13status bar		=	1 sTexts[8]
14menu bar		=	mbMain
15
16[wxMenuBar mbMain]
17contents		=	menuFile
18contents		=	menuHelp
19
20[wxMenu menuFile]
21text			=	sTexts[0]
22contents		=	miFileOpen
23contents		=	miFileExit
24
25[wxMenuItem miFileOpen]
26id				=	wxID_OPEN
27text			=	sTexts[40]
28tip				=	sTexts[41]
29
30[wxMenuItem miFileExit]
31id				=	wxID_EXIT
32text			=	sTexts[1]
33tip				=	sTexts[2]
34
35[wxMenu menuHelp]
36text			=	sTexts[3]
37contents		=	miHelpAbout
38contents		=	miHelpContents
39
40[wxMenuItem miHelpAbout]
41id				=	WximgszFrame::ID_HELP_ABOUT
42text			=	sTexts[4]
43tip				=	sTexts[5]
44
45[wxMenuItem miHelpContents]
46id				=	WximgszFrame::ID_HELP_TOC
47text			=	sTexts[6]
48tip				=	sTexts[7]
49
50[wxBoxSizer mainSizer]
51direction		=	horizontal
52contents		=	$space(10)
53contents		=	verticalSizer
54contents		=	$space(10)
55
56[wxBoxSizer verticalSizer]
57direction		=	vertical
58grow			=	yes
59proportion		=	1
60contents		=	$space(10)
61contents		=	contentsSizer
62contents		=	$space(10)
63
64[wxBoxSizer		contentsSizer]
65direction		=	horizontal
66grow			=	yes
67proportion		=	1
68contents		=	inputSizer
69contents		=	$space(20,20)
70contents		=	runButtonSizer
71contents		=	$space(20,20)
72contents		=	resultSizer
73
74[wxGridBagSizer		inputSizer]
75grid			=	5 5
76contents		=	lInput				 0	 0	 1	 2	left
77contents		=	lInputWidth			+1	 0	 1	 1	right	centered-y
78contents		=	spInputWidth		 .	+1	 1	 1			centered-y
79contents		=	lInputHeight		+1	 0	 1	 1	right	centered-y
80contents		=	spInputHeight		 .	+1	 1	 1			centered-y
81contents		=	$space(10)			+1	 0	 1	 1
82contents		=	lChange				+1	 0	 1	 2	left
83contents		=	lOperation			+1	 0	 1	 1	right	centered-y
84contents		=	cbOperation			 .	+1	 1	 1	left	centered-y
85contents		=	lOperationMin		+1	 0	 1	 1	right	centered-y
86contents		=	spOperationMin		 .	+1	 1	 1	left	centered-y
87contents		=	lOperationMax		+1	 0	 1	 1	right	centered-y
88contents		=	spOperationMax		 .	+1	 1	 1	left	centered-y
89
90[wxBoxSizer			runButtonSizer]
91grow			=	yes
92direction		=	vertical
93contents		=	$stretch(10)
94contents		=	bRun
95contents		=	$stretch(10)
96
97[wxBoxSizer			resultSizer]
98grow			=	yes
99proportion		=	1
100direction		=	vertical
101contents		=	lResults	left
102contents		=	tResult		left
103
104[wxStaticText	lInput]
105text			=	sTexts[13]
106
107[wxStaticText	lResults]
108text			=	sTexts[28]
109
110[wxStaticText	lInputWidth]
111text			=	sTexts[14]
112
113[wxStaticText	lInputHeight]
114text			=	sTexts[15]
115
116[wxSpinCtrl		spInputWidth]
117value			=	1
118range			=	1	65535
119tip				=	sTexts[16]
120
121[wxBitmapButton		bRun]
122tip				=	sTexts[29]
123bitmap			=	xpm_run_conversion
124id				=	ID_BUTTON_RUN
125
126[wxGrid				tResult]
127text style		=	readonly
128column head		=	sTexts[30]
129column head		=	sTexts[31]
130column head		=	sTexts[32]
131column head		=	sTexts[33]
132rows			=	4
133# minimum size	=	150 100
134grow			=	true
135proportion		=	1
136
137[wxSpinCtrl		spInputHeight]
138value			=	1
139range			=	1	65535
140tip				=	sTexts[17]
141
142[wxStaticText	lChange]
143text			=	sTexts[18]
144
145[wxStaticText	lOperation]
146text			=	sTexts[19]
147
148[wxChoice		cbOperation]
149id				=	ID_CHOICE_OP
150choices			=	3 saOperation
151tip				=	sTexts[20]
152proportion		=	1
153
154[wxStaticText	lOperationMin]
155text			=	sTexts[24]
156
157[wxSpinCtrl		spOperationMin]
158value			=	1
159range			=	1	65535
160tip				=	sTexts[26]
161
162[wxStaticText	lOperationMax]
163text			=	sTexts[25]
164
165[wxSpinCtrl		spOperationMax]
166value			=	1
167range			=	1	65535
168tip				=	sTexts[27]
169
170%%	header start
171
172
173
174%%	class start
175class WximgszFrame : public Dk4WxFrame
176{
177	private:
178
179		/**	Event table for frame.
180		*/
181		DECLARE_EVENT_TABLE()
182
183	protected:
184
185		/**	Auto start controller.
186		*/
187		Dk4WxAutostartController	cas;
188
189		/**	Dark red text colour for group labels.
190		*/
191		wxColour				 cLabelRed;
192
193		/**	Light red background for table cells.
194		*/
195		wxColour				 cRed;
196
197		/**	Light green background for table cells.
198		*/
199		wxColour				 cGreen;
200
201		/** Yellow background for table cells.
202		*/
203		wxColour				 cYellow;
204
205		/**	Text colour for table cells.
206		*/
207		wxColour				 cBlack;
208
209		/**	Image file name to process on autostart.
210		*/
211		wxString				 sImageFileName;
212
213		/**	Directory previous image file was read from.
214		*/
215		wxString				 sDirectory;
216
217		/**	Localized texts.
218		*/
219		wxChar const * const	*sTexts;
220
221		/**	Non-localized texts.
222		*/
223		wxChar const * const	*sNlWx;
224
225		/**	Non-localized texts.
226		*/
227		dkChar const * const	*sNlDk;
228
229		/*	__CHANGE__ 011:	Add further member variables.
230		*/
231
232		/**	Maximum number of items in grid.
233		*/
234		int						 maxpass;
235
236		/**	Have image file name.
237		*/
238		bool					 bImageFileName;
239
240		/**	Flag: Application should still respond to onidle.
241		*/
242		bool					 bActive;
243
244		/**	Process the file name which was specified on command line.
245		*/
246		void
247		ProcessSpecifiedFileName(void);
248
249%%	class end
250
251	public:
252
253		/**	Window IDs used in main window (frame).
254		*/
255		enum {
256			ID_FRAME	= (wxID_HIGHEST + 1),	/**< Frame. */
257			ID_HELP_ABOUT ,		/**< Open information dialog box. */
258			ID_HELP_TOC ,		/**< Open help table of contents. */
259			ID_BUTTON_RUN ,		/**< Button to run calculation. */
260			ID_CHOICE_OP ,		/**< Choice box for operation. */
261		};
262
263		/**	Maximum number of passes.
264		*/
265		enum {
266			MAXPASS = 2000
267		};
268
269		/**	Maximum image dimension adjustable in spin control.
270		*/
271		enum {
272			/**	Maximum image dimension adjustable in spin control.
273			*/
274			MAXIMGDIM = 65535
275		};
276
277		/**	Constructor.
278			@param	wxid				Window ID.
279			@param	applicationHelper	Application helper object.
280			@param	hc					Help controller for online help.
281			@param	argc				Number of command line arguments.
282			@param	argv				Command line arguments array.
283			@param	localizedTexts		Localized wxChar texts.
284			@param	nlWx				Non-localized wxChar texts.
285			@param	nlDk				Non-localized dkChar texts.
286		*/
287		WximgszFrame(
288			int						  wxid,
289			Dk4WxApplicationHelper	 *applicationHelper,
290			Dk4WxHelpController		 *hc,
291			int			 			  argc,
292			wxChar					**argv,
293			wxChar const * const	 *localizedTexts,
294			wxChar const * const	 *nlWx,
295			dkChar const * const	 *nlDk
296		);
297
298		/**	Destructor.
299		*/
300		~WximgszFrame();
301
302		/**	Check whether we can close the window.
303			@param	isLast	Flag: Last main window to close.
304		*/
305		bool
306		CanClose(bool isFinal);
307
308		/**	Handler for File/Open.
309			@param	event	Event to process.
310		*/
311		void
312		OnFileOpen(wxCommandEvent & event);
313
314		/**	Handler for File/Exit.
315			@param	event	Event to process.
316		*/
317		void
318		OnQuit(wxCommandEvent & event);
319
320		/**	Handler for Help/About.
321			@param	event	Event to process.
322		*/
323		void
324		OnAbout(wxCommandEvent & event);
325
326		/**	Handler for Help/Contents.
327			@param	event	Event to process.
328		*/
329		void
330		OnHelpContents(wxCommandEvent & event);
331
332		/**	Do the calculations and update table.
333		*/
334		void
335		Calculations(void);
336
337		/**	Handler for Run button.
338			@param	event	Event to process.
339		*/
340		void
341		OnButtonRun(wxCommandEvent & event);
342
343		/**	Handler for operations choice box.
344			@param	event	Event to process.
345		*/
346		void
347		OnChoiceOperation(wxCommandEvent & event);
348
349		/*	__CHANGE__ 008:	Remove OnIdle if no idle processing required.
350		*/
351		/**	Handler for idle events.
352		*/
353		void
354		OnIdle(wxIdleEvent & event);
355
356		/*	__CHANGE__ 017:	Event handlers for further events.
357		*/
358
359		/*	__CHANGE__ 014:	Add further methods.
360		*/
361
362		/**	Activate or deactivate idle processing.
363			@param	fl	Flag to activate/deactivate.
364		*/
365		void
366		ActivateIdleProcessing(bool fl = true);
367
368};
369
370%%	header end
371
372
373/* vim: set ai sw=4 ts=4 : */
374%%	module start
375
376#include <wximgsz/wximgsz.h>
377
378
379#if !defined(__WXMSW__)
380#include "gui-img/icons/dkicon.xpm"
381#endif
382
383
384#include "gui-img/shared/toolbar/run-conversion.xpm"
385
386
387$!trace-include
388
389
390
391/*	__CHANGE__ 017: Add further events. */
392
393/*	Hint: Window IDs for main frame members are defined in an enum
394	in the frame class.
395	IDs defined in this enum should have WximgszFrame:: prepended
396	for an optical distinction from predefined window IDs (i.e. from
397	wxWidgets).
398*/
399
400/*	__CHANGE__ 008: Remove OnIdle if no idle processing required.
401	When removing the table entry here, remove the entire OnIdle() method.
402*/
403
404#if wxCHECK_VERSION(3,0,0)
405wxBEGIN_EVENT_TABLE(WximgszFrame,wxFrame)
406#else
407BEGIN_EVENT_TABLE(WximgszFrame,wxFrame)
408#endif
409	EVT_MENU(\
410		wxID_OPEN,\
411		WximgszFrame::OnFileOpen\
412	)
413	EVT_MENU(\
414		wxID_EXIT,\
415		WximgszFrame::OnQuit\
416	)
417	EVT_MENU(\
418		WximgszFrame::ID_HELP_ABOUT,\
419		WximgszFrame::OnAbout\
420	)
421	EVT_MENU(\
422		WximgszFrame::ID_HELP_TOC,\
423		WximgszFrame::OnHelpContents\
424	)
425	EVT_BUTTON(\
426		WximgszFrame::ID_BUTTON_RUN,\
427		WximgszFrame::OnButtonRun\
428	)
429	EVT_CHOICE(\
430		WximgszFrame::ID_CHOICE_OP,\
431		WximgszFrame::OnChoiceOperation\
432	)
433	EVT_IDLE(\
434		WximgszFrame::OnIdle\
435	)
436#if wxCHECK_VERSION(3,0,0)
437wxEND_EVENT_TABLE()
438#else
439END_EVENT_TABLE()
440#endif
441
442
443
444/**	Image file types we can handle.
445*/
446static wxChar const image_files_to_open[] = {
447	wxT("All files (*.*)|*.*")
448#if	wxUSE_LIBPNG
449	wxT("|PNG files (*.png)|*.png")
450#endif
451#if	wxUSE_LIBJPEG
452	wxT("|JPEG files (*.jpeg)|*.jpeg")
453	wxT("|JPEG files (*.jpg)|*.jpg")
454#endif
455#if	wxUSE_LIBTIFF
456	wxT("|TIFF files (*.tiff)|*.tiff")
457	wxT("|TIFF files (*.tif)|*.tif")
458#endif
459#if	wxUSE_GIF
460	wxT("|GIF files (*.gif)|*.gif")
461#endif
462#if	wxUSE_PCX
463	wxT("|PCX files (*.pcx)|*.pcx")
464#endif
465	wxT("|BMP files (*.bmp)|*.bmp")
466#if	wxUSE_ICO_CUR
467	wxT("|ICO files (*.ico)|*.ico")
468	wxT("|CUR files (*.cur)|*.cur")
469#endif
470#if	wxUSE_XPM
471	wxT("|XPM files (*.xpm)|*.xpm")
472	wxT("|XBM files (*.xbm)|*.xbm")
473#endif
474#if	wxUSE_TGA
475	wxT("|TGA files (*.tga)|*.tga")
476#endif
477#if	wxUSE_IFF
478	wxT("|IFF files (*.iff)|*.iff")
479#endif
480	wxT("|ANI files (*.ani)|*.ani")
481#if	wxUSE_PNM
482	wxT("|NetPBM files (*.pam)|*.pam")
483	wxT("|NetPBM files (*.pnm)|*.pnm")
484	wxT("|NetPBM files (*.ppm)|*.ppm")
485	wxT("|NetPBM files (*.pgm)|*.pgm")
486	wxT("|NetPBM files (*.pbm)|*.pbm")
487#endif
488};
489
490
491/**	Suffix and bitmap type relationship.
492*/
493typedef struct {
494	wxChar const	*s;	/**< File name suffix. */
495	wxBitmapType	 t;	/**< Bitmap type. */
496} Suffix_and_type_t;
497
498
499
500/**	Array to assign file name suffixes to file types.
501*/
502Suffix_and_type_t	suffix_and_type[] = {
503#if	wxUSE_LIBPNG
504	{ wxT(".png"),		wxBITMAP_TYPE_PNG },
505#endif
506#if	wxUSE_LIBJPEG
507	{ wxT(".jpeg"),		wxBITMAP_TYPE_JPEG },
508	{ wxT(".jpg"),		wxBITMAP_TYPE_JPEG },
509#endif
510#if	wxUSE_LIBTIFF
511	{ wxT(".tiff"),		wxBITMAP_TYPE_TIFF },
512	{ wxT(".tif"),		wxBITMAP_TYPE_TIF },
513#endif
514#if	wxUSE_PNM
515	{ wxT(".pam"),		wxBITMAP_TYPE_PNM },
516	{ wxT(".pnm"),		wxBITMAP_TYPE_PNM },
517	{ wxT(".ppm"),		wxBITMAP_TYPE_PNM },
518	{ wxT(".pgm"),		wxBITMAP_TYPE_PNM },
519	{ wxT(".pbm"),		wxBITMAP_TYPE_PNM },
520#endif
521#if	wxUSE_XPM
522	{ wxT(".xpm"),		wxBITMAP_TYPE_XPM },
523	{ wxT(".xbm"),		wxBITMAP_TYPE_XBM },
524#endif
525#if	wxUSE_ICO_CUR
526	{ wxT(".ico"),		wxBITMAP_TYPE_ICO },
527	{ wxT(".cur"),		wxBITMAP_TYPE_CUR },
528#endif
529#if	wxUSE_GIF
530	{ wxT(".gif"),		wxBITMAP_TYPE_GIF },
531#endif
532#if	wxUSE_PCX
533	{ wxT(".pcx"),		wxBITMAP_TYPE_PCX },
534#endif
535	{ wxT(".bmp"),		wxBITMAP_TYPE_BMP },
536#if	wxUSE_TGA
537	{ wxT(".tga"),		wxBITMAP_TYPE_TGA },
538#endif
539#if	wxUSE_IFF
540	{ wxT(".iff"),		wxBITMAP_TYPE_IFF },
541#endif
542	{ wxT(".ani"),		wxBITMAP_TYPE_ANI },
543	{ NULL,				wxBITMAP_TYPE_INVALID }
544};
545
546
547
548static
549wxBitmapType
550bitmap_type_for_name(wxString & fn)
551{
552	wxChar const		*ptr		= NULL;
553	Suffix_and_type_t	*sat		= NULL;
554	wxBitmapType		 back		= wxBITMAP_TYPE_INVALID;
555	wxCStrData			 strdata	= fn.c_str();
556	ptr = (wxChar const *)strdata;
557	if (NULL != ptr) {
558		ptr = dk4strx_get_path_suffix(ptr, NULL);
559		if (NULL != ptr) {
560			sat = suffix_and_type;
561			while((NULL != sat->s) && (wxBITMAP_TYPE_INVALID == back)) {
562				if (0 == dk4strx_casecmp(sat->s, ptr)) {
563					back = sat->t;
564				}
565				else {
566					sat++;
567				}
568			}
569		}
570	}
571	return back;
572}
573
574
575
576%%	constructor start
577WximgszFrame::WximgszFrame(
578	int						  wxid,
579	Dk4WxApplicationHelper	 *applicationHelper,
580	Dk4WxHelpController		 *hc,
581	int						  argc,
582	wxChar					**argv,
583	wxChar const * const	 *localizedTexts,
584	wxChar const * const	 *nlWx,
585	dkChar const * const	 *nlDk
586) : Dk4WxFrame(nlWx[0], applicationHelper, hc, wxid),
587	cas(),
588	cLabelRed(127, 0, 0),
589	cRed(255, 91, 91),
590	cGreen(127, 255, 127),
591	cYellow(255, 255, 0),
592	cBlack(0, 0, 0),
593	sImageFileName((1 < argc)?(argv[1]):(wxT(""))),
594	sDirectory(wxEmptyString)
595{
596	wxString saOperation[] = {
597		wxString(localizedTexts[21]),
598		wxString(localizedTexts[22]),
599		wxString(localizedTexts[23])
600	};
601	$? "+ WximgszFrame::WximgszFrame"
602	/*	__CHANGE__ 012:	Add further local variables.
603	*/
604
605	/*	__CHANGE__ 012: Initialize further local variables.
606	*/
607
608	sTexts = localizedTexts;
609	sNlWx  = nlWx;
610	sNlDk  = nlDk;
611#if defined(__WXMSW__)
612	wxIcon	wximgsz_icon(sNlWx[4]);
613#else
614	wxIcon	wximgsz_icon(xpm_dkicon);
615#endif
616
617	/*	__CHANGE__ 011:	Initialize further class members.
618	*/
619	maxpass = MAXPASS;
620	bActive = false;
621	bImageFileName = false;
622	if (1 < argc) {
623		bImageFileName = true;
624		cas.SetAutoStart();
625	}
626
627%%	constructor end
628	if(dkctGUILayoutOK) {
629		lInput->SetForegroundColour(cLabelRed);
630		lChange->SetForegroundColour(cLabelRed);
631		lResults->SetForegroundColour(cLabelRed);
632#if	0
633		spInputWidth->SetRange(1, INT_MAX);
634		spInputHeight->SetRange(1, INT_MAX);
635		spOperationMin->SetRange(1, INT_MAX);
636		spOperationMax->SetRange(1, INT_MAX);
637		inputSizer->Fit(spInputWidth);
638		inputSizer->Fit(spInputHeight);
639		inputSizer->Fit(spOperationMin);
640		inputSizer->Fit(spOperationMax);
641		mainSizer->Layout();
642#endif
643		cbOperation->SetSelection(0);
644		spOperationMin->Enable(false);
645		spOperationMax->Enable(false);
646		SetTitle(nlWx[0]);
647#if 0
648		RestorePosition();
649#endif
650	}
651
652	/*	__CHANGE__ 012:	Release resources allocated by local variables.
653	*/
654
655	$? "- WximgszFrame::WximgszFrame"
656}
657
658%%	module end
659
660
661
662WximgszFrame::~WximgszFrame()
663{
664	$? "+ WximgszFrame::~WximgszFrame"
665
666	/*	__CHANGE__ 011:	Release resources allocated by further class members.
667	*/
668
669	$? "- WximgszFrame::~WximgszFrame"
670}
671
672
673
674bool
675WximgszFrame::CanClose(bool WXUNUSED(isLast))
676{
677	bool		back	= true;
678	$? "+ WximgszFrame::CanClose"
679
680	/*	__CHANGE__ 013: Check for unsaved data.
681						And probably change parameter to "bool WXUNUSED(isLast)"
682	*/
683
684	$? "- WximgszFrame::CanClose %d", (back ? 1 : 0)
685	return back;
686}
687
688
689
690void
691WximgszFrame::OnFileOpen(wxCommandEvent & WXUNUSED(event))
692{
693	dkChar			 buf[DK4_MAX_PATH];
694	dk4_bif_t		*pbif;
695	const wxChar	*ptrFilePath;
696	bool			 success	=	false;
697	int				 dke;
698	int				 wxe;
699	int				 res;
700#if	wxCHECK_VERSION(2, 9, 0)
701	wxFileDialog dlg(
702		this, sTexts[42], sDirectory, wxEmptyString,
703		image_files_to_open, (wxFD_OPEN | wxFD_FILE_MUST_EXIST)
704	);
705#else
706	wxFileDialog dlg(
707		this, sTexts[42], sDirectory, wxEmptyString,
708		image_files_to_open, wxOPEN
709	);
710#endif
711	$? "+ OnFileOpen"
712	if(wxID_OK == dlg.ShowModal()) {
713		wxString	pa	=	dlg.GetPath();
714		wxFileName	wxfn(pa);
715		if (wxfn.FileExists() && wxfn.IsFileReadable()) {
716			sDirectory		=	dlg.GetDirectory();
717			{
718				wxCStrData	sFilePath	= pa.c_str();
719				ptrFilePath = (wxChar const *)sFilePath;
720				if (NULL != ptrFilePath) {
721					dke = pAppHelp->GetDkEncoding();
722					wxe = pAppHelp->GetWxEncoding();
723					res = dk4recwx_wxchar_to_dkchar(
724						buf, DK4_SIZEOF(buf,dkChar), dke, ptrFilePath, wxe, NULL
725					);
726					if (0 != res) {
727						pbif = dk4bif_open(buf, 1, NULL, NULL);
728						if (NULL != pbif) {
729							dk4_bif_dim_t w = dk4bif_get_width(pbif);
730							dk4_bif_dim_t h = dk4bif_get_height(pbif);
731							if (
732								((dk4_im_t)0L < (dk4_im_t)w)
733								&& ((dk4_im_t)0L < (dk4_im_t)h)
734								&& ((dk4_im_t)(MAXIMGDIM) >= (dk4_im_t)w)
735								&& ((dk4_im_t)(MAXIMGDIM) >= (dk4_im_t)h)
736							) {
737								spInputWidth->SetValue((int)w);
738								spInputHeight->SetValue((int)h);
739								success = true;
740							}
741							dk4bif_close(pbif);
742						}
743					}
744				}
745			}
746			if (!(success)) {						$? ". no success yet"
747				wxBitmapType	t = bitmap_type_for_name(pa);
748				if (wxBITMAP_TYPE_INVALID != t) {	$? ". file suffix ok"
749					wxBitmap	bm(pa, t);
750					if (bm.IsOk()) {
751						int		w =	bm.GetWidth();
752						int		h = bm.GetHeight();
753						if ((0 < w) && (0 < h)) {
754							spInputWidth->SetValue(w);
755							spInputHeight->SetValue(h);
756							success = true;
757						}
758						else {						$? "! dimensions"
759							wxMessageBox(
760								sTexts[44], sTexts[43],
761								(wxOK | wxCENTRE | wxICON_ERROR)
762							);
763						}
764					}
765					else {							$? "! bitmap not ok"
766						wxMessageBox(
767							sTexts[44], sTexts[43],
768							(wxOK | wxCENTRE | wxICON_ERROR)
769						);
770					}
771				}
772				else {
773					wxString	s(sTexts[49]);
774					s.Append(pa);
775					s.Append(sTexts[50]);
776					wxMessageBox(
777						s, wxString(sTexts[43]), (wxOK | wxCENTRE | wxICON_ERROR)
778					);
779				}
780			}
781			if(success) {
782				Calculations();
783			}
784		}
785		else {
786			if (!(wxfn.FileExists())) {			$? "! no such file"
787				wxString	s(sTexts[45]);
788				s.Append(pa);
789				s.Append(sTexts[46]);
790				wxMessageBox(
791					s, wxString(sTexts[43]), (wxOK | wxCENTRE | wxICON_ERROR)
792				);
793			}
794			else {
795				if (!(wxfn.IsFileReadable())) {	$? "! permissions"
796					wxString	s(sTexts[47]);
797					s.Append(pa);
798					s.Append(sTexts[48]);
799					wxMessageBox(
800						s,wxString(sTexts[43]),(wxOK | wxCENTRE | wxICON_ERROR)
801					);
802				}
803			}
804		}
805	}
806	$? "- OnFileOpen"
807	Refresh();
808	Update();
809}
810
811
812void
813WximgszFrame::OnQuit(wxCommandEvent & WXUNUSED(event))
814{
815	$? "+ WximgszFrame::OnQuit"
816	bActive = false;
817	$? "- WximgszFrame::OnQuit"
818	Close();
819}
820
821
822
823void
824WximgszFrame::OnAbout(wxCommandEvent & WXUNUSED(event))
825{
826	wxString	text(wxT(""));
827	wxString	title(wxT(""));
828	$? "+ WximgszFrame::OnAbout"
829	/* Construct message text. */
830	text.Append(sNlWx[0]);
831	text.Append(sNlWx[7]);
832#if	0
833	text.Append(sNlWx[1]);
834#endif
835	text.Append(DKT_VERSION_WX);
836	text.Append(sNlWx[8]);
837	text.Append(sTexts[9]);
838	text.Append(sNlWx[2]);
839	text.Append(sNlWx[8]);
840	text.Append(sNlWx[8]);
841	text.Append(sTexts[11]);
842	text.Append(sNlWx[8]);
843	text.Append(sNlWx[9]);
844	text.Append(sNlWx[8]);
845	text.Append(sNlWx[8]);
846	text.Append(sTexts[12]);
847	text.Append(sNlWx[8]);
848	text.Append(sNlWx[10]);
849	text.Append(sNlWx[8]);
850	text.Append(sNlWx[11]);
851	text.Append(sNlWx[8]);
852	text.Append(sNlWx[12]);
853	text.Append(sNlWx[8]);
854	text.Append(sNlWx[13]);
855	text.Append(sNlWx[8]);
856	text.Append(sNlWx[14]);
857	text.Append(sNlWx[8]);
858	text.Append(sNlWx[15]);
859	text.Append(sNlWx[8]);
860
861	/* Construct dialog box title. */
862	title.Append(sTexts[10]);
863	title.Append(sNlWx[0]);
864
865	/* Show dialog box. */
866	wxMessageBox(text, title);
867
868	/*	__CHANGE__ 019:	Create better about box.
869	*/
870	$? "- WximgszFrame::OnAbout"
871}
872
873
874
875void
876WximgszFrame::OnHelpContents(wxCommandEvent & WXUNUSED(event))
877{
878	$? "+ WximgszFrame::OnHelpContents"
879	DisplayContents();
880	$? "- WximgszFrame::OnHelpContents"
881}
882
883
884
885static
886int
887bits_in_int(int x)
888{
889	int		back = 0;
890	int		test = 1;
891	int		done = 0;
892
893	while (0 == done) {
894		if (0 != (x & test)) {
895			if (1 < ++back) {
896				done = 1;
897			}
898		}
899		if ((INT_MAX / 2) >= test) {
900			test = test * 2;
901			if (test > x) {
902				done = 1;
903			}
904		}
905		else {
906			done = 1;
907		}
908	}
909	return back;
910}
911
912
913static
914int
915is_power_of_2(int x)
916{
917	int			back = 0;
918	if (1 == bits_in_int(x)) {
919		back = 1;
920	}
921	return back;
922}
923
924
925
926static
927int
928quality_for_fraction(int counter, int denom)
929{
930	int		 back = 0;
931	if (1 == denom) {
932		back = 1;
933		if (0 != is_power_of_2(counter)) {
934			back = 2;
935		}
936	}
937	else {
938		if (1 == counter) {
939			back = 1;
940			if (0 != is_power_of_2(denom)) {
941				back = 2;
942			}
943		}
944	}
945	return back;
946}
947
948
949
950static
951int
952gcd(int a, int b)
953{
954	int		h;
955	$? "+ gcd a=%d b=%d", a, b
956	while (0 < b) {
957		h = a % b;
958		a = b;
959		b = h;
960	}	$? "- gcd %d", a
961	return a;
962}
963
964
965/*	__CHANGE__ 017:	Event handlers for further events.
966*/
967
968void
969WximgszFrame::Calculations(void)
970{
971	wxString	s1;			/* Width */
972	wxString	s2;			/* Height */
973	wxString	s3;			/* Factor */
974	wxString	m2(sTexts[36]);
975	wxString	m1(sTexts[35]);
976	wxString	m0(sTexts[34]);
977	int			w_ori;		/* Original width */
978	int			h_ori;		/* Original height */
979	int			w_min;		/* Minimum width */
980	int			h_min;		/* Minimum height */
981	int			gcd_ori;	/* Greatest common divisor original width height */
982	int			min;		/* Destination range minimum */
983	int			max;		/* Destination range maximum */
984	int			opsel;		/* Operation selection */
985	int			f_min;		/* Minimum factor */
986	int			f_max;		/* Maximum factor */
987	int			nrows;		/* Number of table rows */
988	int			passno;		/* Current pass number (table row index) */
989	int			f;			/* Current factor */
990	int			w;			/* Current width */
991	int			h;			/* Current height */
992	int			counter;	/* Fraction counter */
993	int			denom;		/* Fraction denominator */
994	int			gcd_fr;		/* Fraction greatest common divisor */
995	int			q;			/* Fraction quality */
996	int			i;			/* Walk through the columns */
997	bool		bDidSkip;	/* Flag: Restricted output to 2000 columns */
998	$? "+ Calculations"
999	bDidSkip = false;
1000	w_ori = spInputWidth->GetValue();
1001	h_ori = spInputHeight->GetValue();
1002	min   = spOperationMin->GetValue();
1003	max   = spOperationMax->GetValue();
1004	opsel = cbOperation->GetSelection();
1005	if (0 >= w_ori) { w_ori = 1; }
1006	if (0 >= h_ori) { h_ori = 1; }
1007	if (0 >= min) { min = 1; }
1008	if (0 >= max) { max = 1; }
1009	gcd_ori = gcd(w_ori, h_ori);
1010	w_min = w_ori / gcd_ori;
1011	h_min = h_ori / gcd_ori;
1012	f_min = 1;
1013	f_max = gcd_ori;
1014	switch (opsel) {
1015		case 1: {
1016			f_min = min / w_min;
1017			f_max = max / w_min;
1018			if (0 >= f_min) { f_min = 1; }
1019			if (0 >= f_max) { f_max = 1; }
1020		} break;
1021		case 2: {
1022			f_min = min / h_min;
1023			f_max = max / h_min;
1024			if (0 >= f_min) { f_min = 1; }
1025			if (0 >= f_max) { f_max = 1; }
1026		} break;
1027	}
1028	nrows = f_max - f_min + 1;
1029	if (nrows > maxpass) { nrows = maxpass; bDidSkip = true; }
1030	/*
1031		Delete old table columns, allocate new columns
1032	*/
1033	passno = tResult->GetNumberRows();
1034	tResult->DeleteRows(0, passno);
1035	tResult->AppendRows(nrows);
1036	/*
1037		Fill table
1038	*/
1039	passno = 0;
1040	f = f_min;
1041	while (passno < nrows) {
1042		w = f * w_min;
1043		h = f * h_min;
1044		gcd_fr = gcd(f, gcd_ori);
1045		counter = f / gcd_fr;
1046		denom   = gcd_ori / gcd_fr;
1047		q       = quality_for_fraction(counter, denom);
1048		s1.Printf(wxT("%d"), w);
1049		s2.Printf(wxT("%d"), h);
1050		if (1 == denom) {
1051			s3.Printf(wxT("%d"), counter);
1052		}
1053		else {
1054			s3.Printf(wxT("%d / %d"), counter, denom);
1055		}
1056		for (i = 0; i < 4; i++) {
1057			tResult->SetCellTextColour(passno, i, cBlack);
1058		}
1059		tResult->SetCellValue(passno, 0, s1);
1060		tResult->SetCellValue(passno, 1, s2);
1061		tResult->SetCellValue(passno, 2, s3);
1062		switch (q) {
1063			case 2: {
1064				tResult->SetCellValue(passno, 3, m2);
1065				for (i = 0; i < 4; i++) {
1066					tResult->SetCellBackgroundColour(
1067						passno, i, cGreen
1068					);
1069				}
1070			} break;
1071			case 1: {
1072				tResult->SetCellValue(passno, 3, m1);
1073				for (i = 0; i < 4; i++) {
1074					tResult->SetCellBackgroundColour(
1075						passno, i, cYellow
1076					);
1077				}
1078			} break;
1079			case 0: {
1080				tResult->SetCellValue(passno, 3, m0);
1081				for (i = 0; i < 4; i++) {
1082					tResult->SetCellBackgroundColour(
1083						passno, i, cRed
1084					);
1085				}
1086			} break;
1087		}
1088		tResult->SetCellAlignment(passno, 0, wxALIGN_CENTRE, wxALIGN_CENTRE);
1089		tResult->SetCellAlignment(passno, 1, wxALIGN_CENTRE, wxALIGN_CENTRE);
1090		tResult->SetCellAlignment(passno, 2, wxALIGN_CENTRE, wxALIGN_CENTRE);
1091		tResult->SetCellAlignment(passno, 3, wxALIGN_CENTRE, wxALIGN_CENTRE);
1092		passno++;
1093		f++;
1094	}
1095	tResult->AutoSizeColumns();
1096	tResult->EnableDragColSize(true);
1097	if (bDidSkip) {
1098		wxMessageBox( sTexts[39], sTexts[38], (wxOK | wxCENTRE | wxICON_ERROR));
1099	}
1100	$? "- Calculations"
1101}
1102
1103
1104
1105void
1106WximgszFrame::OnButtonRun(wxCommandEvent & WXUNUSED(event))
1107{
1108	$? "+ OnButtonRun"
1109	Calculations();
1110	$? "- OnButtonRun"
1111	Refresh();
1112	Update();
1113}
1114
1115
1116
1117void
1118WximgszFrame::OnChoiceOperation(wxCommandEvent & WXUNUSED(event))
1119{
1120	$? "+ OnChoiceOperation"
1121	switch (cbOperation->GetSelection()) {
1122		case 2 : case 1 : {
1123			spOperationMin->Enable();
1124			spOperationMax->Enable();
1125		} break;
1126		default : {
1127			spOperationMin->Enable(false);
1128			spOperationMax->Enable(false);
1129		} break;
1130	}
1131	$? "- OnChoiceOperation"
1132	Refresh();
1133	Update();
1134}
1135
1136
1137/*	__CHANGE__ 014:	Implementation of further methods.
1138*/
1139
1140
1141void
1142WximgszFrame::ActivateIdleProcessing(bool fl)
1143{
1144	bActive = fl;
1145}
1146
1147
1148void
1149WximgszFrame::ProcessSpecifiedFileName(void)
1150{
1151	dkChar			 buf[DK4_MAX_PATH];
1152	wxChar const	*ptrImageFileName;
1153	dk4_bif_t		*pbif;
1154	int				 dke;
1155	int				 wxe;
1156	int				 res;
1157	bool			 success;
1158	$? "+ ProcessSpecifiedFileName"
1159	success = false;
1160	wxFileName	wxfn(sImageFileName);
1161	if (wxfn.FileExists() && wxfn.IsFileReadable()) {
1162		wxCStrData	csImageFileName = sImageFileName.c_str();
1163		ptrImageFileName = (wxChar const *)csImageFileName;
1164		if (NULL != ptrImageFileName) {			$? ". have wxChar file name"
1165			dke = pAppHelp->GetDkEncoding();
1166			wxe = pAppHelp->GetWxEncoding();
1167			res = dk4recwx_wxchar_to_dkchar(
1168				buf, DK4_SIZEOF(buf,dkChar), dke, ptrImageFileName, wxe, NULL
1169			);
1170			if (0 != res) {						$? ". have dkChar file name"
1171				pbif = dk4bif_open(buf, 1, NULL, NULL);
1172				if (NULL != pbif) {
1173					dk4_bif_dim_t w = dk4bif_get_width(pbif);
1174					dk4_bif_dim_t h = dk4bif_get_height(pbif);
1175					if (
1176						((dk4_im_t)0L < (dk4_im_t)w)
1177						&& ((dk4_im_t)0L < (dk4_im_t)h)
1178						&& ((dk4_im_t)(MAXIMGDIM) >= (dk4_im_t)w)
1179						&& ((dk4_im_t)(MAXIMGDIM) >= (dk4_im_t)h)
1180					) {
1181						spInputWidth->SetValue((int)w);
1182						spInputHeight->SetValue((int)h);
1183						success = true;
1184					}
1185#if	TRACE_DEBUG
1186					else {						$? "! dimensions out of range"
1187					}
1188#endif
1189					dk4bif_close(pbif);
1190				}
1191#if	TRACE_DEBUG
1192				else {							$? "! failed to open bif"
1193				}
1194#endif
1195			}
1196#if	TRACE_DEBUG
1197			else {								$? "! no dkChar file name"
1198			}
1199#endif
1200		}
1201#if	TRACE_DEBUG
1202		else {									$? "! no wxChar file name"
1203		}
1204#endif
1205		if (!(success)) {						$? ". not yet succeeded"
1206			wxBitmapType	t = bitmap_type_for_name(sImageFileName);
1207			if (wxBITMAP_TYPE_INVALID != t) {	$? ". valid file type"
1208				wxBitmap		bm(sImageFileName, t);
1209				if (bm.IsOk()) {
1210					int	w = bm.GetWidth();
1211					int	h = bm.GetHeight();
1212					if ((0 < w) && (0 < h)) {
1213						spInputWidth->SetValue(w);
1214						spInputHeight->SetValue(h);
1215						success = true;
1216					}
1217					else {						$? "! dimensions out of range"
1218#if	0
1219						wxMessageBox(
1220							sTexts[44], sTexts[43],
1221							(wxOK | wxCENTRE | wxICON_ERROR)
1222						);
1223#endif
1224					}
1225				}
1226				else {							$? "! bitmap not ok"
1227#if	0
1228					wxMessageBox(
1229						sTexts[44],sTexts[43],(wxOK | wxCENTRE | wxICON_ERROR)
1230					);
1231#endif
1232				}
1233			}
1234			else {								$? "! invalid file suffix"
1235#if	0
1236				wxString	s(sTexts[49]);
1237				s.Append(sImageFileName);
1238				s.Append(sTexts[50]);
1239				wxMessageBox(
1240					s, wxString(sTexts[43]), (wxOK | wxCENTRE | wxICON_ERROR)
1241				);
1242#endif
1243			}
1244		}
1245		if (success) {
1246			Calculations();
1247		}
1248	}
1249	else {
1250		if (!(wxfn.FileExists())) {				$? "! no such file"
1251#if	0
1252			wxString	s(sTexts[45]);
1253			s.Append(sImageFileName);
1254			s.Append(sTexts[46]);
1255			wxMessageBox(
1256				s, wxString(sTexts[43]), (wxOK | wxCENTRE | wxICON_ERROR)
1257			);
1258#endif
1259		}
1260		else {
1261			if (!(wxfn.IsFileReadable())) {		$? "! permissions"
1262#if	0
1263				wxString	s(sTexts[47]);
1264				s.Append(sImageFileName);
1265				s.Append(sTexts[48]);
1266				wxMessageBox(
1267					s, wxString(sTexts[43]), (wxOK | wxCENTRE | wxICON_ERROR)
1268				);
1269#endif
1270			}
1271		}
1272	}
1273	$? "- ProcessSpecifiedFileName"
1274}
1275
1276/*	__CHANGE__ 008:	Remove OnIdle if no idle processing required.
1277*/
1278
1279/*	__CHANGE__ 008: Remove the request for more events if not needed.
1280*/
1281
1282/*	__CHANGE__ 008: Decide about Skip() call.
1283	The function name is irritating: Skip() or Skip(true) will continue to
1284	process the event, calling default handlers.
1285	Skip(false) or handlers without Skip() will skip further processing of the
1286	event.
1287
1288	From the wxWidgets documenation: Skip() should be called for all
1289	non-command events to allow the default handling to take place.
1290	The command events are, however, normally not skipped as usually a single
1291	command such as a button click or menu item selection must only be
1292	processed by one handler.
1293
1294	So my recommendation is to have a Skip() call in the idle event handler.
1295*/
1296
1297void
1298WximgszFrame::OnIdle(wxIdleEvent & event)
1299{
1300	bool	rqm	=	false;
1301	$? "+ WximgszFrame::OnIdle"
1302	/* __CHANGE__
1303	*/
1304	if (bActive) {
1305		switch (cas.GetReaction()) {
1306			case Dk4WxAutostartController::REACTION_START : {
1307				cas.StartProcessing();
1308				ProcessSpecifiedFileName();
1309				cas.EndProcessing();
1310				Refresh();
1311				Update();
1312			} break;
1313		}
1314		if (rqm) { event.RequestMore(); }
1315	}
1316	$? "- WximgszFrame::OnIdle"
1317	event.Skip();
1318}
1319
1320
1321/* vim: set ai sw=4 ts=4 : */
1322