------------------------------------------------------------------------ --# 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,"o"}), fileclose = create(GtkMenuItem,"gtk-close",_("FileClose"),0,{group,"c"}), sep1 = create(GtkSeparatorMenuItem), fileexit = create(GtkMenuItem,"gtk-quit","Quit",0,{group,"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,"a"}) set(helpinfo,"add accelerator",{group,"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