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