
------------------------------------------------------------------------
--# A simple, but fairly complete, image viewer.
-- Demonstrates Menus, FileChooser, FileFilters, Previews, etc.
-- Resizes images to fit the current window, shows statistics for 
-- selected image, with variable preview sizes available.

-- There's quite a bit of functionality here for only around 250 
-- lines of code!
------------------------------------------------------------------------

include GtkEngine.e
include GtkEvents.e
include std/filesys.e
include std/datetime.e
  
atom preview_max = 150  -- default size 
object fn = 0 -- current filename
sequence name, path

constant win = create(GtkWindow,
    "name=Main,title=`Simple Image Viewer`,size=500x400,position=1," &
    "$configure-event=ResizeWindow,$destroy=Quit")

constant group = create(GtkAccelGroup) -- for CTL-O, CTL-C, CTL-Q menu options
    set(win,"add accel group",group)

constant panel = create(GtkBox,"name=box,orientation=VERTICAL")
    gtk:add(win,panel)

constant menubar = create(GtkMenuBar) 
    pack(panel,menubar)

constant menu1 = create(GtkMenuItem,"_File"),
 filemenu = create(GtkMenu),
    fileopen = create(GtkMenuItem,"gtk-open",_("FileOpen"),0,{group,"<Ctl>o"}),
    fileclose = create(GtkMenuItem,"gtk-close",_("FileClose"),0,{group,"<Ctl>c"}),
    sep1 = create(GtkSeparatorMenuItem),
    fileexit = create(GtkMenuItem,"gtk-quit","Quit",0,{group,"<Ctl>q"})
    set(fileclose,"sensitive",FALSE)
    gtk:add(filemenu,{fileopen,fileclose,sep1,fileexit})
    set(menu1,"submenu",filemenu)
    gtk:add(menubar,menu1)

constant menu2 = create(GtkMenuItem,"_Help"),
  helpmenu = create(GtkMenu),
    helpabout = create(GtkMenuItem,"gtk-about#About",_("ShowAbout"),0,{group,"F1"}),
    helpinfo = create(GtkMenuItem,"gtk-info#Photo _Info",_("PixInfo"),0,{group,"F2"})
    
    set(helpabout,"add accelerator",{group,"<ctl>a"})
    set(helpinfo,"add accelerator",{group,"<ctl>i"})
	
    set(helpinfo,"sensitive",FALSE)
    set(helpabout,"tooltip text","About this program...")
    set(helpinfo,"tooltip text","About current photo")
    gtk:add(helpmenu,{helpabout,helpinfo})
    set(menu2,"submenu",helpmenu)
    gtk:add(menubar,menu2)
    
constant scrolwin = create(GtkScrolledWindow)
    pack(panel,scrolwin,1,1)
    
constant scroller = create(GtkViewport)
    gtk:add(scrolwin,scroller)

constant img = create(GtkImage)
    gtk:add(scroller,img)
    set(scroller,"border width",10)

-----------------------------------------------------------------
-- filters determine which types of files will be shown in the
-- file chooser dialog. No filter = show all files.
-----------------------------------------------------------------

constant imagetypes = {"gif","jpg","png","ico"}

constant filter1 = create(GtkFileFilter,{{"name","All Images"}})
    ifdef UNIX then 
	set(filter1,"add mime type","image/*")
    elsedef -- windows doesn't know mime types?
	for i = 1 to length(imagetypes)  do
	    set(filter1,"add pattern",sprintf("*.%s",{imagetypes[i]}))
	end for
    end ifdef
    
constant 
    filter2 = create(GtkFileFilter,"name=`JPEG images`,add_pattern=*.jpg"),
    filter3 = create(GtkFileFilter,"name=`GIF images`,add_pattern=*.gif"),
    filter4 = create(GtkFileFilter,"name=`PNG images`,add_pattern=*.png"),
    filter5 = create(GtkFileFilter,"name=`All files`,add_pattern=*")

constant dlg = create(GtkFileChooserDialog,{
    {"title","Select an image"},
    {"transient for",win},
    {"action",GTK_FILE_CHOOSER_ACTION_OPEN},
    {"local only",FALSE},
    {"select multiple",FALSE}})
	
gtk:add(dlg,{filter1,filter2,filter3,filter4,filter5})

constant sizer = create(GtkScale,{
    {"orientation",HORIZONTAL},
    {"range",64,512},
    {"increments",1},
    {"value",preview_max},
    {"draw value",FALSE},
    {"tooltip text",sprintf("Preview width %d px",preview_max)},
    {"connect","change-value",call_back(routine_id("ChangePreviewSize"))}})
    
constant action_area = get(dlg,"action area")
    gtk:add(action_area,sizer) show(sizer)
    set(dlg,"add button","gtk-cancel",MB_CANCEL)
    set(dlg,"add button","gtk-ok",MB_APPLY)
	
constant preview = create(GtkImage)
    set(dlg,"preview widget",preview)
  
-- call UpdatePreview whenever selection, filter, or folder changes.
    connect(dlg,"update-preview",_("UpdatePreview")) 

show_all(win)

-- try to find user's pictures folder via a call to a glib func:
ifdef WINDOWS then
	path = canonical_path("~\\Pictures")
end ifdef

ifdef OSX then
	-- FIXME OSX
end ifdef

ifdef LINUX then -- this function doesn't exist on Windows;
    path = gtk_str_func("g_get_user_special_dir",{S},
	{G_USER_DIRECTORY_PICTURES})
end ifdef

main()

------------------------------------------------------------------------
function FileOpen()
------------------------------------------------------------------------
object tmp
integer result 

    set(dlg,"current folder",path)
    result = get(dlg,"run") 
    switch result do
    
        case GTK_RESPONSE_APPLY then
        tmp = get(dlg,"filename")
        path = dirname(tmp)
        
        -- note: important to check to see that an actual file is selected, 
        if not atom(tmp) then -- if atom, no file was selected 
            fn = locate_file(tmp)
            if file_type(fn) = 1 then
		set(win,"title",filename(fn))
		set(fileclose,"sensitive",TRUE)
		ResizeWindow()
	    end if
        end if
        
    case GTK_RESPONSE_CANCEL then
        path = current_dir()
    end switch
    
    set(dlg,"hide")
    set(helpinfo,"sensitive",TRUE)
    
return 1
end function 

------------------------------------------------------------------------
function FileClose() -- remove image from view;
------------------------------------------------------------------------
    fn = 0
    set(img,"clear")
    set(win,"title","Image Viewer")
    set(fileopen,"sensitive",TRUE)
    set(fileclose,"sensitive",FALSE)
    set(helpinfo,"sensitive",FALSE)
return 1
end function

------------------------------------------------------------------------
global function UpdatePreview(atom ctl=0, atom event=0) -- as focus changes;
------------------------------------------------------------------------
object pix 
atom ratio
object dimensions 

object fn = get(dlg,"filename")  

if string(fn) then -- avoid trying to preview a directory!
	pix = create(GdkPixbuf,fn) 
	if pix > 0 then
	    dimensions = get(pix,"size") 
	    ratio = preview_max / dimensions[1]  
	    dimensions *= {ratio,ratio}
	    pix = set(pix,"scale simple",dimensions[1],dimensions[2],1)
	    set(preview,"from pixbuf",pix)
	    set(dlg,"preview widget active",TRUE)
	end if
end if

return 0
end function

------------------------------------------------------------------------
global function ResizeWindow() -- tries to fit the image into the window!
------------------------------------------------------------------------
object pix
object ratio 
sequence size
size = get(win,"size") - {30,50} -- allow for window border & header
pix = create(GdkPixbuf,fn,size[1],size[2],1) 
set(img,"from pixbuf",pix)
return 0
end function

------------------------------------------------------------------------
function ChangePreviewSize(atom ctl)
------------------------------------------------------------------------
    preview_max = to_integer(get(ctl,"value"))
    set(sizer,"tooltip text",sprintf("Preview width %d px",preview_max))
    UpdatePreview()
return 0
end function

------------------------------------------------------------------------
function ShowAbout()
------------------------------------------------------------------------
return Info(win," About ","Simple Image Viewer",
`Resize the main window,
 the image is expanded to fit.`,,"emblem-photos")
end function

------------------------------------------------------------------------
function PixInfo()
------------------------------------------------------------------------
atom w = allocate(8), h = allocate(8)

-- obtain size of the current image;
integer flen = file_length(fn)

-- obtain time & date file saved;
object tstamp = file_timestamp(fn)

-- get more info by obtaining a a file_info structure from the filename;
object info = gtk_func("gdk_pixbuf_get_file_info",{P,I,I},{allocate_string(fn,1),w,h}) 
    w = peek4u(w) h = peek4u(h)

-- get image format (jpg, gif, etc...) from the info structure;
object fmt = peek_string(peek4u(info))

-- create an icon for the Info box using the current image;
Pixbuf pix = create(GdkPixbuf,fn,90,0,1)

Info(win,"File Info", -- show as much info about the selected image as possible;
    text:format("File: []\n",{filename(fn)}),
    text:format("Folder: []\nFormat: []\nWidth: []px, Height: []px\nSize: [,,] bytes",
        {path,fmt,w,h,flen}) &
    datetime:format(tstamp,"\nDate: %a, %d %b %Y"),,pix,128)
    
return 1
end function

