1 /********************************************************************************
2 *                                                                               *
3 *                      I m a g e   V i e w e r   D e m o                        *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 2000,2006 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * $Id: imageviewer.cpp,v 1.114 2006/01/22 17:59:01 fox Exp $                    *
9 ********************************************************************************/
10 #include "fx.h"
11 #ifdef HAVE_PNG_H
12 #include "FXPNGImage.h"
13 #endif
14 #ifdef HAVE_JPEG_H
15 #include "FXJPGImage.h"
16 #endif
17 #ifdef HAVE_TIFF_H
18 #include "FXTIFImage.h"
19 #endif
20 #include "FXICOImage.h"
21 #include "FXTGAImage.h"
22 #include "FXRGBImage.h"
23 #include "FXPPMImage.h"
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <sys/stat.h>
27 #include <signal.h>
28 #ifndef WIN32
29 #include <unistd.h>
30 #endif
31 
32 
33 /*******************************************************************************/
34 
35 
36 // Mini application object
37 class ImageWindow : public FXMainWindow {
38   FXDECLARE(ImageWindow)
39 protected:
40   FXImageView       *imageview;             // Image viewer
41   FXRecentFiles      mrufiles;              // Recent files
42   FXString           filename;              // File being viewed
43   FXMenuBar         *menubar;               // Menu bar
44   FXToolBar         *toolbar;               // Tool bar
45   FXStatusBar       *statusbar;             // Status bar
46   FXSplitter        *splitter;              // Splitter
47   FXHorizontalFrame *filebox;               // Box containing directories/files
48   FXFileList        *filelist;              // File List
49   FXMenuPane        *filemenu;              // File menu
50   FXMenuPane        *editmenu;              // Edit menu
51   FXMenuPane        *viewmenu;              // View menu
52   FXMenuPane        *helpmenu;              // Help menu
53   FXMenuPane        *manipmenu;             // Manipulations menu
54   FXTextField       *filter;                // Filter for tree list
55   FXIcon            *fileopenicon;          // Icons
56   FXIcon            *filesaveicon;
57   FXIcon            *cuticon;
58   FXIcon            *copyicon;
59   FXIcon            *pasteicon;
60   FXIcon            *uplevelicon;
61   FXIcon            *paletteicon;
62 protected:
ImageWindow()63   ImageWindow(){}
64 public:
65   long onCmdAbout(FXObject*,FXSelector,void*);
66   long onCmdOpen(FXObject*,FXSelector,void*);
67   long onCmdSave(FXObject*,FXSelector,void*);
68   long onCmdQuit(FXObject*,FXSelector,void*);
69   long onUpdTitle(FXObject*,FXSelector,void*);
70   long onCmdFileList(FXObject*,FXSelector,void*);
71   long onCmdRecentFile(FXObject*,FXSelector,void*);
72   long onCmdRotate(FXObject*,FXSelector,void*);
73   long onCmdMirror(FXObject*,FXSelector,void*);
74   long onCmdScale(FXObject*,FXSelector,void*);
75   long onCmdCrop(FXObject*,FXSelector,void*);
76   long onUpdImage(FXObject*,FXSelector,void*);
77 public:
78   enum{
79     ID_ABOUT=FXMainWindow::ID_LAST,
80     ID_OPEN,
81     ID_SAVE,
82     ID_TITLE,
83     ID_QUIT,
84     ID_FILELIST,
85     ID_RECENTFILE,
86     ID_ROTATE_90,
87     ID_ROTATE_180,
88     ID_ROTATE_270,
89     ID_MIRROR_HOR,
90     ID_MIRROR_VER,
91     ID_MIRROR_BOTH,
92     ID_SCALE,
93     ID_CROP,
94     ID_LAST
95     };
96 public:
97   ImageWindow(FXApp* a);
98   virtual void create();
99   FXbool loadimage(const FXString& file);
100   FXbool saveimage(const FXString& file);
101   virtual ~ImageWindow();
102   };
103 
104 
105 /*******************************************************************************/
106 
107 
108 // File Save
109 const unsigned char filesave[]={
110   0x47,0x49,0x46,0x38,0x37,0x61,0x10,0x00,0x10,0x00,0xf2,0x00,0x00,0xb2,0xc0,0xdc,
111   0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x80,0x80,0x80,0xff,0xff,0xff,0x00,
112   0x00,0x00,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x03,
113   0x42,0x08,0xaa,0xb1,0xfe,0x4c,0x34,0x06,0xa3,0x90,0x20,0xcc,0x1a,0xae,0xc4,0x95,
114   0x75,0x6d,0x8f,0xa6,0x79,0x64,0xa6,0x0d,0x44,0x87,0x9a,0x0c,0xc1,0x9a,0xb4,0x3c,
115   0x05,0x33,0xad,0xd7,0x43,0x50,0x0c,0xbf,0x20,0x10,0xb8,0x6a,0x0d,0x85,0x42,0x8d,
116   0x11,0x79,0xec,0x65,0x7a,0x4c,0x64,0x23,0xb0,0x6c,0x26,0x55,0xd6,0xe6,0x6d,0xc7,
117   0x55,0x24,0x00,0x00,0x3b
118   };
119 
120 
121 // File Open
122 const unsigned char fileopen[]={
123   0x47,0x49,0x46,0x38,0x37,0x61,0x10,0x00,0x10,0x00,0xf2,0x00,0x00,0xb2,0xc0,0xdc,
124   0x00,0x00,0x00,0x00,0xff,0x00,0xff,0xff,0x00,0x80,0x80,0x80,0xff,0xff,0xff,0x00,
125   0x00,0x00,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x03,
126   0x45,0x08,0xba,0x1c,0xfe,0x2c,0xae,0x20,0x44,0x90,0x91,0xd6,0x8b,0x95,0xb6,0x1c,
127   0x00,0x79,0x95,0x25,0x3e,0x03,0x31,0x3c,0xa5,0x73,0xaa,0xf0,0xda,0xae,0x5e,0xfa,
128   0xdc,0xb8,0xa3,0x06,0xc5,0xd0,0xff,0x3e,0x9f,0xc3,0x16,0x04,0x02,0x75,0x81,0xa2,
129   0xb2,0x77,0x49,0xf2,0x96,0xc5,0x26,0x21,0x69,0x54,0x36,0xa9,0x50,0xa6,0xe7,0x59,
130   0xfd,0x71,0x72,0x60,0x4e,0x02,0x00,0x3b
131   };
132 
133 
134 // Cut
135 const unsigned char cut[]={
136   0x47,0x49,0x46,0x38,0x37,0x61,0x10,0x00,0x10,0x00,0xf1,0x00,0x00,0xb2,0xc0,0xdc,
137   0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x00,0x10,0x00,
138   0x10,0x00,0x00,0x02,0x29,0x84,0x8f,0xa9,0x10,0xd7,0xeb,0x22,0x34,0x8f,0x4d,0xda,
139   0x42,0x9d,0xf9,0x3a,0xed,0x49,0xa1,0x10,0x08,0x21,0x60,0x0a,0xea,0xa4,0xa6,0x86,
140   0xa9,0xc0,0x2e,0xba,0xc8,0xf4,0x9d,0xd8,0x28,0x5c,0xf3,0xe7,0x54,0x00,0x00,0x3b
141   };
142 
143 
144 // Copy
145 const unsigned char copy[]={
146   0x47,0x49,0x46,0x38,0x37,0x61,0x10,0x00,0x10,0x00,0xf1,0x00,0x00,0xb2,0xc0,0xdc,
147   0x00,0x00,0x00,0xff,0xff,0xff,0x00,0x00,0x80,0x2c,0x00,0x00,0x00,0x00,0x10,0x00,
148   0x10,0x00,0x00,0x02,0x38,0x84,0x8f,0x69,0xc1,0xad,0x18,0x84,0x14,0xec,0xad,0x49,
149   0xa9,0x8d,0x8c,0x8e,0x0f,0x42,0x98,0x30,0x60,0xdf,0xc1,0x35,0xe5,0x54,0x0e,0x97,
150   0x49,0x45,0xa0,0x9b,0x32,0xeb,0x48,0xe3,0x71,0x43,0x02,0x8d,0x3a,0x92,0xb8,0x14,
151   0xa5,0x9f,0xec,0x71,0x33,0x21,0x67,0x33,0x8b,0xf3,0x99,0x28,0x00,0x00,0x3b
152   };
153 
154 
155 // Paste
156 const unsigned char paste[]={
157   0x47,0x49,0x46,0x38,0x37,0x61,0x10,0x00,0x10,0x00,0xf2,0x00,0x00,0xb2,0xc0,0xdc,
158   0x00,0x00,0x00,0xff,0xff,0x00,0xc0,0xc0,0xc0,0x80,0x80,0x00,0x80,0x80,0x80,0x00,
159   0x00,0x80,0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x03,
160   0x4b,0x08,0xba,0xdc,0x1e,0x30,0x38,0x15,0xa1,0x10,0x55,0x52,0x52,0x48,0xc0,0x5f,
161   0xd0,0x15,0x9a,0x48,0x0e,0x68,0x2a,0x7a,0x1b,0x99,0x41,0x05,0x49,0x8d,0x5c,0x4d,
162   0x97,0x36,0x61,0xec,0xbc,0x51,0xd2,0x05,0xc3,0x61,0x38,0xdc,0xb5,0x6a,0x42,0xe2,
163   0x41,0x68,0x00,0xac,0x46,0xc2,0xc8,0x92,0x17,0xc8,0x25,0x95,0xc5,0x27,0x27,0x9a,
164   0x59,0x3a,0x2b,0x57,0x6c,0xb3,0xd1,0x2b,0x8f,0x27,0x93,0x04,0x00,0x3b
165   };
166 
167 
168 // Palette of colors
169 const unsigned char colorpal[]={
170   0x47,0x49,0x46,0x38,0x37,0x61,0x10,0x00,0x10,0x00,0xf2,0x00,0x00,0x80,0x80,0x80,
171   0x00,0x00,0x00,0xff,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0x00,0x00,
172   0x00,0xff,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x03,
173   0x47,0x08,0x0a,0xd1,0xfb,0x30,0x88,0xe9,0xe0,0x92,0x33,0x07,0xcb,0xf2,0xf8,0xd4,
174   0xd3,0x64,0xc2,0x37,0x48,0x55,0x83,0x11,0x04,0x83,0x09,0x9b,0x23,0xb1,0x2d,0x49,
175   0x6d,0xdd,0x42,0xc6,0x68,0x67,0xdf,0x23,0x58,0xa7,0x40,0x7c,0x05,0x85,0x12,0x62,
176   0xe1,0x65,0xc3,0xa1,0x24,0x86,0x68,0x54,0x73,0xc9,0x48,0x0d,0x54,0xd1,0xf1,0x66,
177   0x91,0xa9,0x70,0x11,0x30,0x07,0x90,0x00,0x00,0x3b
178   };
179 
180 const unsigned char tbuplevel[]={
181   0x47,0x49,0x46,0x38,0x37,0x61,0x10,0x00,0x10,0x00,0xf1,0x00,0x00,0xb2,0xc0,0xdc,
182   0x00,0x00,0x00,0xff,0xff,0x00,0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x10,0x00,
183   0x10,0x00,0x00,0x02,0x32,0x84,0x8f,0x79,0xc1,0xac,0x18,0xc4,0x90,0x22,0x3c,0xd0,
184   0xb2,0x76,0x78,0x7a,0xfa,0x0d,0x56,0xe4,0x05,0x21,0x35,0x96,0xcc,0x29,0x62,0x92,
185   0x76,0xa6,0x28,0x08,0x8e,0x35,0x5b,0x75,0x28,0xfc,0xba,0xf8,0x27,0xfb,0xf5,0x36,
186   0x44,0xce,0xe5,0x88,0x44,0x14,0x00,0x00,0x3b
187   };
188 
189 // Patterns
190 const FXchar patterns[]=
191   "All Files (*)"
192   "\nGIF Image (*.gif)"
193   "\nBMP Image (*.bmp)"
194   "\nXPM Image (*.xpm)"
195   "\nPCX Image (*.pcx)"
196   "\nICO Image (*.ico)"
197   "\nRGB Image  (*.rgb)"
198   "\nXBM Image  (*.xbm)"
199   "\nTARGA Image  (*.tga)"
200   "\nPPM Image  (*.ppm)"
201 #ifdef HAVE_PNG_H
202   "\nPNG Image  (*.png)"
203 #endif
204 #ifdef HAVE_JPEG_H
205   "\nJPEG Image (*.jpg)"
206 #endif
207 #ifdef HAVE_TIFF_H
208   "\nTIFF Image (*.tif)"
209 #endif
210   ;
211 
212 /*******************************************************************************/
213 
214 // Map
215 FXDEFMAP(ImageWindow) ImageWindowMap[]={
216   FXMAPFUNC(SEL_COMMAND,       ImageWindow::ID_ABOUT,      ImageWindow::onCmdAbout),
217   FXMAPFUNC(SEL_COMMAND,       ImageWindow::ID_OPEN,       ImageWindow::onCmdOpen),
218   FXMAPFUNC(SEL_COMMAND,       ImageWindow::ID_SAVE,       ImageWindow::onCmdSave),
219   FXMAPFUNC(SEL_UPDATE,        ImageWindow::ID_TITLE,      ImageWindow::onUpdTitle),
220   FXMAPFUNC(SEL_COMMAND,       ImageWindow::ID_QUIT,       ImageWindow::onCmdQuit),
221   FXMAPFUNC(SEL_SIGNAL,        ImageWindow::ID_QUIT,       ImageWindow::onCmdQuit),
222   FXMAPFUNC(SEL_CLOSE,         ImageWindow::ID_TITLE,      ImageWindow::onCmdQuit),
223   FXMAPFUNC(SEL_DOUBLECLICKED, ImageWindow::ID_FILELIST,   ImageWindow::onCmdFileList),
224   FXMAPFUNC(SEL_COMMAND,       ImageWindow::ID_RECENTFILE, ImageWindow::onCmdRecentFile),
225   FXMAPFUNC(SEL_COMMAND,       ImageWindow::ID_ROTATE_90,  ImageWindow::onCmdRotate),
226   FXMAPFUNC(SEL_COMMAND,       ImageWindow::ID_ROTATE_180, ImageWindow::onCmdRotate),
227   FXMAPFUNC(SEL_COMMAND,       ImageWindow::ID_ROTATE_270, ImageWindow::onCmdRotate),
228   FXMAPFUNC(SEL_COMMAND,       ImageWindow::ID_MIRROR_HOR, ImageWindow::onCmdMirror),
229   FXMAPFUNC(SEL_COMMAND,       ImageWindow::ID_MIRROR_VER, ImageWindow::onCmdMirror),
230   FXMAPFUNC(SEL_COMMAND,       ImageWindow::ID_MIRROR_BOTH,ImageWindow::onCmdMirror),
231   FXMAPFUNC(SEL_COMMAND,       ImageWindow::ID_SCALE,      ImageWindow::onCmdScale),
232   FXMAPFUNC(SEL_COMMAND,       ImageWindow::ID_CROP,       ImageWindow::onCmdCrop),
233   FXMAPFUNC(SEL_UPDATE,        ImageWindow::ID_ROTATE_90,  ImageWindow::onUpdImage),
234   FXMAPFUNC(SEL_UPDATE,        ImageWindow::ID_ROTATE_180, ImageWindow::onUpdImage),
235   FXMAPFUNC(SEL_UPDATE,        ImageWindow::ID_ROTATE_270, ImageWindow::onUpdImage),
236   FXMAPFUNC(SEL_UPDATE,        ImageWindow::ID_MIRROR_HOR, ImageWindow::onUpdImage),
237   FXMAPFUNC(SEL_UPDATE,        ImageWindow::ID_MIRROR_VER, ImageWindow::onUpdImage),
238   FXMAPFUNC(SEL_UPDATE,        ImageWindow::ID_MIRROR_BOTH,ImageWindow::onUpdImage),
239   FXMAPFUNC(SEL_UPDATE,        ImageWindow::ID_SCALE,      ImageWindow::onUpdImage),
240   FXMAPFUNC(SEL_UPDATE,        ImageWindow::ID_CROP,       ImageWindow::onUpdImage),
241   };
242 
243 
244 // Object implementation
FXIMPLEMENT(ImageWindow,FXMainWindow,ImageWindowMap,ARRAYNUMBER (ImageWindowMap))245 FXIMPLEMENT(ImageWindow,FXMainWindow,ImageWindowMap,ARRAYNUMBER(ImageWindowMap))
246 
247 
248 // Make some windows
249 ImageWindow::ImageWindow(FXApp* a):FXMainWindow(a,"FOX Image Viewer: - untitled",NULL,NULL,DECOR_ALL,0,0,850,600,0,0){
250   setTarget(this);
251   setSelector(ID_TITLE);
252 
253   // Make some icons
254   fileopenicon=new FXGIFIcon(getApp(),fileopen);
255   filesaveicon=new FXGIFIcon(getApp(),filesave);
256   cuticon=new FXGIFIcon(getApp(),cut);
257   copyicon=new FXGIFIcon(getApp(),copy);
258   pasteicon=new FXGIFIcon(getApp(),paste);
259   uplevelicon=new FXGIFIcon(getApp(),tbuplevel);
260   paletteicon=new FXGIFIcon(getApp(),colorpal);
261 
262   // Make color dialog
263   FXColorDialog *colordlg=new FXColorDialog(this,"Color Dialog");
264 
265   // Make menu bar
266   menubar=new FXMenuBar(this,LAYOUT_SIDE_TOP|LAYOUT_FILL_X|FRAME_RAISED);
267 
268   // Tool bar
269   toolbar=new FXToolBar(this,LAYOUT_SIDE_TOP|PACK_UNIFORM_WIDTH|PACK_UNIFORM_HEIGHT|FRAME_RAISED|LAYOUT_FILL_X);
270 
271   // Make menu bar
272   //menubar=new FXMenuBar(this,LAYOUT_SIDE_TOP|LAYOUT_FILL_X|FRAME_RAISED);
273 
274   // Tool bar
275   //FXHorizontalFrame* toolbarcontainer=new FXHorizontalFrame(this,LAYOUT_SIDE_TOP|LAYOUT_FILL_X,0,0,0,0, 0,0,0,0, 0,0);
276   //new FXToolBarTab(toolbarcontainer,NULL,0,FRAME_RAISED);
277   //toolbar=new FXToolBar(toolbarcontainer,FRAME_RAISED|PACK_UNIFORM_WIDTH|LAYOUT_SIDE_TOP|LAYOUT_FILL_X,0,0,0,0, 4,4,4,4, 0,0);
278 
279   // Status bar
280   statusbar=new FXStatusBar(this,LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|STATUSBAR_WITH_DRAGCORNER);
281 
282   // File menu
283   filemenu=new FXMenuPane(this);
284   new FXMenuTitle(menubar,"&File",NULL,filemenu);
285 
286   // Edit Menu
287   editmenu=new FXMenuPane(this);
288   new FXMenuTitle(menubar,"&Edit",NULL,editmenu);
289 
290   // Edit Menu
291   manipmenu=new FXMenuPane(this);
292   new FXMenuTitle(menubar,"&Manipulation",NULL,manipmenu);
293 
294   // View menu
295   viewmenu=new FXMenuPane(this);
296   new FXMenuTitle(menubar,"&View",NULL,viewmenu);
297 
298   // Help menu
299   helpmenu=new FXMenuPane(this);
300   new FXMenuTitle(menubar,"&Help",NULL,helpmenu,LAYOUT_RIGHT);
301 
302   // Splitter
303   splitter=new FXSplitter(this,LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y|SPLITTER_TRACKING|SPLITTER_VERTICAL|SPLITTER_REVERSED);
304 
305   // Sunken border for image widget
306   FXHorizontalFrame *imagebox=new FXHorizontalFrame(splitter,FRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y,0,0,0,0, 0,0,0,0);
307 
308   // Make image widget
309   imageview=new FXImageView(imagebox,NULL,NULL,0,LAYOUT_FILL_X|LAYOUT_FILL_Y);
310 
311   // Sunken border for file list
312   filebox=new FXHorizontalFrame(splitter,LAYOUT_FILL_X|LAYOUT_FILL_Y,0,0,0,0, 0,0,0,0);
313 
314   // Make file list
315   FXHorizontalFrame* fileframe=new FXHorizontalFrame(filebox,FRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y,0,0,0,0, 0,0,0,0, 0,0);
316   filelist=new FXFileList(fileframe,this,ID_FILELIST,LAYOUT_FILL_X|LAYOUT_FILL_Y|ICONLIST_MINI_ICONS|ICONLIST_AUTOSIZE);
317   new FXButton(filebox,"\tUp one level\tGo up to higher directory.",uplevelicon,filelist,FXFileList::ID_DIRECTORY_UP,BUTTON_TOOLBAR|FRAME_RAISED|LAYOUT_FILL_Y);
318 
319   // Toobar buttons: File manipulation
320   new FXButton(toolbar,"&Open\tOpen Image\tOpen image file.",fileopenicon,this,ID_OPEN,ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED);
321   new FXButton(toolbar,"&Save\tSave Image\tSave image file.",filesaveicon,this,ID_SAVE,ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED);
322 
323   // Toobar buttons: Editing
324   new FXButton(toolbar,"Cut\tCut",cuticon,NULL,0,ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED);
325   new FXButton(toolbar,"Copy\tCopy",copyicon,NULL,0,ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED);
326   new FXButton(toolbar,"Paste\tPaste",pasteicon,NULL,0,ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED);
327 
328   // Color
329   new FXButton(toolbar,"&Colors\tColors\tDisplay color dialog.",paletteicon,colordlg,FXWindow::ID_SHOW,ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED|LAYOUT_RIGHT);
330 
331   // File Menu entries
332   new FXMenuCommand(filemenu,"&Open...\tCtl-O\tOpen image file.",fileopenicon,this,ID_OPEN);
333   new FXMenuCommand(filemenu,"&Save...\tCtl-S\tSave image file.",filesaveicon,this,ID_SAVE);
334   new FXMenuCommand(filemenu,"Dump",NULL,getApp(),FXApp::ID_DUMP);
335 
336   // Recent file menu; this automatically hides if there are no files
337   FXMenuSeparator* sep1=new FXMenuSeparator(filemenu);
338   sep1->setTarget(&mrufiles);
339   sep1->setSelector(FXRecentFiles::ID_ANYFILES);
340   new FXMenuCommand(filemenu,FXString::null,NULL,&mrufiles,FXRecentFiles::ID_FILE_1);
341   new FXMenuCommand(filemenu,FXString::null,NULL,&mrufiles,FXRecentFiles::ID_FILE_2);
342   new FXMenuCommand(filemenu,FXString::null,NULL,&mrufiles,FXRecentFiles::ID_FILE_3);
343   new FXMenuCommand(filemenu,FXString::null,NULL,&mrufiles,FXRecentFiles::ID_FILE_4);
344   new FXMenuCommand(filemenu,FXString::null,NULL,&mrufiles,FXRecentFiles::ID_FILE_5);
345   new FXMenuCommand(filemenu,FXString::null,NULL,&mrufiles,FXRecentFiles::ID_FILE_6);
346   new FXMenuCommand(filemenu,FXString::null,NULL,&mrufiles,FXRecentFiles::ID_FILE_7);
347   new FXMenuCommand(filemenu,FXString::null,NULL,&mrufiles,FXRecentFiles::ID_FILE_8);
348   new FXMenuCommand(filemenu,FXString::null,NULL,&mrufiles,FXRecentFiles::ID_FILE_9);
349   new FXMenuCommand(filemenu,FXString::null,NULL,&mrufiles,FXRecentFiles::ID_FILE_10);
350   new FXMenuCommand(filemenu,"&Clear Recent Files",NULL,&mrufiles,FXRecentFiles::ID_CLEAR);
351   FXMenuSeparator* sep2=new FXMenuSeparator(filemenu);
352   sep2->setTarget(&mrufiles);
353   sep2->setSelector(FXRecentFiles::ID_ANYFILES);
354   new FXMenuCommand(filemenu,"&Quit\tCtl-Q",NULL,this,ID_QUIT);
355 
356   // Edit Menu entries
357   new FXMenuCommand(editmenu,"&Undo\tCtl-Z\tUndo last change.");
358   new FXMenuCommand(editmenu,"&Redo\tCtl-R\tRedo last undo.");
359   new FXMenuCommand(editmenu,"&Copy\tCtl-C\tCopy selection to clipboard.",copyicon,NULL,0);
360   new FXMenuCommand(editmenu,"C&ut\tCtl-X\tCut selection to clipboard.",cuticon,NULL,0);
361   new FXMenuCommand(editmenu,"&Paste\tCtl-V\tPaste from clipboard.",pasteicon,NULL,0);
362   new FXMenuCommand(editmenu,"&Delete\t\tDelete selection.",NULL,NULL,0);
363 
364   // Manipulation Menu entries
365   new FXMenuCommand(manipmenu,"Rotate 90\t\tRotate 90 degrees.",NULL,this,ID_ROTATE_90);
366   new FXMenuCommand(manipmenu,"Rotate 180\t\tRotate 180 degrees.",NULL,this,ID_ROTATE_180);
367   new FXMenuCommand(manipmenu,"Rotate -90\t\tRotate -90 degrees.",NULL,this,ID_ROTATE_270);
368   new FXMenuCommand(manipmenu,"Mirror Horizontally\t\tMirror Horizontally.",NULL,this,ID_MIRROR_HOR);
369   new FXMenuCommand(manipmenu,"Mirror Vertically\t\tMirror Vertically.",NULL,this,ID_MIRROR_VER);
370   new FXMenuCommand(manipmenu,"Mirror Both\t\tMirror Both.",NULL,this,ID_MIRROR_BOTH);
371   new FXMenuCommand(manipmenu,"Scale...\t\tScale image.",NULL,this,ID_SCALE);
372   new FXMenuCommand(manipmenu,"Crop...\t\tCrop image.",NULL,this,ID_CROP);
373 
374   // View Menu entries
375   new FXMenuCommand(viewmenu,"File list\t\tDisplay file list.",NULL,filebox,FXWindow::ID_TOGGLESHOWN);
376   new FXMenuCommand(viewmenu,"Show hidden files\t\tShow hidden files and directories.",NULL,filelist,FXFileList::ID_TOGGLE_HIDDEN);
377   new FXMenuCommand(viewmenu,"Show small icons\t\tDisplay directory with small icons.",NULL,filelist,FXFileList::ID_SHOW_MINI_ICONS);
378   new FXMenuCommand(viewmenu,"Show big icons\t\tDisplay directory with big icons.",NULL,filelist,FXFileList::ID_SHOW_BIG_ICONS);
379   new FXMenuCommand(viewmenu,"Show details view\t\tDisplay detailed directory listing.",NULL,filelist,FXFileList::ID_SHOW_DETAILS);
380   new FXMenuCommand(viewmenu,"Rows of icons\t\tView row-wise.",NULL,filelist,FXFileList::ID_ARRANGE_BY_ROWS);
381   new FXMenuCommand(viewmenu,"Columns of icons\t\tView column-wise.",NULL,filelist,FXFileList::ID_ARRANGE_BY_COLUMNS);
382   new FXMenuCommand(viewmenu,"Toolbar\t\tDisplay toolbar.",NULL,toolbar,FXWindow::ID_TOGGLESHOWN);
383   new FXMenuCommand(viewmenu,"Float toolbar\t\tUndock the toolbar.",NULL,toolbar,FXToolBar::ID_DOCK_FLOAT);
384   new FXMenuCommand(viewmenu,"Dock toolbar top\t\tDock the toolbar on the top.",NULL,toolbar,FXToolBar::ID_DOCK_TOP);
385   new FXMenuCommand(viewmenu,"Dock toolbar left\t\tDock the toolbar on the left.",NULL,toolbar,FXToolBar::ID_DOCK_LEFT);
386   new FXMenuCommand(viewmenu,"Dock toolbar right\t\tDock the toolbar on the right.",NULL,toolbar,FXToolBar::ID_DOCK_RIGHT);
387   new FXMenuCommand(viewmenu,"Dock toolbar bottom\t\tDock the toolbar on the bottom.",NULL,toolbar,FXToolBar::ID_DOCK_BOTTOM);
388   new FXMenuCommand(viewmenu,"Status line\t\tDisplay status line.",NULL,statusbar,FXWindow::ID_TOGGLESHOWN);
389 
390   // Help Menu entries
391   new FXMenuCommand(helpmenu,"&About FOX...",NULL,this,ID_ABOUT,0);
392 
393   // Make a tool tip
394   new FXToolTip(getApp(),TOOLTIP_NORMAL);
395 
396   // Recent files
397   mrufiles.setTarget(this);
398   mrufiles.setSelector(ID_RECENTFILE);
399 
400   // Initialize file name
401   filename="untitled";
402   }
403 
404 
405 // Clean up
~ImageWindow()406 ImageWindow::~ImageWindow(){
407   delete filemenu;
408   delete editmenu;
409   delete manipmenu;
410   delete helpmenu;
411   delete viewmenu;
412   delete fileopenicon;
413   delete filesaveicon;
414   delete cuticon;
415   delete copyicon;
416   delete pasteicon;
417   delete uplevelicon;
418   delete paletteicon;
419   }
420 
421 
422 // About box
onCmdAbout(FXObject *,FXSelector,void *)423 long ImageWindow::onCmdAbout(FXObject*,FXSelector,void*){
424   FXMessageBox about(this,"About Image Viewer","Image Viewer demonstrates the FOX ImageView widget.\n\nUsing the FOX C++ GUI Library (http://www.fox-toolkit.org)\n\nCopyright (C) 2000,2004 Jeroen van der Zijp (jeroen@fox-toolkit.org)",NULL,MBOX_OK|DECOR_TITLE|DECOR_BORDER);
425   about.execute();
426   return 1;
427   }
428 
429 
430 // Load file
loadimage(const FXString & file)431 FXbool ImageWindow::loadimage(const FXString& file){
432   FXString ext=FXPath::extension(file);
433   FXImage *img=NULL;
434   FXImage *old;
435   if(comparecase(ext,"gif")==0){
436     img=new FXGIFImage(getApp(),NULL,IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
437     }
438   else if(comparecase(ext,"bmp")==0){
439     img=new FXBMPImage(getApp(),NULL,IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
440     }
441   else if(comparecase(ext,"xpm")==0){
442     img=new FXXPMImage(getApp(),NULL,IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
443     }
444   else if(comparecase(ext,"pcx")==0){
445     img=new FXPCXImage(getApp(),NULL,IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
446     }
447   else if(comparecase(ext,"ico")==0 || comparecase(ext,"cur")==0){
448     img=new FXICOImage(getApp(),NULL,IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
449     }
450   else if(comparecase(ext,"tga")==0){
451     img=new FXTGAImage(getApp(),NULL,IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
452     }
453   else if(comparecase(ext,"rgb")==0){
454     img=new FXRGBImage(getApp(),NULL,IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
455     }
456   else if(comparecase(ext,"xbm")==0){
457     img=new FXXBMImage(getApp(),NULL,NULL,IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
458     }
459   else if(comparecase(ext,"ppm")==0){
460     img=new FXPPMImage(getApp(),NULL,IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
461     }
462   else if(comparecase(ext,"iff")==0 || comparecase(ext,"lbm")==0){
463     img=new FXIFFImage(getApp(),NULL,IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
464     }
465   else if(comparecase(ext,"ras")==0){
466     img=new FXRASImage(getApp(),NULL,IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
467     }
468 #ifdef HAVE_PNG_H
469   else if(comparecase(ext,"png")==0){
470     img=new FXPNGImage(getApp(),NULL,IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
471     }
472 #endif
473 #ifdef HAVE_JPEG_H
474   else if(comparecase(ext,"jpg")==0){
475     img=new FXJPGImage(getApp(),NULL,IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
476     }
477 #endif
478 #ifdef HAVE_TIFF_H
479   else if(comparecase(ext,"tif")==0 || comparecase(ext,"tiff")==0){
480     img=new FXTIFImage(getApp(),NULL,IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
481     }
482 #endif
483 
484   // Perhaps failed
485   if(img==NULL){
486     FXMessageBox::error(this,MBOX_OK,"Error Loading Image","Unsupported type: %s",ext.text());
487     return FALSE;
488     }
489 
490   // Load it
491   FXFileStream stream;
492   if(stream.open(file,FXStreamLoad)){
493     getApp()->beginWaitCursor();
494     img->loadPixels(stream);
495     stream.close();
496 
497 //img->gradient(FXRGB(255,0,0),FXRGB(0,255,0),FXRGB(0,0,255),FXRGB(255,255,255));
498 //img->gradient(FXRGB(255,0,0),FXRGB(255,255,0),FXRGB(0,0,255),FXRGB(255,0,255));
499 //img->hgradient(FXRGB(255,0,0),FXRGB(0,0,255));
500 //img->vgradient(FXRGB(255,0,0),FXRGB(0,0,255));
501 //img->fill(FXRGB(255,0,0));
502 //img->fade(FXRGB(255,255,255),128);
503 //img->blend(getApp()->getBaseColor());
504 //img->blend(FXRGB(255,128,255));
505 //img->xshear(-30*256,FXRGB(0,255,128));
506 //img->yshear(-50*256,FXRGB(0,255,128));
507 
508 
509     img->create();
510     old=imageview->getImage();
511     imageview->setImage(img);
512     delete old;
513     getApp()->endWaitCursor();
514     }
515   return TRUE;
516   }
517 
518 
519 // Save file
saveimage(const FXString & file)520 FXbool ImageWindow::saveimage(const FXString& file){
521   FXImage *img;
522   FXFileStream stream;
523   if(stream.open(file,FXStreamSave)){
524     getApp()->beginWaitCursor();
525     img=imageview->getImage();///// We may want to save in another format...
526     img->savePixels(stream);
527     stream.close();
528     getApp()->endWaitCursor();
529     }
530   return TRUE;
531   }
532 
533 
534 // Open
onCmdOpen(FXObject *,FXSelector,void *)535 long ImageWindow::onCmdOpen(FXObject*,FXSelector,void*){
536   FXFileDialog open(this,"Open Image");
537   open.setFilename(filename);
538   open.setPatternList(patterns);
539   if(open.execute()){
540     filename=open.getFilename();
541     filelist->setCurrentFile(filename);
542     mrufiles.appendFile(filename);
543     loadimage(filename);
544     }
545   return 1;
546   }
547 
548 
549 // Save
onCmdSave(FXObject *,FXSelector,void *)550 long ImageWindow::onCmdSave(FXObject*,FXSelector,void*){
551   FXFileDialog savedialog(this,"Save Image");
552   savedialog.setFilename(filename);
553   if(savedialog.execute()){
554     if(FXStat::exists(savedialog.getFilename())){
555       if(MBOX_CLICKED_NO==FXMessageBox::question(this,MBOX_YES_NO,"Overwrite Image","Overwrite existing image?")) return 1;
556       }
557     filename=savedialog.getFilename();
558     filelist->setCurrentFile(filename);
559     mrufiles.appendFile(filename);
560     saveimage(filename);
561     }
562   return 1;
563   }
564 
565 
566 // Quit
onCmdQuit(FXObject *,FXSelector,void *)567 long ImageWindow::onCmdQuit(FXObject*,FXSelector,void*){
568   FXTRACE((100,"Quit\n"));
569 
570   // Write new window size back to registry
571   getApp()->reg().writeIntEntry("SETTINGS","x",getX());
572   getApp()->reg().writeIntEntry("SETTINGS","y",getY());
573   getApp()->reg().writeIntEntry("SETTINGS","width",getWidth());
574   getApp()->reg().writeIntEntry("SETTINGS","height",getHeight());
575 
576   // Width of tree
577   getApp()->reg().writeIntEntry("SETTINGS","fileheight",filebox->getHeight());
578 
579   // Was file box shown
580   getApp()->reg().writeIntEntry("SETTINGS","filesshown",filebox->shown());
581 
582   FXString dir=filelist->getDirectory();
583   getApp()->reg().writeStringEntry("SETTINGS","directory",dir.text());
584 
585   // Quit
586   getApp()->exit(0);
587   return 1;
588   }
589 
590 
591 // Update title
onUpdTitle(FXObject * sender,FXSelector,void *)592 long ImageWindow::onUpdTitle(FXObject* sender,FXSelector,void*){
593   FXString caption="FOX Image Viewer:- " + filename;
594   FXImage* image=imageview->getImage();
595   if(image){ caption+=" (" + FXStringVal(image->getWidth()) + " x " + FXStringVal(image->getHeight()) + ")"; }
596   sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_SETSTRINGVALUE),(void*)&caption);
597   return 1;
598   }
599 
600 
601 // Open recent file
onCmdRecentFile(FXObject *,FXSelector,void * ptr)602 long ImageWindow::onCmdRecentFile(FXObject*,FXSelector,void* ptr){
603   filename=(FXchar*)ptr;
604   filelist->setCurrentFile(filename);
605   loadimage(filename);
606   return 1;
607   }
608 
609 
610 // Command from the tree list
onCmdFileList(FXObject *,FXSelector,void * ptr)611 long ImageWindow::onCmdFileList(FXObject*,FXSelector,void* ptr){
612   FXint index=(FXint)(FXival)ptr;
613   if(0<=index){
614     if(filelist->isItemDirectory(index)){
615       filelist->setDirectory(filelist->getItemPathname(index));
616       }
617     else if(filelist->isItemFile(index)){
618       filename=filelist->getItemPathname(index);
619       mrufiles.appendFile(filename);
620       loadimage(filename);
621       }
622     }
623   return 1;
624   }
625 
626 
627 // Rotate image
onCmdRotate(FXObject *,FXSelector sel,void *)628 long ImageWindow::onCmdRotate(FXObject*,FXSelector sel,void*){
629   FXImage* image=imageview->getImage();
630   FXASSERT(image);
631   switch(FXSELID(sel)){
632     case ID_ROTATE_90: image->rotate(90); break;
633     case ID_ROTATE_180: image->rotate(180); break;
634     case ID_ROTATE_270: image->rotate(270); break;
635     }
636   imageview->setImage(image);
637   return 1;
638   }
639 
640 
641 // Update image
onUpdImage(FXObject * sender,FXSelector,void *)642 long ImageWindow::onUpdImage(FXObject* sender,FXSelector,void*){
643   if(imageview->getImage())
644     sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_ENABLE),NULL);
645   else
646     sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_DISABLE),NULL);
647   return 1;
648   }
649 
650 
651 // Mirror
onCmdMirror(FXObject *,FXSelector sel,void *)652 long ImageWindow::onCmdMirror(FXObject*,FXSelector sel,void*){
653   FXImage* image=imageview->getImage();
654   FXASSERT(image);
655   switch(FXSELID(sel)){
656     case ID_MIRROR_HOR: image->mirror(TRUE,FALSE); break;
657     case ID_MIRROR_VER: image->mirror(FALSE,TRUE); break;
658     case ID_MIRROR_BOTH: image->mirror(TRUE,TRUE); break;
659     }
660   imageview->setImage(image);
661   return 1;
662   }
663 
664 
665 // Scale
onCmdScale(FXObject *,FXSelector,void *)666 long ImageWindow::onCmdScale(FXObject*,FXSelector,void*){
667   FXImage* image=imageview->getImage();
668   FXASSERT(image);
669   FXint sx=image->getWidth();
670   FXint sy=image->getHeight();
671   FXint sq=1;                   //: ADDED by Amanda Ross To reflect new feature since V1.1.32
672   FXDataTarget sxtarget(sx);
673   FXDataTarget sytarget(sy);
674   FXDataTarget sqtarget(sq);    //: ADDED by Amanda Ross To reflect new feature since V1.1.32
675   FXDialogBox  scalepanel(this,"Scale Image To Size");
676   FXHorizontalFrame* frame=new FXHorizontalFrame(&scalepanel,LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y);
677   new FXLabel(frame,"W:",NULL,LAYOUT_CENTER_Y);
678   new FXTextField(frame,5,&sxtarget,FXDataTarget::ID_VALUE,LAYOUT_CENTER_Y|FRAME_SUNKEN|FRAME_THICK|JUSTIFY_RIGHT);
679   new FXLabel(frame,"H:",NULL,LAYOUT_CENTER_Y);
680   new FXTextField(frame,5,&sytarget,FXDataTarget::ID_VALUE,LAYOUT_CENTER_Y|FRAME_SUNKEN|FRAME_THICK|JUSTIFY_RIGHT);
681   new FXLabel(frame,"Q:",NULL,LAYOUT_CENTER_Y); //: ADDED by Amanda Ross To reflect new feature since V1.1.32
682   FXSpinner *spinner=new FXSpinner(frame,2,&sqtarget,FXDataTarget::ID_VALUE,SPIN_NORMAL|FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_TOP);
683   spinner->setRange(0,1);
684   spinner->setValue(1);
685   new FXButton(frame,"Cancel",NULL,&scalepanel,FXDialogBox::ID_CANCEL,LAYOUT_CENTER_Y|FRAME_RAISED|FRAME_THICK,0,0,0,0, 20,20,4,4);
686   new FXButton(frame,"OK",NULL,&scalepanel,FXDialogBox::ID_ACCEPT,LAYOUT_CENTER_Y|FRAME_RAISED|FRAME_THICK,0,0,0,0, 30,30,4,4);
687   if(!scalepanel.execute()) return 1;
688   if(sx<1 || sy<1) return 1;
689   image->scale(sx,sy,FXCLAMP(0,sq,1));
690   imageview->setImage(image);
691   return 1;
692   }
693 
694 
695 // Crop
onCmdCrop(FXObject *,FXSelector,void *)696 long ImageWindow::onCmdCrop(FXObject*,FXSelector,void*){
697   FXImage* image=imageview->getImage();
698   FXASSERT(image);
699   FXint cx=0;
700   FXint cy=0;
701   FXint cw=image->getWidth();
702   FXint ch=image->getHeight();
703   FXDataTarget cxtarget(cx);
704   FXDataTarget cytarget(cy);
705   FXDataTarget cwtarget(cw);
706   FXDataTarget chtarget(ch);
707   FXDialogBox  croppanel(this,"Crop image");
708   FXHorizontalFrame* frame=new FXHorizontalFrame(&croppanel,LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y);
709   new FXLabel(frame,"X:",NULL,LAYOUT_CENTER_Y);
710   new FXTextField(frame,5,&cxtarget,FXDataTarget::ID_VALUE,LAYOUT_CENTER_Y|FRAME_SUNKEN|FRAME_THICK|JUSTIFY_RIGHT);
711   new FXLabel(frame,"Y:",NULL,LAYOUT_CENTER_Y);
712   new FXTextField(frame,5,&cytarget,FXDataTarget::ID_VALUE,LAYOUT_CENTER_Y|FRAME_SUNKEN|FRAME_THICK|JUSTIFY_RIGHT);
713   new FXLabel(frame,"W:",NULL,LAYOUT_CENTER_Y);
714   new FXTextField(frame,5,&cwtarget,FXDataTarget::ID_VALUE,LAYOUT_CENTER_Y|FRAME_SUNKEN|FRAME_THICK|JUSTIFY_RIGHT);
715   new FXLabel(frame,"H:",NULL,LAYOUT_CENTER_Y);
716   new FXTextField(frame,5,&chtarget,FXDataTarget::ID_VALUE,LAYOUT_CENTER_Y|FRAME_SUNKEN|FRAME_THICK|JUSTIFY_RIGHT);
717   new FXButton(frame,"Cancel",NULL,&croppanel,FXDialogBox::ID_CANCEL,LAYOUT_CENTER_Y|FRAME_RAISED|FRAME_THICK,0,0,0,0, 20,20,4,4);
718   new FXButton(frame,"OK",NULL,&croppanel,FXDialogBox::ID_ACCEPT,LAYOUT_CENTER_Y|FRAME_RAISED|FRAME_THICK,0,0,0,0, 30,30,4,4);
719   if(!croppanel.execute()) return 1;
720   if(cx+cw<=0 || cy+ch<=0 || cx>=image->getWidth() || cy>=image->getHeight()) return 1;
721   image->crop(cx,cy,cw,ch);
722   imageview->setImage(image);
723   return 1;
724   }
725 
726 
727 // Create and show window
create()728 void ImageWindow::create(){
729   FXint ww,hh,xx,yy,fh,fs;
730   FXString dir;
731 
732   // Get size
733   xx=getApp()->reg().readIntEntry("SETTINGS","x",600);
734   yy=getApp()->reg().readIntEntry("SETTINGS","y",400);
735   ww=getApp()->reg().readIntEntry("SETTINGS","width",600);
736   hh=getApp()->reg().readIntEntry("SETTINGS","height",400);
737 
738   fh=getApp()->reg().readIntEntry("SETTINGS","fileheight",100);
739   fs=getApp()->reg().readIntEntry("SETTINGS","filesshown",TRUE);
740 
741   dir=getApp()->reg().readStringEntry("SETTINGS","directory","~");
742   filelist->setDirectory(dir);
743 
744   filebox->setHeight(fh);
745 
746   // Hide tree if asked for
747   if(!fs) filebox->hide();
748 
749   // Reposition window
750   position(xx,yy,ww,hh);
751 
752   FXMainWindow::create();
753   show();
754   }
755 
756 
757 /*******************************************************************************/
758 
759 
760 // Start the whole thing
main(int argc,char * argv[])761 int main(int argc,char *argv[]){
762 
763   // Make application
764   FXApp application("ImageViewer","FoxTest");
765 
766   // Open display
767   application.init(argc,argv);
768 
769   // Make window
770   ImageWindow* window=new ImageWindow(&application);
771 
772   // Handle interrupt to save stuff nicely
773   application.addSignal(SIGINT,window,ImageWindow::ID_QUIT);
774 
775   // Create it
776   application.create();
777 
778   // Passed image file?
779   if(argc>1) window->loadimage(argv[1]);
780 
781   // Run
782   return application.run();
783   }
784 
785 
786