2007-08-21 13:40:19 +04:00
/*
* $ Id $
*
* EImage - EDE Image Viewer
* Part of Equinox Desktop Environment ( EDE ) .
* Copyright ( c ) 2006 - 2007 EDE Authors .
*
* This program is licenced under terms of the
* GNU General Public Licence version 2 or newer .
* See COPYING for details .
*/
2007-06-25 13:21:48 +04:00
# include <Fl/Fl.h>
# include <Fl/Fl_Window.h>
# include <Fl/Fl_Button.h>
# include <Fl/Fl_Shared_Image.h>
# include <Fl/Fl_Scroll.h>
# include <Fl/Fl_Widget.h>
# include <Fl/Fl_File_Chooser.h>
# include <Fl/filename.h>
2006-08-20 22:43:09 +04:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
2007-06-25 13:21:48 +04:00
# include <sys/stat.h>
2007-08-21 13:26:40 +04:00
# include <errno.h>
2006-08-20 22:43:09 +04:00
2007-06-25 13:21:48 +04:00
# define DEBUG 1
2006-08-20 22:43:09 +04:00
2007-08-21 13:26:40 +04:00
// Can this be moved to Jamfile/configure?
//#define USE_EDELIB
# ifdef USE_EDELIB
# include <edelib/Nls.h>
# else
# define _(stuff) stuff
# endif
2006-08-20 22:43:09 +04:00
2007-06-25 13:21:48 +04:00
// Supported image types
const char * supported [ ] = { " bm " , " bmp " , " gif " , " jpg " , " pbm " , " pgm " , " png " , " ppm " , " xbm " , " xpm " , 0 } ;
2006-08-20 22:43:09 +04:00
2007-06-25 13:21:48 +04:00
// Global variables used everywhere
char filename [ FL_PATH_MAX ] , directory [ FL_PATH_MAX ] ;
Fl_Window * w ;
2006-08-20 22:43:09 +04:00
float zoomfactor ;
bool autozoom = false ;
2007-06-25 13:21:48 +04:00
Fl_Shared_Image * im ;
class ScrolledImage ;
ScrolledImage * s ;
2006-08-20 22:43:09 +04:00
2007-06-25 13:21:48 +04:00
// Directory list cache used in prevnext()
2006-08-20 22:43:09 +04:00
dirent * * files ;
int nfiles ;
2007-06-25 13:21:48 +04:00
// Forward declaration of funcs for use from callbacks
2006-08-20 22:43:09 +04:00
void nextpic ( ) ;
void prevpic ( ) ;
void loadimage ( ) ;
void newdir ( ) ;
2007-06-25 13:21:48 +04:00
// Callbacks for main menu
void next_cb ( Fl_Widget * , void * ) { nextpic ( ) ; }
void prev_cb ( Fl_Widget * , void * ) { prevpic ( ) ; }
void open_cb ( Fl_Widget * , void * ) {
// construct filename filter
char filter [ FL_PATH_MAX ] ;
2007-08-21 13:26:40 +04:00
snprintf ( filter , FL_PATH_MAX , " %s(*.{%s " , _ ( " Image files " ) , supported [ 0 ] ) ; // splitted for easier localization
2007-06-25 13:21:48 +04:00
for ( int i = 1 ; supported [ i ] ; i + + )
snprintf ( filter , FL_PATH_MAX , " %s,%s " , filter , supported [ i ] ) ;
snprintf ( filter , FL_PATH_MAX , " %s}) " , filter ) ;
2007-08-21 13:26:40 +04:00
const char * f = fl_file_chooser ( _ ( " Choose image or directory " ) , filter , directory ) ;
2006-08-20 22:43:09 +04:00
if ( ! f ) return ;
2007-06-25 13:21:48 +04:00
strncpy ( filename , f , FL_PATH_MAX ) ;
2006-08-20 22:43:09 +04:00
newdir ( ) ;
loadimage ( ) ;
}
2007-06-25 13:21:48 +04:00
void manage_cb ( Fl_Widget * b , void * ) { } // call file manager
void fullscreen_cb ( Fl_Widget * b , void * ) {
2006-08-20 22:43:09 +04:00
static bool isfull = false ;
static int X , Y , W , H ;
if ( isfull ) {
w - > fullscreen_off ( X , Y , W , H ) ;
isfull = false ;
} else {
X = w - > x ( ) ; Y = w - > y ( ) ; W = w - > w ( ) ; H = w - > h ( ) ;
w - > fullscreen ( ) ;
isfull = true ;
}
}
2007-06-25 13:21:48 +04:00
void zoomin_cb ( Fl_Widget * b , void * ) {
2006-08-20 22:43:09 +04:00
if ( zoomfactor > = 1 ) zoomfactor + = 0.2 ; else zoomfactor + = zoomfactor / 5 ;
autozoom = false ;
loadimage ( ) ;
}
2007-06-25 13:21:48 +04:00
void zoomout_cb ( Fl_Widget * b , void * ) {
2006-08-20 22:43:09 +04:00
if ( zoomfactor > = 1 ) zoomfactor - = 0.2 ; else zoomfactor - = zoomfactor / 5 ;
autozoom = false ;
loadimage ( ) ;
}
2007-06-25 13:21:48 +04:00
void zoomrestore_cb ( Fl_Widget * b , void * ) { zoomfactor = 1 ; autozoom = false ; loadimage ( ) ; }
void zoomauto_cb ( Fl_Widget * b , void * ) { autozoom = ! autozoom ; loadimage ( ) ; }
void about_cb ( Fl_Widget * b , void * ) { } // about window
void exit_cb ( Fl_Widget * b , void * ) { exit ( 0 ) ; }
// Main popup menu
Fl_Menu_Item mainmenu [ ] = {
2007-08-21 13:26:40 +04:00
{ _ ( " &Open " ) , FL_CTRL + ' o ' , open_cb } ,
{ _ ( " &Manage " ) , 0 , manage_cb , 0 , FL_MENU_DIVIDER } ,
2007-06-25 13:21:48 +04:00
2007-08-21 13:26:40 +04:00
{ _ ( " &Previous " ) , FL_Page_Up , prev_cb } ,
{ _ ( " &Next " ) , FL_Page_Down , next_cb , 0 , FL_MENU_DIVIDER } ,
2007-06-25 13:21:48 +04:00
2007-08-21 13:26:40 +04:00
{ _ ( " &Zoom in " ) , ' + ' , zoomin_cb } ,
{ _ ( " Zoom &out " ) , ' - ' , zoomout_cb } ,
{ _ ( " Zoom &auto " ) , FL_CTRL + ' a ' , zoomauto_cb } ,
{ _ ( " &Restore " ) , ' / ' , zoomrestore_cb , 0 , FL_MENU_DIVIDER } ,
2007-06-25 13:21:48 +04:00
2007-08-21 13:26:40 +04:00
{ _ ( " &Fullscreen " ) , FL_F + 11 , fullscreen_cb , 0 , FL_MENU_DIVIDER } ,
2007-06-25 13:21:48 +04:00
2007-08-21 13:26:40 +04:00
{ _ ( " A&bout " ) , 0 , about_cb } ,
{ _ ( " &Exit " ) , FL_Escape , exit_cb } ,
2007-06-25 13:21:48 +04:00
{ 0 }
} ;
2006-08-20 22:43:09 +04:00
2007-06-25 13:21:48 +04:00
class ScrolledImage : public Fl_Scroll {
2006-08-20 22:43:09 +04:00
private :
2007-06-25 13:21:48 +04:00
Fl_Box * b ;
Fl_Menu_Button * mb ;
2006-08-20 22:43:09 +04:00
public :
2007-06-25 13:21:48 +04:00
ScrolledImage ( int x , int y , int w , int h , const char * l = 0 )
: Fl_Scroll ( x , y , w , h , l ) {
align ( FL_ALIGN_INSIDE | FL_ALIGN_CENTER ) ;
begin ( ) ;
2006-08-20 22:43:09 +04:00
2007-06-25 13:21:48 +04:00
b = new Fl_Box ( w / 2 , h / 2 , 0 , 0 ) ;
2006-08-20 22:43:09 +04:00
2007-06-25 13:21:48 +04:00
mb = new Fl_Menu_Button ( 0 , 0 , 0 , 0 , " " ) ;
mb - > type ( Fl_Menu_Button : : POPUP3 ) ;
mb - > menu ( 0 ) ;
2007-08-21 13:26:40 +04:00
mb - > box ( FL_NO_BOX ) ;
2006-08-20 22:43:09 +04:00
2007-06-25 13:21:48 +04:00
end ( ) ;
redraw ( ) ;
2006-08-20 22:43:09 +04:00
}
2007-06-25 13:21:48 +04:00
void image ( Fl_Image * a ) { b - > image ( a ) ; }
void image ( Fl_Image & a ) { b - > image ( a ) ; }
Fl_Image * image ( ) { return b - > image ( ) ; }
void label ( const char * a ) {
if ( a ) resizebox ( 0 , 0 ) ; // center label
b - > label ( a ) ;
2006-08-20 22:43:09 +04:00
}
2007-06-25 13:21:48 +04:00
// Resize the box containing image
void resizebox ( int W , int H ) {
int X = 0 , Y = 0 ;
int aw = w ( ) - scrollbar . w ( ) ; int ah = h ( ) - hscrollbar . h ( ) ;
if ( aw > W ) X = ( aw - W ) / 2 ;
if ( ah > H ) Y = ( ah - H ) / 2 ;
b - > resize ( X , Y , W , H ) ;
2006-08-20 22:43:09 +04:00
}
2007-06-25 13:21:48 +04:00
void resize ( int x , int y , int w , int h ) {
Fl_Scroll : : resize ( x , y , w , h ) ;
resizebox ( b - > w ( ) , b - > h ( ) ) ; // refresh image position
redraw ( ) ;
2006-08-20 22:43:09 +04:00
}
2007-06-25 13:21:48 +04:00
virtual int handle ( int event ) {
if ( event = = FL_PUSH ) {
if ( Fl : : event_button ( ) = = 3 & & mb - > menu ( ) ! = 0 ) {
mb - > popup ( ) ;
return 1 ;
}
}
// sometimes PgUp and PgDown aren't handled
else if ( event = = FL_SHORTCUT & & mb - > menu ( ) ! = 0 ) {
int key = Fl : : event_key ( ) ;
if ( key = = FL_Page_Up | | key = = FL_Page_Down )
return mb - > handle ( event ) ;
}
return Fl_Scroll : : handle ( event ) ;
2006-08-20 22:43:09 +04:00
}
2007-06-25 13:21:48 +04:00
void setmenu ( Fl_Menu_Item * menu ) {
if ( menu ! = 0 ) {
mb - > menu ( menu ) ;
2006-08-20 22:43:09 +04:00
}
}
} ;
2007-06-25 13:21:48 +04:00
2006-08-20 22:43:09 +04:00
// Directory changed, get new directory from filename
void newdir ( ) {
int p = 0 ;
2007-08-21 13:26:40 +04:00
for ( uint i = 0 ; i < strlen ( filename ) ; i + + )
2006-08-20 22:43:09 +04:00
if ( filename [ i ] = = ' / ' ) p = i ;
// There must be at least one '/'
strncpy ( directory , filename , p ) ;
directory [ p ] = ' \0 ' ;
// make prevnext() reread directory
nfiles = 0 ;
}
// Load the image given in char[] filename
void loadimage ( ) {
2007-06-25 13:21:48 +04:00
char tmp [ FL_PATH_MAX ] ; // the string buffer
if ( DEBUG ) fprintf ( stderr , " Loadimage() - file: %s \n " , filename ) ;
2006-08-20 22:43:09 +04:00
// Load image
2007-06-25 13:21:48 +04:00
if ( im ) { im - > release ( ) ; im = 0 ; }
im = Fl_Shared_Image : : get ( filename ) ; // image type is autodetected now
if ( ! im ) {
if ( DEBUG ) fprintf ( stderr , " Fl_Shared_Image::get() failed! \n " ) ;
s - > image ( 0 ) ;
2007-08-21 13:26:40 +04:00
snprintf ( tmp , FL_PATH_MAX , _ ( " Can't load image %s \n " ) , filename ) ;
s - > copy_label ( tmp ) ;
2007-06-25 13:21:48 +04:00
s - > redraw ( ) ;
return ;
}
// Measure image
int realw = im - > w ( ) , realh = im - > h ( ) ;
int scaledw , scaledh ;
2006-08-20 22:43:09 +04:00
if ( autozoom ) {
2007-06-25 13:21:48 +04:00
// Adjust zoom factor so picture fits inside window
// When user switches to manual zooming, this factor will remain
float fw = ( float ) s - > w ( ) / realw ; float fh = ( float ) s - > h ( ) / realh ;
if ( fw < fh ) zoomfactor = fw ; else zoomfactor = fh ;
2006-08-20 22:43:09 +04:00
}
2007-06-25 13:21:48 +04:00
// Resample image to new size
2007-08-21 13:26:40 +04:00
scaledw = int ( realw * zoomfactor ) ;
scaledh = int ( realh * zoomfactor ) ;
2007-06-25 13:21:48 +04:00
if ( zoomfactor ! = 1 ) {
Fl_Image * temp = im - > copy ( scaledw , scaledh ) ;
im = ( Fl_Shared_Image * ) temp ;
}
2006-08-20 22:43:09 +04:00
2007-06-25 13:21:48 +04:00
// Set image
s - > resizebox ( scaledw , scaledh ) ;
s - > image ( im ) ;
2006-08-20 22:43:09 +04:00
2007-06-25 13:21:48 +04:00
s - > label ( 0 ) ; // clear any previous labels
s - > redraw ( ) ;
2006-08-20 22:43:09 +04:00
2007-06-25 13:21:48 +04:00
// set window title
2006-08-20 22:43:09 +04:00
if ( zoomfactor = = 1 )
2007-08-21 13:26:40 +04:00
snprintf ( tmp , FL_PATH_MAX , " %s (%dx%d) - %s " , fl_filename_name ( filename ) , realw , realh , _ ( " View picture " ) ) ; // splitted for easier localization
2006-08-20 22:43:09 +04:00
else
2007-08-21 13:26:40 +04:00
snprintf ( tmp , FL_PATH_MAX , " %s (%dx%d) - %s %1.1fx - %s " , fl_filename_name ( filename ) , realw , realh , _ ( " zoom " ) , zoomfactor , _ ( " View picture " ) ) ;
2006-08-20 22:43:09 +04:00
w - > label ( strdup ( tmp ) ) ;
}
2007-06-25 13:21:48 +04:00
// Get next/previous picture file in directory
// (universal func. to be called from nextpic() and prevpic() )
2006-08-20 22:43:09 +04:00
void prevnext ( int direction ) {
2007-06-25 13:21:48 +04:00
char tmp [ FL_PATH_MAX ] ; // the string buffer
if ( DEBUG )
fprintf ( stderr , " Prevnext() - file: %s dir: %s direction: %d \n " , filename , directory , direction ) ;
2006-08-20 22:43:09 +04:00
if ( nfiles = = 0 ) { // read directory
2007-06-25 13:21:48 +04:00
nfiles = fl_filename_list ( directory , & files ) ;
2006-08-20 22:43:09 +04:00
}
// Select next picture after current
bool found = false ;
2007-06-25 13:21:48 +04:00
if ( filename [ 0 ] ) {
const char * justname = fl_filename_name ( filename ) ;
// this basically means: if direction is 1 go from first to last, else from last to first
for ( int i = ( direction ? 0 : nfiles - 1 ) ; ( direction ? i < nfiles : i > = 0 ) ; i + = ( direction ? 1 : - 1 ) ) {
if ( strncmp ( justname , files [ i ] - > d_name , FL_PATH_MAX ) = = 0 ) {
found = true ;
continue ; // skip to next file
}
if ( found ) {
for ( int j = 0 ; supported [ j ] ; j + + ) {
snprintf ( tmp , FL_PATH_MAX , " *.%s " , supported [ j ] ) ;
if ( fl_filename_match ( files [ i ] - > d_name , tmp ) ) {
snprintf ( filename , FL_PATH_MAX , " %s/%s " , directory , files [ i ] - > d_name ) ;
loadimage ( ) ;
return ;
}
2006-08-20 22:43:09 +04:00
}
}
}
}
2007-06-25 13:21:48 +04:00
if ( found ) { //this means that the current picture is the last/first in directory
if ( im ) { im - > release ( ) ; im = 0 ; }
s - > image ( 0 ) ;
filename [ 0 ] = 0 ;
if ( direction )
2007-08-21 13:26:40 +04:00
s - > label ( _ ( " This was the last picture. \n Press 'Next' again for first one. " ) ) ;
2007-06-25 13:21:48 +04:00
else
2007-08-21 13:26:40 +04:00
s - > label ( _ ( " This was the first picture. \n Press 'Previous' again for last one. " ) ) ;
2007-06-25 13:21:48 +04:00
s - > redraw ( ) ;
return ;
} else {
// Just give first (or last) picture in directory
for ( int i = ( direction ? 0 : nfiles - 1 ) ; ( direction ? i < nfiles : i > = 0 ) ; i + = ( direction ? 1 : - 1 ) ) {
for ( int j = 0 ; supported [ j ] ; j + + ) {
snprintf ( tmp , FL_PATH_MAX , " *.%s " , supported [ j ] ) ;
if ( fl_filename_match ( files [ i ] - > d_name , tmp ) ) {
snprintf ( filename , FL_PATH_MAX , " %s/%s " , directory , files [ i ] - > d_name ) ;
loadimage ( ) ;
return ;
}
2006-08-20 22:43:09 +04:00
}
}
}
// Nothing found...
2007-06-25 13:21:48 +04:00
if ( DEBUG ) fprintf ( stderr , " Nextpic() - nothing found \n " ) ;
if ( im ) { im - > release ( ) ; im = 0 ; }
s - > image ( 0 ) ;
filename [ 0 ] = 0 ;
2007-08-21 13:26:40 +04:00
snprintf ( tmp , FL_PATH_MAX , _ ( " No pictures in directory %s " ) , directory ) ;
2007-06-25 13:21:48 +04:00
s - > label ( strdup ( tmp ) ) ;
s - > redraw ( ) ;
2006-08-20 22:43:09 +04:00
// Window title
2007-08-21 13:26:40 +04:00
snprintf ( tmp , FL_PATH_MAX , _ ( " View picture - nothing found in %s " ) , directory ) ;
2006-08-20 22:43:09 +04:00
w - > label ( strdup ( tmp ) ) ;
}
void nextpic ( ) { prevnext ( 1 ) ; }
void prevpic ( ) { prevnext ( 0 ) ; }
int main ( int argc , char * * argv ) {
2007-08-21 13:26:40 +04:00
// Parse command line - this must come first
int unknown = 0 ;
Fl : : args ( argc , argv , unknown ) ;
filename [ 0 ] = ' \0 ' ; directory [ 0 ] = ' \0 ' ;
if ( unknown = = argc )
snprintf ( directory , FL_PATH_MAX , getenv ( " HOME " ) ) ;
else {
if ( strcmp ( argv [ unknown ] , " --help " ) = = 0 ) {
printf ( _ ( " EImage - EDE Image Viewer \n Part of Equinox Desktop Environment (EDE). \n Copyright (c) 2000-2007 EDE Authors. \n \n This program is licenced under terms of the \n GNU General Public Licence version 2 or newer. \n See COPYING for details. \n \n " ) ) ;
printf ( _ ( " Usage: \n \t eimage [OPTIONS] [IMAGE_FILE] \n \n " ) ) ;
printf ( _ ( " Available options: \n %s \n " ) , Fl : : help ) ;
return 1 ;
}
if ( fl_filename_isdir ( argv [ unknown ] ) ) { // Param is directory
snprintf ( directory , FL_PATH_MAX , argv [ unknown ] ) ;
if ( directory [ 0 ] = = ' ~ ' & & directory [ 1 ] = = ' / ' ) // expand home dir
snprintf ( directory , FL_PATH_MAX , " %s%s " , getenv ( " HOME " ) , argv [ unknown ] + 1 ) ;
else if ( directory [ 0 ] ! = ' / ' ) // relative path
snprintf ( directory , FL_PATH_MAX , " %s/%s " , getenv ( " PWD " ) , argv [ unknown ] ) ;
} else {
snprintf ( filename , FL_PATH_MAX , argv [ unknown ] ) ;
if ( filename [ 0 ] = = ' ~ ' & & filename [ 1 ] = = ' / ' ) // expand home dir
snprintf ( filename , FL_PATH_MAX , " %s%s " , getenv ( " HOME " ) , argv [ unknown ] + 1 ) ;
else if ( filename [ 0 ] ! = ' / ' ) // relative filename
snprintf ( filename , FL_PATH_MAX , " %s/%s " , getenv ( " PWD " ) , argv [ unknown ] ) ;
newdir ( ) ; // rebuild char[] directory from filename
}
}
zoomfactor = 1 ; im = 0 ; // defaults
2007-06-25 13:21:48 +04:00
fl_register_images ( ) ;
2007-08-21 13:26:40 +04:00
FL_NORMAL_SIZE = 12 ;
fl_message_font ( FL_HELVETICA , 12 ) ;
2007-06-25 13:21:48 +04:00
// Main window
2007-08-21 13:26:40 +04:00
w = new Fl_Window ( 400 , 200 , _ ( " View picture " ) ) ;
s = new ScrolledImage ( 0 , 0 , 400 , 200 ) ;
2007-06-25 13:21:48 +04:00
s - > color ( 33 ) ;
s - > labelcolor ( FL_WHITE ) ;
s - > setmenu ( mainmenu ) ;
w - > resizable ( s ) ;
2006-08-20 22:43:09 +04:00
w - > end ( ) ;
2007-06-25 13:21:48 +04:00
w - > align ( FL_ALIGN_INSIDE | FL_ALIGN_CENTER ) ;
2007-08-21 13:26:40 +04:00
// Check that file exists and open
struct stat mstat ;
char tmp [ FL_PATH_MAX ] ;
if ( ! filename [ 0 ] ) { // Load directory
if ( stat ( directory , & mstat ) ! = 0 ) {
snprintf ( tmp , FL_PATH_MAX , _ ( " Directory not found: \n %s " ) , directory ) ;
2007-06-25 13:21:48 +04:00
s - > label ( tmp ) ;
2007-08-21 13:26:40 +04:00
} else
nextpic ( ) ;
} else {
if ( stat ( filename , & mstat ) ! = 0 ) {
snprintf ( tmp , FL_PATH_MAX , _ ( " File not found: \n %s " ) , filename ) ;
s - > label ( tmp ) ;
} else
2006-08-20 22:43:09 +04:00
loadimage ( ) ;
}
2007-06-25 13:21:48 +04:00
// Resize window to image size or screen
2007-08-21 13:26:40 +04:00
int W , H ;
if ( im ) { // skip if file not found
if ( im - > w ( ) > Fl : : w ( ) ) W = Fl : : w ( ) ; else W = im - > w ( ) ;
if ( im - > h ( ) > Fl : : h ( ) ) H = Fl : : h ( ) ; else H = im - > h ( ) ;
w - > resize ( 0 , 0 , W , H ) ;
}
2007-06-25 13:21:48 +04:00
// Window manager should make sure that window is fully visible
2006-08-20 22:43:09 +04:00
w - > show ( argc , argv ) ;
2007-06-25 13:21:48 +04:00
return Fl : : run ( ) ;
2006-08-20 22:43:09 +04:00
}