"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "f.gallery.cc" between
fotoxx-23.0.tar.gz and fotoxx-23.1.tar.gz

About: fotoxx is a program for photo editing and collection management.

f.gallery.cc  (fotoxx-23.0):f.gallery.cc  (fotoxx-23.1)
/******************************************************************************* * /******************************************************************************* *
Fotoxx edit photos and manage collections Fotoxx - edit photos and manage collections
Copyright 2007-2023 Michael Cornelison Copyright 2007-2023 Michael Cornelison
source code URL: https://kornelix.net source code URL: https://kornelix.net
contact: mkornelix@gmail.com contact: mkornelix@gmail.com
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. See https://www.gnu.org/licenses (at your option) any later version. See https://www.gnu.org/licenses
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details. See the GNU General Public License for more details.
******************************************************************************** * ******************************************************************************** *
Fotoxx image edit - folder navigation and thumbnail gallery functions Fotoxx image edit - folder navigation and thumbnail gallery functions
gallery create/update/search/paint an image gallery gallery() create/update/search/paint an image gallery
navi:: navi::
gallery_comp gallery sort compare function gallery_comp gallery sort compare function
filename_comp gallery sort file name compare function filename_comp gallery sort file name compare function
gallery_paint paint thumbnail gallery, resizable thumbnails gallery_paint paint thumbnail gallery, resizable thumbnails
gallery_paintmeta same, metadata report from search function gallery_paintmeta same, metadata report from search function
gallery_paintmeta2 same, thumbnails with basic metadata gallery_paintmeta2 same, thumbnails with basic metadata
dir_filecount paint - get folder subdir and image file counts dir_filecount paint - get folder subdir and image file counts
draw_text paint - write text over thumbnail images draw_text paint - write text over thumbnail images
gallery_navibutts add folder navigation buttons gallery_navibutts add folder navigation buttons
skipping to change at line 96 skipping to change at line 96
******************************************************************************** */ ******************************************************************************** */
#define EX extern // disable extern declarations #define EX extern // disable extern declarations
#include "fotoxx.h" // (variables in fotoxx.h are refs) #include "fotoxx.h" // (variables in fotoxx.h are refs)
/******************************************************************************* */ /******************************************************************************* */
/*** gallery index in fotoxx.h /*** gallery index in fotoxx.h
typedef struct { current gallery file list in memory typedef struct { current gallery file list in memory
char *file; /folder.../filename ch *file; /folder.../filename
char fdate[16]; file date: yyyymmddhhmmss int folder; flag, file is a folder
char pdate[16]; photo date: yyyymmddhhmmss ch fdate[16]; file date: yyyymmddhhmmss
ch pdate[16]; photo date: yyyymmddhhmmss
int fsize; file size, bytes int fsize; file size, bytes
int psize; image size, pixels int psize; image size, pixels
char *mdata; metadata (text) ch *mdata; metadata (text)
} Gindex_t; } Gindex_t;
***/ ***/
namespace navi namespace navi
{ {
#define maxgallerylevs 60 // max gallery navigation levels #define maxgallerylevs 60 // max gallery navigation levels
#define TEXTWIN GTK_TEXT_WINDOW_TEXT // GDK window of GTK text view #define TEXTWIN GTK_TEXT_WINDOW_TEXT // GDK window of GTK text view
#define NEVER GTK_POLICY_NEVER #define NEVER GTK_POLICY_NEVER
#define ALWAYS GTK_POLICY_ALWAYS #define ALWAYS GTK_POLICY_ALWAYS
skipping to change at line 124 skipping to change at line 125
int fontx[5] = { 0, -1, -1, -2, -3 }; // font size wrt appfont int fontx[5] = { 0, -1, -1, -2, -3 }; // font size wrt appfont
Gindex_t *Gindex = 0; // gallery index Gindex_t *Gindex = 0; // gallery index
int GFlock = 0; // gallery index lock int GFlock = 0; // gallery index lock
int TClock = 0; // thumbnail cache lock int TClock = 0; // thumbnail cache lock
int Gfiles = 0; // gallery files (incl. subfolders) int Gfiles = 0; // gallery files (incl. subfolders)
int Gfolders = 0; // gallery subfolder count int Gfolders = 0; // gallery subfolder count
int Gimages = 0; // gallery image file count int Gimages = 0; // gallery image file count
int preload_trigger = 0; // kick preload_thumb() thread int preload_trigger = 0; // kick preload_thumb() thread
int preload_start = 0; // 1st file in gallery to check int preload_start = 0; // 1st file in gallery to check
int Gmdrows = 0; // text rows in metadata list int Gmdrows = 0; // text rows in metadata list
char *galleryname = 0; // folder or file list name ch *galleryname = 0; // folder or file list name
GTYPE gallerytype; // gallery type: folder, recent, etc. GTYPE gallerytype; // gallery type: folder, recent, etc.
GSORT gallerysort; // gallery sort: f.name, f.date, p.date GSORT gallerysort; // gallery sort: f.name, f.date, p.date
GSEQ galleryseq; // gallery sort: ascending/descending GSEQ galleryseq; // gallery sort: ascending/descending
int galleryposn = 0; // scroll-to file position (Nth) int galleryposn = 0; // scroll-to file position (Nth)
int Fthumbview = 1; // gallery view mode 1/2 = normal/metadata int Fthumbview = 1; // gallery view mode 1/2 = normal/metadata
GtkWidget *gallerybutt[60]; // gallery navi buttons [aaa] [bbb] ... GtkWidget *gallerybutt[60]; // gallery navi buttons [aaa] [bbb] ...
char *gallerypath[60]; // corresp. folder names aaa bbb ... ch *gallerypath[60]; // corresp. folder names aaa bbb ...
GtkWidget *gallerylabel = 0; // gallery label (album name ...) GtkWidget *gallerylabel = 0; // gallery label (album name ...)
int gallerypainted = 0; // gallery is finished painting int gallerypainted = 0; // gallery is finished painting
int xwinW, xwinH; // gallery window current size int xwinW, xwinH; // gallery window current size
int thumbsize = 256; // initial thumbnail image size int thumbsize = 256; // initial thumbnail image size
int thumbW, thumbH; // gallery window thumbnail cell size int thumbW, thumbH; // gallery window thumbnail cell size
int fontsize = 10; // font size for gallery text int fontsize = 10; // font size for gallery text
int texthh; // vertical space req. for metadata text int texthh; // vertical space req. for metadata text
int xrows, xcols; // gallery window thumbnail rows, cols int xrows, xcols; // gallery window thumbnail rows, cols
int margin = 5; // cell margin from left and top edge int margin = 5; // cell margin from left and top edge
int genthumbs = 0; // count newly generated thumbnails int genthumbs = 0; // count newly generated thumbnails
int scrollposn = 0; // scroll position int scrollposn = 0; // scroll position
int maxscroll; // max. scroll position int maxscroll; // max. scroll position
char *drag_file = 0; // selected thumbnail (file) ch *drag_file = 0; // selected thumbnail (file)
int drag_posn = -1; // drag from position int drag_posn = -1; // drag from position
int gallery_scrollgoal = -1; // gallery scroll goal position int gallery_scrollgoal = -1; // gallery scroll goal position
int gallery_scrollspeed = 0; // gallery scroll speed pixels/second int gallery_scrollspeed = 0; // gallery scroll speed pixels/second
// private functions // private functions
int gallery_comp(cchar *rec1, cchar *rec2); int gallery_comp(ch *rec1, ch *rec2);
// gallery record compare for sort options // gallery record compare for sort options
int filename_comp(char *file1, char *file2); int filename_comp(ch *file1, ch *file2);
// special file name compare function // special file name compare function
int gallery_paint(GtkWidget *, cairo_t *); // gallery window paint, resizable thumbnails int gallery_paint(GtkWidget *, cairo_t *); // gallery window paint, resizable thumbnails
int gallery_paintmeta(GtkWidget *Gdrawin, cairo_t *cr); // same, metadata report from search func. int gallery_paintmeta(GtkWidget *Gdrawin, cairo_t *cr); // same, metadata report from search func.
int gallery_paintmeta2(GtkWidget *Gdrawin, cairo_t *cr); // same, thumbnails with basic metadata int gallery_paintmeta2(GtkWidget *Gdrawin, cairo_t *cr); // same, thumbnails with basic metadata
void dir_filecount(char *dirname, int &ndir, int &nfil); void dir_filecount(ch *dirname, int &ndir, int &nfil);
// get subdir and image file counts // get subdir and image file counts
void draw_text(cairo_t *cr, char *text, int x, int y, int ww); void draw_text(cairo_t *cr, ch *text, int x, int y, int ww);
// draw text in gallery window // draw text in gallery window
void gallery_navibutts(); // create navigation buttons in top panel void gallery_navibutts(); // create navigation buttons in top panel
void menufuncx(GtkWidget *, cchar *menu); // function for gallery window buttons void menufuncx(GtkWidget *, ch *menu); // function for gallery window buttons
void gallery_scroll(int position, int speed); // start gallery slow scroll to position void gallery_scroll(int position, int speed); // start gallery slow scroll to position
int gallery_scrollfunc(void *); // gallery scroll timer function int gallery_scrollfunc(void *); // gallery scroll timer function
void navibutt_clicked(GtkWidget *, int *level); // set gallery via click navigation button void navibutt_clicked(GtkWidget *, int *level); // set gallery via click navigation button
void newtop(GtkWidget *widget, GdkEventButton *event); // function for [TOP] button void newtop(GtkWidget *widget, GdkEventButton *event); // function for [TOP] button
void newtop_menu_event(GtkWidget *, cchar *); // [TOP] menu response function void newtop_menu_event(GtkWidget *, ch *); // [TOP] menu response function
void newalbum(GtkWidget *widget, GdkEventButton *event); // function for [Album] button void newalbum(GtkWidget *widget, GdkEventButton *event); // function for [Album] button
void newalbum_menu_event(GtkWidget *, cchar *); // [Album] menu response function void newalbum_menu_event(GtkWidget *, ch *); // [Album] menu response function
int mouse_event(GtkWidget *widget, GdkEvent *event, void *); // gallery window mouse event function int mouse_event(GtkWidget *widget, GdkEvent *event, void *); // gallery window mouse event function
char * gallery_dragfile(); ch * gallery_dragfile();
// start drag-drop, set the file // start drag-drop, set the file
void gallery_dropfile(int mousex, int mousey, char *file); void gallery_dropfile(int mousex, int mousey, ch *file);
// accept drag-drop file at position // accept drag-drop file at position
int KBpress(GtkWidget *, GdkEventKey *, void *); // gallery window key press event int KBpress(GtkWidget *, GdkEventKey *, void *); // gallery window key press event
} }
using namespace zfuncs; using namespace zfuncs;
using namespace navi; using namespace navi;
/******************************************************************************* * /******************************************************************************* *
char * gallery(cchar *filez, cchar *action, int Nth) ch * gallery(ch *filez, ch *action, int Nth)
public function to create/update image gallery (thumbnail window) public function to create/update image gallery (thumbnail window)
Make a scrolling window of thumbnails for a folder or list of files Make a scrolling window of thumbnails for a folder or list of files
Handle window buttons (up row, down page, open file, etc.) Handle window buttons (up row, down page, open file, etc.)
Call external functions in response to thumbnail mouse-clicks. Call external functions in response to thumbnail mouse-clicks.
filez: image file or folder, or file with list of image files filez: image file or folder, or file with list of image files
filez action Nth filez action Nth
----- ------ --- ----- ------ ---
file init * folder gallery, file name sort (subdirs first, last version option) file init * folder gallery, file name sort (folders first, last vers. option)
file initF * file list gallery, no sort file initF * file list gallery, no sort
* sort -2 sort and position via gallery_memory() * sort -2 sort and position via gallery_memory()
* sort -1 sort and position from current params * sort -1 sort and position from current params
file paint N paint, position = file (use N if valid for file ) file paint N paint, position = file (use N if valid for file )
0 paint N paint, position = N 0 paint N paint, position = N
0 paint -1 paint, no change in position 0 paint -1 paint, no change in position
file insert N add file to gallery at position N (folder or un sorted album) file insert N add file to gallery at position N (folder or un sorted album)
* delete N delete Nth file in gallery list * delete N delete Nth file in gallery list
* get N return file N in gallery list or null if N > la st * get N return file N in gallery list or null if N > la st
file update * update gallery index (Gindex[*]) from image ind ex in memory file update * update gallery index (Gindex[*]) from image ind ex in memory
* get1st * return 1st image file in gallery or null if non e
Returned values: Returned values:
get or get1st: filespec others: null get: filespec returned filespec is subject for zfree().
The returned file belongs to caller and is subject for zfree(). getR: filespec reference no zfree() needed
thumbnail click functions: thumbnail click functions:
gallery_Lclick_func() default function (open file) gallery_Lclick_func() default function (open file)
gallery_Rclick_popup() default function (popup menu) gallery_Rclick_popup() default function (popup menu)
gallery_select_Lclick_func() gallery_select active gallery_select_Lclick_func() gallery_select active
gallery_select_Rclick_func() gallery_select active gallery_select_Rclick_func() gallery_select active
edit_bookmarks_Lclick_func edit bookmarks active edit_bookmarks_Lclick_func edit bookmarks active
******************************************************************************** */ ******************************************************************************** */
char * gallery(cchar *filez, cchar *action, int Nth) ch * gallery(ch *filez, ch *action, int Nth)
{ {
char *file, *file2; ch *file, *file2;
char *pp, *pp1, *pp2; ch *pp, *pp1, *pp2;
char buff[XFCC]; ch buff[XFCC];
char **Flist = 0; ch **Flist = 0;
xxrec_t *xxrec; xxrec_t *xxrec;
static int ftf = 1; static int ftf = 1;
int err, ii, jj, kk; int err, ii, jj, kk;
int cc, cc1, cc2, fposn; int cc, cc1, cc2, fposn;
int NF, flags; int NF, flags;
FTYPE ftype; FTYPE ftype;
FILE *fid; FILE *fid;
while (! resource_lock(GFlock)) zsleep(0.0001); // lock gallery file list while (! resource_lock(GFlock)) zsleep(0.0001); // lock gallery file list
skipping to change at line 256 skipping to change at line 256
zstrcopy(galleryname,filez,"gallery"); // new gallery name zstrcopy(galleryname,filez,"gallery"); // new gallery name
NF = Gfiles; // current file count NF = Gfiles; // current file count
Gfiles = Gfolders = Gimages = 0; // no new files yet Gfiles = Gfolders = Gimages = 0; // no new files yet
for (ii = 0; ii < NF; ii++) { // free prior gallery index for (ii = 0; ii < NF; ii++) { // free prior gallery index
if (Gindex[ii].file) zfree(Gindex[ii].file); // memory leak 22.30 if (Gindex[ii].file) zfree(Gindex[ii].file); // memory leak 22.30
if (Gindex[ii].mdata1) zfree(Gindex[ii].mdata1); if (Gindex[ii].mdata1) zfree(Gindex[ii].mdata1);
if (Gindex[ii].mdata2) zfree(Gindex[ii].mdata2); // 22.20 if (Gindex[ii].mdata2) zfree(Gindex[ii].mdata2); // 22.20
Gindex[ii].file = Gindex[ii].mdata1 = Gindex[ii].mdata2 = 0; Gindex[ii].file = Gindex[ii].mdata1 = Gindex[ii].mdata2 = 0;
Gindex[ii].folder = 0; // 23.1
} }
} }
if (strmatch(action,"init")) // initz. from given file or folder if (strmatch(action,"init")) // initz. from given file or folder
{ {
if (! dirfile(galleryname)) { // bad folder? (may be member file) if (! dirfile(galleryname)) { // bad folder? (may be member file)
pp = (char *) strrchr(galleryname,'/'); // try parent folder pp = (ch *) strrchr(galleryname,'/'); // try parent folder
if (pp) *pp = 0; if (pp) *pp = 0;
if (! dirfile(galleryname)) goto return0; // give up, empty file list if (! dirfile(galleryname)) goto return0; // give up, empty file list
} }
gallerytype = FOLDER; // gallery type = folder gallerytype = FOLDER; // gallery type = folder
cc = strlen(galleryname) - 1; // remove trailing '/' cc = strlen(galleryname) - 1; // remove trailing '/'
if (cc > 1 && galleryname[cc] == '/') galleryname[cc] = 0; // but not if root folder '/' if (cc > 1 && galleryname[cc] == '/') galleryname[cc] = 0; // but not if root folder '/'
flags = 1 + 8; // images + folders, one level flags = 1 + 8; // images + folders, one level
skipping to change at line 301 skipping to change at line 302
if (Gfiles == maxgallery) { // too many files if (Gfiles == maxgallery) { // too many files
zmessageACK(Mwin,"gallery truncated to %d images",maxgallery); zmessageACK(Mwin,"gallery truncated to %d images",maxgallery);
break; break;
} }
ftype = image_file_type(file); ftype = image_file_type(file);
if (ftype == FDIR) // subfolder if (ftype == FDIR) // subfolder
{ {
Gindex[Gfiles].file = file; // add to gallery index Gindex[Gfiles].file = file; // add to gallery index
Gindex[Gfiles].file[0] = '!'; // if folder, make it sort first Gindex[Gfiles].folder = 1; // mark folder 23.1
Gindex[Gfiles].fdate[0] = 0; // no file date Gindex[Gfiles].fdate[0] = 0; // no file date
Gindex[Gfiles].pdate[0] = 0; // no photo date Gindex[Gfiles].pdate[0] = 0; // no photo date
Gindex[Gfiles].psize = 0; // no image size Gindex[Gfiles].psize = 0; // no image size
Gfiles++; Gfiles++;
Gfolders++; Gfolders++;
} }
else if (ftype == IMAGE || ftype == RAW || ftype == VIDEO) // supported image file type else if (ftype == IMAGE || ftype == RAW || ftype == VIDEO) // supported image file type
{ {
for (jj = 0; jj < Nblacklist; jj++) // omit blacklisted file for (jj = 0; jj < Nblacklist; jj++) // omit blacklisted file
skipping to change at line 325 skipping to change at line 326
continue; continue;
} }
xxrec = get_xxrec(file); xxrec = get_xxrec(file);
if (! xxrec) { if (! xxrec) {
zfree(file); zfree(file);
continue; continue;
} }
Gindex[Gfiles].file = file; // add to gallery index Gindex[Gfiles].file = file; // add to gallery index
Gindex[Gfiles].folder = 0;
strcpy(Gindex[Gfiles].fdate,xxrec->fdate); strcpy(Gindex[Gfiles].fdate,xxrec->fdate);
strcpy(Gindex[Gfiles].pdate,xxrec->pdate); strcpy(Gindex[Gfiles].pdate,xxrec->pdate);
Gindex[Gfiles].fsize = xxrec->fsize; // file size, MB Gindex[Gfiles].fsize = xxrec->fsize; // file size, MB
Gindex[Gfiles].psize = xxrec->ww * xxrec->hh; // image size, pixels Gindex[Gfiles].psize = xxrec->ww * xxrec->hh; // image size, pixels
Gfiles++; Gfiles++;
Gimages++; Gimages++;
} }
else zfree(file); // thumbnail or other kind of file else zfree(file); // thumbnail or other kind of file
skipping to change at line 348 skipping to change at line 350
} }
} }
if (Flist) zfree(Flist); if (Flist) zfree(Flist);
gallerysort = FNAME; // sort Gindex by file name ascending gallerysort = FNAME; // sort Gindex by file name ascending
galleryseq = ASCEND; galleryseq = ASCEND;
galleryposn = 0; galleryposn = 0;
if (Gfiles > 1) if (Gfiles > 1)
HeapSort((char *) Gindex, sizeof(Gindex_t), Gfiles, gallery_comp); HeapSort((ch *) Gindex, sizeof(Gindex_t), Gfiles, gallery_comp);
if (Flastversion) // keep last versions only (user setting) if (Flastversion) // keep last versions only (user setting)
{ {
ii = Gfolders; // skip folders ii = Gfolders; // skip folders
jj = ii + 1; jj = ii + 1;
kk = 0; kk = 0;
while (jj < Gfiles) while (jj < Gfiles)
{ {
pp1 = strrchr(Gindex[jj].file,'.'); // /.../filename.vNN.ext pp1 = strrchr(Gindex[jj].file,'.'); // /.../filename.vNN.ext
if (pp1 && pp1[-4] == '.' && pp1[-3] == 'v') { // | if (pp1 && pp1[-4] == '.' && pp1[-3] == 'v') { // |
cc1 = pp1 - Gindex[jj].file - 3; cc1 = pp1 - Gindex[jj].file - 3;
pp2 = strrchr(Gindex[ii].file,'.'); pp2 = strrchr(Gindex[ii].file,'.');
if (! pp2) cc2 = 0; if (! pp2) cc2 = 0;
else { else {
cc2 = pp2 - Gindex[ii].file + 1; // /.../filename.ext cc2 = pp2 - Gindex[ii].file + 1; // /.../filename.ext
if (pp2[-4] == '.' && pp2[-3] == 'v') cc2 -= 4; // | if (pp2[-4] == '.' && pp2[-3] == 'v') cc2 -= 4; // |
} }
if (cc1 == cc2 && strmatchN(Gindex[jj].file,Gindex[ii].file,cc1)) if (cc1 == cc2 && strmatchN(Gindex[jj].file,Gindex[ii].file,cc1))
{ {
zfree(Gindex[ii].file); // if match to "/.../filename." zfree(Gindex[ii].file); // if match to "/.../filename."
Gindex[ii] = Gindex[jj]; // replace with later version Gindex[ii] = Gindex[jj]; // replace with later version
jj++; jj++;
kk++; kk++;
continue; continue;
} }
} }
ii++; ii++;
Gindex[ii] = Gindex[jj]; Gindex[ii] = Gindex[jj];
jj++; jj++;
skipping to change at line 405 skipping to change at line 408
while (true) // read list of files while (true) // read list of files
{ {
file = fgets_trim(buff,XFCC-1,fid,1); file = fgets_trim(buff,XFCC-1,fid,1);
if (! file) break; if (! file) break;
xxrec = get_xxrec(file); // get index record xxrec = get_xxrec(file); // get index record
if (! xxrec) continue; if (! xxrec) continue;
Gindex[Gfiles].file = zstrdup(file,"gallery"); // add to gallery index Gindex[Gfiles].file = zstrdup(file,"gallery"); // add to gallery index
Gindex[Gfiles].folder = 0;
strcpy(Gindex[Gfiles].fdate,xxrec->fdate); // file date strcpy(Gindex[Gfiles].fdate,xxrec->fdate); // file date
strcpy(Gindex[Gfiles].pdate,xxrec->pdate); // photo date strcpy(Gindex[Gfiles].pdate,xxrec->pdate); // photo date
Gindex[Gfiles].fsize = xxrec->fsize; // file size, MB Gindex[Gfiles].fsize = xxrec->fsize; // file size, MB
Gindex[Gfiles].psize = xxrec->ww * xxrec->hh; // image size, pixels Gindex[Gfiles].psize = xxrec->ww * xxrec->hh; // image size, pixels
Gfiles++; Gfiles++;
if (Gfiles == maxgallery) { // too many files if (Gfiles == maxgallery) { // too many files
zmessageACK(Mwin,"gallery truncated to %d images",maxgallery); zmessageACK(Mwin,"gallery truncated to %d images",maxgallery);
break; break;
} }
} }
skipping to change at line 430 skipping to change at line 434
galleryseq = QNONE; galleryseq = QNONE;
galleryposn = 0; galleryposn = 0;
gallerypainted = 0; gallerypainted = 0;
goto return0; goto return0;
} }
if (strmatch(action,"sort")) // sort the gallery index if (strmatch(action,"sort")) // sort the gallery index
{ {
if (Nth == -2) gallery_memory("get"); // recall prior sort and posn. if (Nth == -2) gallery_memory("get"); // recall prior sort and posn.
if (Gfiles > 1 && gallerysort != SNONE) // sort using current or prior params if (Gfiles > 1 && gallerysort != SNONE) // sort using current or prior params
HeapSort((char *) Gindex, sizeof(Gindex_t), Gfiles, gallery_comp); HeapSort((ch *) Gindex, sizeof(Gindex_t), Gfiles, gallery_comp);
gallerypainted = 0; gallerypainted = 0;
goto return0; goto return0;
} }
if (strmatch(action,"paint")) // paint gallery window if (strmatch(action,"paint")) // paint gallery window
{ {
if (filez) Nth = file_position(filez,Nth); // use or get valid Nth for filez if (filez) Nth = file_position(filez,Nth); // use or get valid Nth for filez
if (Nth >= 0) galleryposn = Nth; // filez position or caller Nth if (Nth >= 0) galleryposn = Nth; // filez position or caller Nth
else gallery_memory("get"); // 22.40 else gallery_memory("get"); // 22.40
gtk_widget_queue_draw(Gdrawin); // draw gallery window gtk_widget_queue_draw(Gdrawin); // draw gallery window
skipping to change at line 466 skipping to change at line 470
xxrec = get_xxrec(filez); xxrec = get_xxrec(filez);
if (! xxrec) { if (! xxrec) {
zmessageACK(Mwin,"file not indexed: %s",filez); zmessageACK(Mwin,"file not indexed: %s",filez);
goto return0; goto return0;
} }
for (ii = Gfiles; ii > fposn; ii--) // create hole in gallery index for (ii = Gfiles; ii > fposn; ii--) // create hole in gallery index
Gindex[ii] = Gindex[ii-1]; Gindex[ii] = Gindex[ii-1];
Gindex[fposn].file = zstrdup(filez,"gallery"); // put new file in hole Gindex[fposn].file = zstrdup(filez,"gallery"); // put new file in hole
Gindex[Gfiles].folder = 0;
strcpy(Gindex[fposn].fdate,xxrec->fdate); strcpy(Gindex[fposn].fdate,xxrec->fdate);
strcpy(Gindex[fposn].pdate,xxrec->pdate); strcpy(Gindex[fposn].pdate,xxrec->pdate);
Gindex[fposn].fsize = xxrec->fsize; // file size, MB Gindex[fposn].fsize = xxrec->fsize; // file size, MB
Gindex[fposn].psize = xxrec->ww * xxrec->hh; // image size, pixels Gindex[fposn].psize = xxrec->ww * xxrec->hh; // image size, pixels
Gfiles++; Gfiles++;
Gimages++; Gimages++;
gallerypainted = 0; gallerypainted = 0;
goto return0; goto return0;
} }
skipping to change at line 496 skipping to change at line 501
Gindex[ii] = Gindex[ii+1]; Gindex[ii] = Gindex[ii+1];
gallerypainted = 0; gallerypainted = 0;
goto return0; goto return0;
} }
if (strmatch(action,"get")) // return Nth folder/file in gallery index if (strmatch(action,"get")) // return Nth folder/file in gallery index
{ {
fposn = Nth; // file position from caller fposn = Nth; // file position from caller
if (fposn < 0 || fposn > Gfiles-1) goto return0; if (fposn < 0 || fposn > Gfiles-1) goto return0;
file2 = zstrdup(Gindex[fposn].file,"gallery"); // get Nth file file2 = zstrdup(Gindex[fposn].file,"gallery"); // get Nth file
file2[0] = '/'; // restore initial '/'
if (regfile(file2)) goto return2; // return file2 if (regfile(file2)) goto return2; // return file2
if (dirfile(file2)) goto return2; if (dirfile(file2)) goto return2;
zfree(file2); zfree(file2);
goto return0; goto return0;
} }
if (strmatch(action,"getR"))
// return file reference (no zstrdup) 23.1
{
fposn = Nth;
// file position from caller
if (fposn < 0 || fposn > Gfiles-1) goto return0;
file2 = Gindex[fposn].file;
// get Nth file
if (regfile(file2)) goto return2;
// return file2
if (dirfile(file2)) goto return2;
goto return0;
}
if (strmatch(action,"update")) // update Gindex file from image index if (strmatch(action,"update")) // update Gindex file from image index
{ // (from update_image_index()) { // (from update_image_index())
for (ii = 0; ii < Gfiles; ii++) for (ii = 0; ii < Gfiles; ii++)
if (strmatch(filez,Gindex[ii].file)) break; if (strmatch(filez,Gindex[ii].file)) break;
if (ii == Gfiles) goto return0; // not found if (ii == Gfiles) goto return0; // not found
xxrec = get_xxrec(filez); xxrec = get_xxrec(filez);
if (! xxrec) goto return0; if (! xxrec) goto return0;
strcpy(Gindex[ii].fdate,xxrec->fdate); strcpy(Gindex[ii].fdate,xxrec->fdate);
strcpy(Gindex[ii].pdate,xxrec->pdate); strcpy(Gindex[ii].pdate,xxrec->pdate);
Gindex[ii].fsize = xxrec->fsize; // file size, MB Gindex[ii].fsize = xxrec->fsize; // file size, MB
Gindex[ii].psize = xxrec->ww * xxrec->hh; // image size, pixels Gindex[ii].psize = xxrec->ww * xxrec->hh; // image size, pixels
gallerypainted = 0; gallerypainted = 0;
goto return0; goto return0;
} }
if (strmatch(action,"get1st"))
// return 1st image file in gallery
{
for (ii = Gfolders; ii < Gfiles; ii++)
// loop from 1st image file
if (regfile(Gindex[ii].file)) break;
if (ii == Gfiles) goto return0;
// no files in gallery
file2 = zstrdup(Gindex[ii].file,"gallery");
// 1st file
goto return2;
// return file2
}
zappcrash("navigate %s",action); // invalid action zappcrash("navigate %s",action); // invalid action
return0: return0:
resource_unlock(GFlock); // unlock gallery file list resource_unlock(GFlock); // unlock gallery file list
return 0; return 0;
return2: return2:
resource_unlock(GFlock); resource_unlock(GFlock);
return file2;; return file2;;
} }
// private function, gallery sort compare // private function, gallery sort compare
// folders sort first and upper/lower case is ignored // folders sort first and upper/lower case is ignored
int navi::gallery_comp(cchar *rec1, cchar *rec2) int navi::gallery_comp(ch *rec1, ch *rec2)
{ {
int nn; int nn;
char *pp1, *pp2; ch *pp1, *pp2;
double d1, d2; double d1, d2;
Gindex_t *grec1, *grec2; Gindex_t *grec1, *grec2;
grec1 = (Gindex_t *) rec1; grec1 = (Gindex_t *) rec1;
grec2 = (Gindex_t *) rec2; grec2 = (Gindex_t *) rec2;
if (grec1->file[0] == '!') { if (grec1->folder) {
// folder sort // folder sort
if (grec2->file[0] != '!') return -1; if (! grec2->folder) return -1;
// folder :: image file // folder :: image file 23.1
nn = strcasecmp(grec1->file,grec2->file); // folder :: folder nn = strcasecmp(grec1->file,grec2->file); // folder :: folder
if (nn) return nn; if (nn) return nn;
nn = strcmp(grec1->file,grec2->file); // if equal, use utf8 compare nn = strcmp(grec1->file,grec2->file); // if equal, use utf8 compare
return nn; return nn;
} }
else if (grec2->file[0] == '!') return +1; // image file :: folder else if (grec2->folder) return +1; // image file :: folder 23.1
if (galleryseq == DESCEND) { // descending, switch inputs if (galleryseq == DESCEND) { // descending, switch inputs
grec1 = (Gindex_t *) rec2; grec1 = (Gindex_t *) rec2;
grec2 = (Gindex_t *) rec1; grec2 = (Gindex_t *) rec1;
} }
switch (gallerysort) { switch (gallerysort) {
case FNAME: { // file name case FNAME: { // file name
nn = strcasecmp(grec1->file,grec2->file); // ignore case nn = strcasecmp(grec1->file,grec2->file); // ignore case
skipping to change at line 589 skipping to change at line 594
return nn; return nn;
} }
case FDATE: { // file mod date/time case FDATE: { // file mod date/time
nn = strcmp(grec1->fdate,grec2->fdate); nn = strcmp(grec1->fdate,grec2->fdate);
if (nn) return nn; if (nn) return nn;
goto tiebreak; goto tiebreak;
} }
case PDATE: { // photo date/time case PDATE: { // photo date/time
nn = strcmp(grec1->pdate,grec2->pdate); // (EXIF DateTimeOriginal) nn = strcmp(grec1->pdate,grec2->pdate); // (metadata DateTimeOriginal)
if (nn) return nn; if (nn) return nn;
goto tiebreak; goto tiebreak;
} }
case FSIZE: { // file size case FSIZE: { // file size
nn = grec1->fsize - grec2->fsize; nn = grec1->fsize - grec2->fsize;
if (nn) return nn; if (nn) return nn;
goto tiebreak; goto tiebreak;
} }
skipping to change at line 660 skipping to change at line 665
/**** /****
compare function for sorting a list of file names with embedded numbers compare function for sorting a list of file names with embedded numbers
+ folder names are compared normally using strcmp() + folder names are compared normally using strcmp()
+ file base names are compared ignoring string case: 'a' = 'A' + file base names are compared ignoring string case: 'a' = 'A'
+ file base names with embedded numbers starting in the same position + file base names with embedded numbers starting in the same position
are compared arithmetically: '5' < '40' < '300' < '1000' are compared arithmetically: '5' < '40' < '300' < '1000'
****/ ****/
int navi::filename_comp(char *file1, char *file2) // 22.11 int navi::filename_comp(ch *file1, ch *file2) // 22.11
{ {
char *pp1, *pp2; ch *pp1, *pp2;
char ch1, ch2; ch ch1, ch2;
int nn; int nn;
int64 nn1, nn2; int64 nn1, nn2;
pp1 = strrchr(file1,'/'); // get end of folders pp1 = strrchr(file1,'/'); // get end of folders
pp2 = strrchr(file2,'/'); pp2 = strrchr(file2,'/');
if (pp1 && pp2) if (pp1 && pp2)
{ // compare folders { // compare folders
*pp1 = *pp2 = 0; *pp1 = *pp2 = 0;
nn = strcmp(file1,file2); nn = strcmp(file1,file2);
skipping to change at line 744 skipping to change at line 749
GtkWidget *Ftext; GtkWidget *Ftext;
xxrec_t *xxrec; xxrec_t *xxrec;
double x1, y1, x2, y2; double x1, y1, x2, y2;
int ii, Fmark; int ii, Fmark;
int nrows, row, col; int nrows, row, col;
int textlines; int textlines;
int row1, row2, ww, hh, cc, fsize; int row1, row2, ww, hh, cc, fsize;
int drwingW, drwingH; int drwingW, drwingH;
int thumx, thumy; int thumx, thumy;
int ndir, nfil, convdate; int ndir, nfil, convdate;
char *pp, *fspec, *fname, p0; ch *pp, *fspec, *fname;
char *ppd, ffolder[60]; ch *ppd, ffolder[60];
char pdt[24], text[200]; ch pdt[24], text[200];
static int prows = 0; static int prows = 0;
gallerypainted = 0; gallerypainted = 0;
if (! galleryname) return 1; // no gallery if (! galleryname) return 1; // no gallery
set_gwin_title(); // main window title = gallery name set_gwin_title(); // main window title = gallery name
gallery_navibutts(); // set navigation buttons on top panel gallery_navibutts(); // set navigation buttons on top panel
rgba.red = 0.00392 * GBrgb[0]; // window background color rgba.red = 0.00392 * GBrgb[0]; // window background color
skipping to change at line 844 skipping to change at line 849
row1 = y1 / thumbH; row1 = y1 / thumbH;
row2 = y2 / thumbH; row2 = y2 / thumbH;
for (row = row1; row <= row2; row++) // draw visible rows for (row = row1; row <= row2; row++) // draw visible rows
for (col = 0; col < xcols; col++) // draw all columns in row for (col = 0; col < xcols; col++) // draw all columns in row
{ {
ii = row * xcols + col; // next file ii = row * xcols + col; // next file
if (ii >= Gfiles) goto endloops; // exit 2 nested loops if (ii >= Gfiles) goto endloops; // exit 2 nested loops
fspec = Gindex[ii].file; // folder/file name fspec = Gindex[ii].file; // folder/file name
p0 = *fspec;
// replace possible '!' with '/'
*fspec = '/';
pp = strrchr(fspec,'/'); // get file name only pp = strrchr(fspec,'/'); // get file name only
if (pp) fname = pp + 1; if (pp) fname = pp + 1;
else fname = fspec; else fname = fspec;
strcpy(ffolder,"/"); strcpy(ffolder,"/");
if (gallerytype != FOLDER) { // files from mixed folders if (gallerytype != FOLDER) { // files from mixed folders
if (pp && pp > fspec) { if (pp && pp > fspec) {
for (ppd = pp-1; ppd >= fspec && *ppd != '/'; ppd--); // get last folder level for (ppd = pp-1; ppd >= fspec && *ppd != '/'; ppd--); // get last folder level
cc = pp - ppd + 1; // (include null to be added) cc = pp - ppd + 1; // (include null to be added)
if (cc > 60) cc = 60; if (cc > 60) cc = 60;
skipping to change at line 957 skipping to change at line 959
ww = gdk_pixbuf_get_width(pxbT); ww = gdk_pixbuf_get_width(pxbT);
ww = (thumbsize - ww) / 4; // shift margin if smaller width ww = (thumbsize - ww) / 4; // shift margin if smaller width
gdk_cairo_set_source_pixbuf(cr,pxbT,thumx+ww,thumy); gdk_cairo_set_source_pixbuf(cr,pxbT,thumx+ww,thumy);
cairo_paint(cr); // paint cairo_paint(cr); // paint
} }
if (ftype == FDIR) { // folder if (ftype == FDIR) { // folder
thumy += thumbsize/3 + 10; // overlay thumbnail with text thumy += thumbsize/3 + 10; // overlay thumbnail with text
draw_text(cr,text,thumx+ww+thumbW/6,thumy,thumbW-5); draw_text(cr,text,thumx+ww+thumbW/6,thumy,thumbW-5);
} }
*fspec = p0;
// restore '!'
} }
endloops: endloops:
gallerypainted = 1; // mark gallery display complete gallerypainted = 1; // mark gallery display complete
preload_start = ii; // start file for preload_thread() preload_start = ii; // start file for preload_thread()
preload_trigger = 1; // trigger preload_thread() preload_trigger = 1; // trigger preload_thread()
return 1; return 1;
} }
skipping to change at line 981 skipping to change at line 981
int navi::gallery_paintmeta(GtkWidget *drwin, cairo_t *cr) int navi::gallery_paintmeta(GtkWidget *drwin, cairo_t *cr)
{ {
PIXBUF *pxbT; PIXBUF *pxbT;
double x1, y1, x2, y2; double x1, y1, x2, y2;
int ii, nrows, row; int ii, nrows, row;
int row1, row2, ww, hh; int row1, row2, ww, hh;
int cc1, cc2; int cc1, cc2;
int drwingW, drwingH; int drwingW, drwingH;
int thumx, thumy, textww; int thumx, thumy, textww;
char *fspec, p0, *mtext; ch *fspec, *mtext;
static int prows = 0; static int prows = 0;
thumbsize = 256; thumbsize = 256;
for (ii = 0; ii < thumbxx; ii++) for (ii = 0; ii < thumbxx; ii++)
if (thumbsize == thumbx[ii]) break; // tolerate bad parameter value if (thumbsize == thumbx[ii]) break; // tolerate bad parameter value
if (ii >= thumbxx) thumbsize = thumbx[2]; // inherited from prior release if (ii >= thumbxx) thumbsize = thumbx[2]; // inherited from prior release
fontsize = appfontsize; fontsize = appfontsize;
skipping to change at line 1055 skipping to change at line 1055
row2 = y2 / thumbH; row2 = y2 / thumbH;
textww = drwingW - thumbW - 2 * margin; // space for text right of thumbnail textww = drwingW - thumbW - 2 * margin; // space for text right of thumbnail
for (row = row1; row <= row2; row++) // draw file thumbnails + text for (row = row1; row <= row2; row++) // draw file thumbnails + text
{ {
ii = row; // next file ii = row; // next file
if (ii >= Gfiles) break; if (ii >= Gfiles) break;
fspec = Gindex[ii].file; // filename fspec = Gindex[ii].file; // filename
p0 = *fspec;
// replace possible ! with /
*fspec = '/';
thumx = margin; // drawing area position thumx = margin; // drawing area position
thumy = row * thumbH + margin; thumy = row * thumbH + margin;
pxbT = get_cache_thumb(fspec,0); // get thumbnail pxbT = get_cache_thumb(fspec,0); // get thumbnail
if (pxbT) { if (pxbT) {
gdk_cairo_set_source_pixbuf(cr,pxbT,thumx,thumy); gdk_cairo_set_source_pixbuf(cr,pxbT,thumx,thumy);
cairo_paint(cr); cairo_paint(cr);
} }
draw_text(cr,fspec,thumbW+margin,thumy,textww); // write filespec to right of thumbnail draw_text(cr,fspec,thumbW+margin,thumy,textww); // write filespec to right of thumbnail
*fspec = p0;
// restore '!'
cc1 = cc2 = 0; cc1 = cc2 = 0;
if (Gindex[ii].mdata1) cc1 = strlen(Gindex[ii].mdata1); // standard metadata text if (Gindex[ii].mdata1) cc1 = strlen(Gindex[ii].mdata1); // standard metadata text
if (Gindex[ii].mdata2) cc2 = strlen(Gindex[ii].mdata2); // user selected metadata text 22.20 if (Gindex[ii].mdata2) cc2 = strlen(Gindex[ii].mdata2); // user selected metadata text 22.20
if (cc1 + cc2 == 0) continue; // no text if (cc1 + cc2 == 0) continue; // no text
if (cc1 && Gindex[ii].mdata1[cc1-1] == '\n') { // delete sporadic trailing \n 23.0 if (cc1 && Gindex[ii].mdata1[cc1-1] == '\n') { // delete sporadic trailing \n 23.0
Gindex[ii].mdata1[cc1-1] = 0; Gindex[ii].mdata1[cc1-1] = 0;
cc1--; cc1--;
} }
if (cc2 && Gindex[ii].mdata2[cc2-1] == '\n') { // delete sporadic trailing \n 23.0 if (cc2 && Gindex[ii].mdata2[cc2-1] == '\n') { // delete sporadic trailing \n 23.0
Gindex[ii].mdata2[cc2-1] = 0; Gindex[ii].mdata2[cc2-1] = 0;
cc2--; cc2--;
} }
mtext = (char *) zmalloc(cc1 + cc2 + 4,"paintmeta"); // space for both 22.20 mtext = (ch *) zmalloc(cc1 + cc2 + 4,"paintmeta"); // space for both 22.20
if (cc1) strcpy(mtext,Gindex[ii].mdata1); // standard text if (cc1) strcpy(mtext,Gindex[ii].mdata1); // standard text
if (cc2) { if (cc2) {
strcpy(mtext + cc1,"\n\n"); strcpy(mtext + cc1,"\n\n");
cc1 += 2; cc1 += 2;
strcpy(mtext+cc1,Gindex[ii].mdata2); strcpy(mtext+cc1,Gindex[ii].mdata2);
} }
draw_text(cr,mtext,thumbW+margin,thumy+20,textww); // draw text to window draw_text(cr,mtext,thumbW+margin,thumy+20,textww); // draw text to window
skipping to change at line 1118 skipping to change at line 1114
int navi::gallery_paintmeta2(GtkWidget *drwin, cairo_t *cr) int navi::gallery_paintmeta2(GtkWidget *drwin, cairo_t *cr)
{ {
PIXBUF *pxbT; PIXBUF *pxbT;
FTYPE ftype; FTYPE ftype;
double x1, y1, x2, y2; double x1, y1, x2, y2;
int ii, nn, cc, nrows, row, col; int ii, nn, cc, nrows, row, col;
int row1, row2, ww, hh; int row1, row2, ww, hh;
int drwingW, drwingH; int drwingW, drwingH;
int thumx, thumy, textx, textww; int thumx, thumy, textx, textww;
int ndir, nfil; int ndir, nfil;
char *fspec, *fspec2, p0; ch *fspec, *fspec2;
xxrec_t *xxrec; xxrec_t *xxrec;
char fdate[20], pdate[20], *pp; ch fdate[20], pdate[20], *pp;
char *rating, *tags, *title, *desc, *location, *country; ch *rating, *tags, *title, *desc, *location, *country;
char wwhh[16], fsize[16]; ch wwhh[16], fsize[16];
char text[1000], xtext1[MXmaxcc+MXmax], **xtext2; ch text[1000], xtext1[xmetaXcc+xmetamaxkeys], **xtext2;
static int prows = 0; static int prows = 0;
thumbsize = 256; // thumbnail size 22.40 thumbsize = 256; // thumbnail size 22.40
fontsize = appfontsize; fontsize = appfontsize;
textww = fontsize * 60; // text width limit for max. 60 chars. textww = fontsize * 60; // text width limit for max. 60 chars.
if (gallerytype != FOLDER) textww = fontsize * 200; // more if full path is written if (gallerytype != FOLDER) textww = fontsize * 200; // more if full path is written
thumbW = thumbsize + 10 + textww; // thumbnail + text layout size thumbW = thumbsize + 10 + textww; // thumbnail + text layout size
thumbH = thumbsize + 20; thumbH = thumbsize + 20;
skipping to change at line 1194 skipping to change at line 1190
row1 = y1 / thumbH; row1 = y1 / thumbH;
row2 = y2 / thumbH; row2 = y2 / thumbH;
for (row = row1; row <= row2; row++) // draw file thumbnails for (row = row1; row <= row2; row++) // draw file thumbnails
for (col = 0; col < xcols; col++) // draw all columns in row for (col = 0; col < xcols; col++) // draw all columns in row
{ {
ii = row * xcols + col; // next file ii = row * xcols + col; // next file
if (ii >= Gfiles) goto endloops; // exit 2 nested loops if (ii >= Gfiles) goto endloops; // exit 2 nested loops
fspec = Gindex[ii].file; fspec = Gindex[ii].file;
p0 = *fspec;
// replace possible ! with /
*fspec = '/';
fspec2 = fspec; fspec2 = fspec;
if (gallerytype == FOLDER) { // folder gallery, write only if (gallerytype == FOLDER) { // folder gallery, write only
pp = strrchr(fspec,'/'); // base file names pp = strrchr(fspec,'/'); // base file names
if (pp) fspec2 = pp+1; if (pp) fspec2 = pp+1;
} }
thumx = col * thumbW + margin; // drawing area position thumx = col * thumbW + margin; // drawing area position
thumy = row * thumbH + margin; thumy = row * thumbH + margin;
pxbT = get_cache_thumb(fspec,0); // get thumbnail pxbT = get_cache_thumb(fspec,0); // get thumbnail
skipping to change at line 1311 skipping to change at line 1304
" rating: %s size: %s %s location: %s %s \n" " rating: %s size: %s %s location: %s %s \n"
" tags: %s \n title: %s \n description: %s ", " tags: %s \n title: %s \n description: %s ",
fspec2, pdate, fdate, rating, wwhh, fsize, fspec2, pdate, fdate, rating, wwhh, fsize,
location, country, tags, title, desc); location, country, tags, title, desc);
} }
} }
else snprintf(text,1000,"\n %s",fspec2); // no index, no metadata, file name only else snprintf(text,1000,"\n %s",fspec2); // no index, no metadata, file name only
draw_text(cr,text,textx,thumy,textww); // paint text draw_text(cr,text,textx,thumy,textww); // paint text
*fspec = p0;
// restore '!'
} }
endloops: endloops:
gallerypainted = 1; gallerypainted = 1;
return 1; return 1;
} }
/******************************************************************************* */ /******************************************************************************* */
// private function // private function
// find the number of subdirs and image files within a given folder // find the number of subdirs and image files within a given folder
void navi::dir_filecount(char *dirname, int &ndir, int &nfil) void navi::dir_filecount(ch *dirname, int &ndir, int &nfil)
{ {
char *file, **flist; ch *file, **flist;
int ii, cc, err, NF; int ii, cc, err, NF;
int dcount = 0, fcount = 0; int dcount = 0, fcount = 0;
FTYPE ftype; FTYPE ftype;
#define NC 1000 // cache capacity #define NC 1000 // cache capacity
static int ftf = 1; static int ftf = 1;
static char *dirnamecache[NC]; // cache for recent folder data static ch *dirnamecache[NC]; // cache for recent folder data
static time_t modtimecache[NC]; static time_t modtimecache[NC];
static int dcountcache[NC]; static int dcountcache[NC];
static int fcountcache[NC]; static int fcountcache[NC];
static int pcache = 0; static int pcache = 0;
STATB statB; STATB statB;
if (ftf) { if (ftf) {
ftf = 0; ftf = 0;
cc = NC * sizeof(char *); // first call, clear cache cc = NC * sizeof(ch *); // first call, clear cache
memset(dirnamecache,0,cc); memset(dirnamecache,0,cc);
} }
ndir = nfil = 0; ndir = nfil = 0;
if (! dirfile(dirname,&statB)) return; if (! dirfile(dirname,&statB)) return;
for (ii = 0; ii < NC; ii++) { // look for folder in cache for (ii = 0; ii < NC; ii++) { // look for folder in cache
if (! dirnamecache[ii]) break; if (! dirnamecache[ii]) break;
if (strmatch(dirname,dirnamecache[ii]) && if (strmatch(dirname,dirnamecache[ii]) &&
skipping to change at line 1394 skipping to change at line 1385
ndir = dcountcache[ii] = dcount; ndir = dcountcache[ii] = dcount;
nfil = fcountcache[ii] = fcount; nfil = fcountcache[ii] = fcount;
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// private function // private function
// write text block at px/py location with width limit ww // write text block at px/py location with width limit ww
void navi::draw_text(cairo_t *cr, char *text, int px, int py, int ww) void navi::draw_text(cairo_t *cr, ch *text, int px, int py, int ww)
{ {
static PangoFontDescription *pfont = 0; static PangoFontDescription *pfont = 0;
static PangoLayout *playout = 0; static PangoLayout *playout = 0;
static int pfontsize = -1; static int pfontsize = -1;
static char thumbfont[20] = ""; static ch thumbfont[20] = "";
if (fontsize != pfontsize) { // adjust for curr. font size if (fontsize != pfontsize) { // adjust for curr. font size
pfontsize = fontsize; pfontsize = fontsize;
snprintf(thumbfont,20,"sans bold %d",fontsize); snprintf(thumbfont,20,"sans bold %d",fontsize);
if (pfont) pango_font_description_free(pfont); if (pfont) pango_font_description_free(pfont);
pfont = pango_font_description_from_string(thumbfont); pfont = pango_font_description_from_string(thumbfont);
if (playout) g_object_unref(playout); if (playout) g_object_unref(playout);
playout = pango_cairo_create_layout(cr); playout = pango_cairo_create_layout(cr);
pango_layout_set_font_description(playout,pfont); pango_layout_set_font_description(playout,pfont);
} }
skipping to change at line 1429 skipping to change at line 1420
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// private function // private function
// create a row of navigation buttons in gallery top panel // create a row of navigation buttons in gallery top panel
void navi::gallery_navibutts() void navi::gallery_navibutts()
{ {
char labtext[100]; ch labtext[100];
int ii, cc, max = maxgallerylevs; int ii, cc, max = maxgallerylevs;
char *pp1, *pp2; ch *pp1, *pp2;
for (ii = 0; ii < max; ii++) { // clear old navi buttons if any for (ii = 0; ii < max; ii++) { // clear old navi buttons if any
if (gallerypath[ii]) { if (gallerypath[ii]) {
zfree(gallerypath[ii]); zfree(gallerypath[ii]);
gallerypath[ii] = 0; gallerypath[ii] = 0;
gtk_widget_destroy(gallerybutt[ii]); gtk_widget_destroy(gallerybutt[ii]);
} }
} }
if (gallerylabel) gtk_widget_destroy(gallerylabel); // clear gallery label if any if (gallerylabel) gtk_widget_destroy(gallerylabel); // clear gallery label if any
skipping to change at line 1472 skipping to change at line 1463
} }
ii = 0; ii = 0;
pp1 = galleryname; pp1 = galleryname;
while (pp1 && *pp1) // construct new buttons while (pp1 && *pp1) // construct new buttons
{ {
pp2 = strchr(pp1+1,'/'); // /aaaaaa/bbbbbb/cccccc pp2 = strchr(pp1+1,'/'); // /aaaaaa/bbbbbb/cccccc
if (pp2) cc = pp2 - pp1; // | | if (pp2) cc = pp2 - pp1; // | |
else cc = strlen(pp1); // pp1 pp2 else cc = strlen(pp1); // pp1 pp2
gallerypath[ii] = (char *) zmalloc(cc,"navibutts"); gallerypath[ii] = (ch *) zmalloc(cc,"navibutts");
strncpy0(gallerypath[ii],pp1+1,cc); // bbbbbb strncpy0(gallerypath[ii],pp1+1,cc); // bbbbbb
gallerybutt[ii] = gtk_button_new_with_label(gallerypath[ii]); gallerybutt[ii] = gtk_button_new_with_label(gallerypath[ii]);
gtk_box_pack_start(GTK_BOX(Gpanel),gallerybutt[ii],0,0,3); gtk_box_pack_start(GTK_BOX(Gpanel),gallerybutt[ii],0,0,3);
G_SIGNAL(gallerybutt[ii],"clicked",navibutt_clicked,&Nval[ii]); G_SIGNAL(gallerybutt[ii],"clicked",navibutt_clicked,&Nval[ii]);
pp1 = pp1 + cc; // next folder level /cccccc pp1 = pp1 + cc; // next folder level /cccccc
if (! *pp1) break; // null = end if (! *pp1) break; // null = end
if (*pp1 == '/' && ! *(pp1+1)) break; // / + null = end if (*pp1 == '/' && ! *(pp1+1)) break; // / + null = end
if (++ii == max) break; // limit of folder levels if (++ii == max) break; // limit of folder levels
} }
gtk_widget_show_all(Gpanel); gtk_widget_show_all(Gpanel);
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// private function - menu function for gallery window // private function - menu function for gallery window
// - scroll window as requested // - scroll window as requested
// - jump to new file or folder as requested // - jump to new file or folder as requested
void navi::menufuncx(GtkWidget *, cchar *menu) void navi::menufuncx(GtkWidget *, ch *menu)
{ {
int ii, scroll1, scroll2; int ii, scroll1, scroll2;
if (FGWM != 'G') m_viewmode(0,"G"); m_viewmode(0,"G");
scrollposn = gtk_adjustment_get_value(Gadjust); // current scroll position scrollposn = gtk_adjustment_get_value(Gadjust); // current scroll position
if (strmatch(menu,"Zoom+")) // next bigger thumbnail size if (strmatch(menu,"Zoom+")) // next bigger thumbnail size
{ {
F1_help_topic = "zoom"; F1_help_topic = "zoom";
if (Fthumbview != 1) return; // not resizable thumb view if (Fthumbview != 1) return; // not resizable thumb view
for (ii = 0; ii < thumbxx; ii++) // set next greater thumbnail size for (ii = 0; ii < thumbxx; ii++) // set next greater thumbnail size
if (thumbsize == thumbx[ii]) break; if (thumbsize == thumbx[ii]) break;
if (ii == 0) return; // already maximum, no change if (ii == 0) return; // already maximum, no change
skipping to change at line 1658 skipping to change at line 1649
return 1; return 1;
} }
/******************************************************************************* */ /******************************************************************************* */
// private function // private function
// gallery top panel folder button clicked, open corresponding folder // gallery top panel folder button clicked, open corresponding folder
void navi::navibutt_clicked(GtkWidget *widget, int *lev) void navi::navibutt_clicked(GtkWidget *widget, int *lev)
{ {
char gallerydir[XFCC], *pp; ch gallerydir[XFCC], *pp;
gallery_scroll(-1,0); // stop scrolling gallery_scroll(-1,0); // stop scrolling
pp = gallerydir; pp = gallerydir;
for (int ii = 0; ii <= *lev; ii++) for (int ii = 0; ii <= *lev; ii++)
{ {
*pp = '/'; *pp = '/';
strcpy(pp+1,gallerypath[ii]); strcpy(pp+1,gallerypath[ii]);
pp = pp + strlen(pp); pp = pp + strlen(pp);
skipping to change at line 1706 skipping to change at line 1697
add_popmenu_item(popmenu,"Desktop",newtop_menu_event,0,0); add_popmenu_item(popmenu,"Desktop",newtop_menu_event,0,0);
add_popmenu_item(popmenu,"Fotoxx home",newtop_menu_event,0,0); add_popmenu_item(popmenu,"Fotoxx home",newtop_menu_event,0,0);
add_popmenu_item(popmenu,"Saved Areas",newtop_menu_event,0,0); add_popmenu_item(popmenu,"Saved Areas",newtop_menu_event,0,0);
add_popmenu_item(popmenu,"recent images",newtop_menu_event,0,0); add_popmenu_item(popmenu,"recent images",newtop_menu_event,0,0);
add_popmenu_item(popmenu,"newest images",newtop_menu_event,0,0); add_popmenu_item(popmenu,"newest images",newtop_menu_event,0,0);
popup_menu(Mwin,popmenu); popup_menu(Mwin,popmenu);
return; return;
} }
void navi::newtop_menu_event(GtkWidget *, cchar *menu) // menu event function void navi::newtop_menu_event(GtkWidget *, ch *menu) // menu event function
{ {
char folder[200]; ch folder[200];
if (! menu) return; if (! menu) return;
strncpy0(folder,menu,200); strncpy0(folder,menu,200);
if (strmatch(menu,"ALL")) { if (strmatch(menu,"ALL")) {
m_allfolders(0,0); m_allfolders(0,0);
return; return;
} }
skipping to change at line 1755 skipping to change at line 1746
} }
/******************************************************************************* */ /******************************************************************************* */
// private function - [Album] button: select new album // private function - [Album] button: select new album
void navi::newalbum(GtkWidget *widget, GdkEventButton *event) void navi::newalbum(GtkWidget *widget, GdkEventButton *event)
{ {
static GtkWidget *popmenu = 0; static GtkWidget *popmenu = 0;
char **flist, *pp; ch **flist, *pp;
char findcomm[200]; ch findcomm[200];
char *albums[200]; ch *albums[200];
int ii, NF, count = 0; int ii, NF, count = 0;
gallery_scroll(-1,0); // stop scrolling gallery_scroll(-1,0); // stop scrolling
snprintf(findcomm,200,"%s/*",albums_folder); // find all album names snprintf(findcomm,200,"%s/*",albums_folder); // find all album names
zfind(findcomm,flist,NF); zfind(findcomm,flist,NF);
for (ii = 0; ii < NF && count < 200; ii++) for (ii = 0; ii < NF && count < 200; ii++)
{ {
pp = strrchr(flist[ii],'/'); pp = strrchr(flist[ii],'/');
skipping to change at line 1797 skipping to change at line 1788
add_popmenu_item(popmenu,"Current Album",newalbum_menu_event,0,0); // add "current album" add_popmenu_item(popmenu,"Current Album",newalbum_menu_event,0,0); // add "current album"
for (int ii = 0; ii < count; ii++) // insert all known albums for (int ii = 0; ii < count; ii++) // insert all known albums
add_popmenu_item(popmenu,albums[ii],newalbum_menu_event,0,0); add_popmenu_item(popmenu,albums[ii],newalbum_menu_event,0,0);
popup_menu(widget,popmenu); popup_menu(widget,popmenu);
return; return;
} }
void navi::newalbum_menu_event(GtkWidget *, cchar *menu) // menu event function void navi::newalbum_menu_event(GtkWidget *, ch *menu) // menu event function
{ {
char albumfile[200]; ch albumfile[200];
if (! menu || strmatch(menu,"Current Album")) if (! menu || strmatch(menu,"Current Album"))
{ {
if (! curr_album || ! *curr_album) { if (! curr_album || ! *curr_album) {
zmessageACK(Mwin,"no current album"); zmessageACK(Mwin,"no current album");
return; return;
} }
album_show(); album_show();
return; return;
} }
skipping to change at line 1830 skipping to change at line 1821
// user function receives clicked file, which is subject for zfree() // user function receives clicked file, which is subject for zfree()
int navi::mouse_event(GtkWidget *widget, GdkEvent *event, void *) int navi::mouse_event(GtkWidget *widget, GdkEvent *event, void *)
{ {
GdkEventButton *eventB; GdkEventButton *eventB;
PIXBUF *pxbT; PIXBUF *pxbT;
int evtype, mousex, mousey, mousebutt; int evtype, mousex, mousey, mousebutt;
int row, col, nrows, tww, thh, marg; int row, col, nrows, tww, thh, marg;
int Nth, poswidth, posheight, err, ftype; int Nth, poswidth, posheight, err, ftype;
static int Fmyclick = 0; static int Fmyclick = 0;
char *filez = 0; ch *filez = 0;
STATB statB; STATB statB;
if (! Gfiles) return 1; // empty gallery if (! Gfiles) return 1; // empty gallery
if (! gallerypainted) return 1; // not initialized if (! gallerypainted) return 1; // not initialized
eventB = (GdkEventButton *) event; eventB = (GdkEventButton *) event;
evtype = eventB->type; evtype = eventB->type;
mousex = int(eventB->x); mousex = int(eventB->x);
mousey = int(eventB->y); mousey = int(eventB->y);
mousebutt = eventB->button; mousebutt = eventB->button;
skipping to change at line 1870 skipping to change at line 1861
else poswidth = posheight = 0; else poswidth = posheight = 0;
if (! xcols) return 1; if (! xcols) return 1;
nrows = 1 + (Gfiles-1) / xcols; // total thumbnail rows, 1 or more nrows = 1 + (Gfiles-1) / xcols; // total thumbnail rows, 1 or more
if (col < 0 || col >= xcols) return 1; // mouse not on a thumbnail if (col < 0 || col >= xcols) return 1; // mouse not on a thumbnail
if (row < 0 || row >= nrows) return 1; if (row < 0 || row >= nrows) return 1;
Nth = xcols * row + col; // mouse at this thumbnail (image file) Nth = xcols * row + col; // mouse at this thumbnail (image file)
if (Nth >= Gfiles) return 1; if (Nth >= Gfiles) return 1;
filez = zstrdup(Gindex[Nth].file,"navi-mouse"); // file (thumbnail) at mouse posn. filez = zstrdup(Gindex[Nth].file,"navi-mouse"); // file (thumbnail) at mouse posn.
*filez = '/';
if (evtype == GDK_BUTTON_PRESS) if (evtype == GDK_BUTTON_PRESS)
{ {
gallery_scroll(-1,0); // stop scrolling gallery_scroll(-1,0); // stop scrolling
Fmyclick = 1; // button press is mine Fmyclick = 1; // button press is mine
if (drag_file) zfree(drag_file); if (drag_file) zfree(drag_file);
drag_file = 0; drag_file = 0;
ftype = image_file_type(filez); // save for poss. drag-drop ftype = image_file_type(filez); // save for poss. drag-drop
skipping to change at line 1965 skipping to change at line 1955
cleanup: cleanup:
if (filez) zfree(filez); if (filez) zfree(filez);
return 0; // must be 0 for drag/drop to work return 0; // must be 0 for drag/drop to work
} }
/******************************************************************************* */ /******************************************************************************* */
// this function is called if a drag-drop is initiated from the gallery window // this function is called if a drag-drop is initiated from the gallery window
char * navi::gallery_dragfile() ch * navi::gallery_dragfile()
{ {
char dragfile[200]; ch dragfile[200];
FILE *fid; FILE *fid;
snprintf(dragfile,200,"%s/drag_from_gallery",get_zhomedir()); // save source gallery name snprintf(dragfile,200,"%s/drag_from_gallery",get_zhomedir()); // save source gallery name
fid = fopen(dragfile,"w"); // and position fid = fopen(dragfile,"w"); // and position
if (! fid) { if (! fid) {
zmessageACK(Mwin,strerror(errno)); zmessageACK(Mwin,strerror(errno));
return 0; return 0;
} }
fprintf(fid,"%s\n",galleryname); fprintf(fid,"%s\n",galleryname);
fprintf(fid,"%d\n",drag_posn); fprintf(fid,"%d\n",drag_posn);
fclose(fid); fclose(fid);
return drag_file; return drag_file;
} }
// this function is called if a drag-drop file is dragged or dropped on the gal lery window // this function is called if a drag-drop file is dragged or dropped on the gal lery window
void navi::gallery_dropfile(int mousex, int mousey, char *file) void navi::gallery_dropfile(int mousex, int mousey, ch *file)
{ {
int err, top, mpos, speed; int err, top, mpos, speed;
int row, col, nrows, Nth, cc; int row, col, nrows, Nth, cc;
int poswidth, from_posn = -1; int poswidth, from_posn = -1;
char dragfile[200], buff[200]; ch dragfile[200], buff[200];
char *pp1, *pp2, *from_gallery = 0, *newfile; ch *pp1, *pp2, *from_gallery = 0, *newfile;
FILE *fid; FILE *fid;
if (gallerytype != FOLDER && gallerytype != ALBUM) return; // reject others (search, recent ...) if (gallerytype != FOLDER && gallerytype != ALBUM) return; // reject others (search, recent ...)
if (! file) // drag motion underway if (! file) // drag motion underway
{ {
if (! mousex) { // drag leave event if (! mousex) { // drag leave event
gallery_scroll(-1,0); // stop scroll gallery_scroll(-1,0); // stop scroll
return; return;
} }
skipping to change at line 2110 skipping to change at line 2100
album_show(); album_show();
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// Private function - respond to keyboard navigation keys. // Private function - respond to keyboard navigation keys.
// KBpress() for main window calls this function when G view is active. // KBpress() for main window calls this function when G view is active.
int navi::KBaction(cchar *action) int navi::KBaction(ch *action)
{ {
int ii; int ii;
int row1, row2, rowf; int row1, row2, rowf;
Plog(2,"KBaction: %s \n",action); Plog(2,"KBaction: %s \n",action);
if (strmatch(action,"Open")) { // goto F-view 22.30 if (strmatch(action,"Open")) { // goto F-view 22.30
m_viewmode(0,"F"); m_viewmode(0,"F");
return 1; return 1;
} }
skipping to change at line 2216 skipping to change at line 2206
/******************************************************************************* */ /******************************************************************************* */
// save and restore gallery sort and top file position // save and restore gallery sort and top file position
#define RGmax 100 // max. recent galleries to remember #define RGmax 100 // max. recent galleries to remember
typedef struct { // gallery memory data typedef struct { // gallery memory data
int galleryposn; // top file position (scroll position) int galleryposn; // top file position (scroll position)
int gallerysort; // sort galleryname/filedate/photodate int gallerysort; // sort galleryname/filedate/photodate
int galleryseq; // sort ascending/descending int galleryseq; // sort ascending/descending
char *galleryname; // gallery name /.../filename ch *galleryname; // gallery name /.../filename
} }
gallerymem_t; gallerymem_t;
gallerymem_t gallerymem[RGmax]; // array of gallery memory gallerymem_t gallerymem[RGmax]; // array of gallery memory
gallerymem_t Tgallerymem; gallerymem_t Tgallerymem;
int NGmem; // current entries <= RGmax int NGmem; // current entries <= RGmax
void gallery_memory(cchar *action) void gallery_memory(ch *action)
{ {
FILE *fid; FILE *fid;
char buff[XFCC], *pp; ch buff[XFCC], *pp;
int ii, nn, err; int ii, nn, err;
if (strmatch(action,"reset")) // clear gallery memory data if (strmatch(action,"reset")) // clear gallery memory data
{ {
NGmem = 0; NGmem = 0;
return; return;
} }
if (strmatch(action,"load")) // load gallery memory from file if (strmatch(action,"load")) // load gallery memory from file
{ // at Fotoxx startup time { // at Fotoxx startup time
skipping to change at line 2359 skipping to change at line 2349
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// set the window title for the gallery window // set the window title for the gallery window
// window title = gallery name // window title = gallery name
void set_gwin_title() void set_gwin_title()
{ {
char *pp, title[200]; ch *pp, title[200];
if (FGWM != 'G') return; if (FGWM != 'G') return;
if (gallerytype == FOLDER) if (gallerytype == FOLDER)
snprintf(title,200,"%s FOLDER %s %d folders %d files", // use Frelease snprintf(title,200,"%s FOLDER %s %d folders %d files", // use Frelease
Frelease,galleryname,Gfolders,Gimages); Frelease,galleryname,Gfolders,Gimages);
else if (gallerytype == SEARCH || gallerytype == META) else if (gallerytype == SEARCH || gallerytype == META)
snprintf(title,200,"%s SEARCH RESULTS %d files",Frelease,Gimages); snprintf(title,200,"%s SEARCH RESULTS %d files",Frelease,Gimages);
skipping to change at line 2395 skipping to change at line 2385
gtk_window_set_title(MWIN,title); gtk_window_set_title(MWIN,title);
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// Return previous or next image file from curr_file in the gallery file list. // Return previous or next image file from curr_file in the gallery file list.
// If lastver is set, only the last edit version is returned. // If lastver is set, only the last edit version is returned.
// (gallery must be sorted by file name (version sequence)). // (gallery must be sorted by file name (version sequence)).
// Returns null if no previous/next file found. // Returns null if no previous/next file found.
// returned file is subject for zfree().
char * prev_next_file(int index, int lastver) ch * prev_next_file(int index, int lastver)
{ {
int Nth; int Nth;
char *rootname1 = 0, *rootname2 = 0; ch *rootname1 = 0, *rootname2 = 0;
// file names without .vNN and .ext // file names without .vNN and .ext
char *file = 0, *filever = 0; ch *file = 0, *filever = 0;
Nth = curr_file_posn; Nth = curr_file_posn;
if (index == +1) // get next file if (index == +1) // get next file
{ {
while (true) while (true)
{ {
Nth += 1; Nth += 1;
if (Nth >= Gfiles) { // no more files this gallery if (Nth >= Gfiles) { // no more files this gallery
if (filever) break; // return last file version if (filever) break; // return last file version
goto retnull; // no more files goto retnull; // no more files
} }
if (file) zfree(file); file = gallery(0,"getR",Nth);
file = gallery(0,"get",Nth); // get next file 23.1
// get next file
if (! file) goto retnull; if (! file) goto retnull;
if (! lastver) goto retfile; // return all versions if (! lastver) goto retfile; // return all versions
if (! filever) { if (! filever) {
filever = file; // potential last version filever = file; // potential last version
file = 0; file = 0;
rootname1 = file_rootname(filever); // save rootname rootname1 = file_rootname(filever); // save rootname
continue; continue;
} }
if (rootname2) zfree(rootname2); if (rootname2) zfree(rootname2);
rootname2 = file_rootname(file); rootname2 = file_rootname(file);
if (! strmatch(rootname1,rootname2)) break; // new rootname, filever was last version if (! strmatch(rootname1,rootname2)) break; // new rootname, filever was last version
zfree(filever);
filever = file; // save last file with same rootname filever = file; // save last file with same rootname
file = 0; file = 0;
} }
if (file) zfree(file);
file = filever; file = filever;
goto retfile; goto retfile;
} }
if (index == -1) // get previous file if (index == -1) // get previous file
{ {
if (curr_file) rootname1 = file_rootname(curr_file); // current file rootname if (curr_file) rootname1 = file_rootname(curr_file); // current file rootname
while (true) while (true)
{ {
Nth -= 1; Nth -= 1;
if (Nth < Gfolders) goto retnull; // no more files if (Nth < Gfolders) goto retnull; // no more files
if (file) zfree(file); file = gallery(0,"getR",Nth);
file = gallery(0,"get",Nth); // get previous file 23.1
// get previous file
if (! file) goto retnull; if (! file) goto retnull;
if (! lastver) goto retfile; // return all versions if (! lastver) goto retfile; // return all versions
if (! rootname1) goto retfile; // no current file - return previous file if (! rootname1) goto retfile; // no current file - return previous file
if (rootname2) zfree(rootname2); if (rootname2) zfree(rootname2);
rootname2 = file_rootname(file); rootname2 = file_rootname(file);
if (! strmatch(rootname1,rootname2)) goto retfile; // new rootname, return this file if (! strmatch(rootname1,rootname2)) goto retfile; // new rootname, return this file
} }
} }
retnull: retnull:
if (file) zfree(file);
file = 0; file = 0;
retfile: retfile:
if (rootname1) zfree(rootname1); if (rootname1) zfree(rootname1);
if (rootname2) zfree(rootname2); if (rootname2) zfree(rootname2);
return file; return file;
} }
/******************************************************************************* */ /******************************************************************************* */
// Find the previous or next gallery from the current gallery. // Find the previous or next gallery from the current gallery.
// (previous/next defined by subfolder sequence in parent folder) // (previous/next defined by subfolder sequence in parent folder)
// returned gallery is subject for zfree(). // returned gallery is subject for zfree().
char * prev_next_gallery(int index) ch * prev_next_gallery(int index)
{ {
int nn, Nth; int nn, Nth;
char *parentdir = 0, *olddir = 0, *newdir = 0, *file = 0; ch *parentdir = 0, *olddir = 0, *newdir = 0, *file = 0;
if (gallerytype != FOLDER) goto errret; // gallery not a physical folder if (gallerytype != FOLDER) goto errret; // gallery not a physical folder
olddir = zstrdup(galleryname,"prev-next-gallery"); // olddir = current gallery / folder olddir = zstrdup(galleryname,"prev-next-gallery"); // olddir = current gallery / folder
if (! olddir) goto errret; if (! olddir) goto errret;
nn = strlen(olddir) - 1; nn = strlen(olddir) - 1;
if (olddir[nn] == '/') olddir[nn] = 0; if (olddir[nn] == '/') olddir[nn] = 0;
parentdir = zstrdup(olddir,"prev-next-gallery"); // get parent folder parentdir = zstrdup(olddir,"prev-next-gallery"); // get parent folder
for (NOP; nn && parentdir[nn] != '/'; nn--) for (NOP; nn && parentdir[nn] != '/'; nn--)
if (! nn) goto errret; if (! nn) goto errret;
skipping to change at line 2523 skipping to change at line 2507
return newdir; return newdir;
} }
/******************************************************************************* */ /******************************************************************************* */
// Get file position in gallery file list. // Get file position in gallery file list.
// If Nth position matches file, this is returned. // If Nth position matches file, this is returned.
// Otherwise the list is searched from position 0. // Otherwise the list is searched from position 0.
// Position 0-last is returned if found, or -1 if not. // Position 0-last is returned if found, or -1 if not.
int file_position(cchar *file, int Nth) int file_position(ch *file, int Nth)
{ {
int ii; int ii;
if (! Gimages) return -1; if (! Gimages) return -1;
if (! file) return -1; if (! file) return -1;
if (Nth >= Gfolders && Nth < Gfiles) if (Nth >= Gfolders && Nth < Gfiles)
if (strmatch(file,Gindex[Nth].file)) return Nth; if (strmatch(file,Gindex[Nth].file)) return Nth;
for (ii = Gfolders; ii < Gfiles; ii++) for (ii = Gfolders; ii < Gfiles; ii++)
if (strmatch(file,Gindex[ii].file)) break; if (strmatch(file,Gindex[ii].file)) break;
if (ii < Gfiles) return ii; if (ii < Gfiles) return ii;
return -1; return -1;
} }
/******************************************************************************* */ /******************************************************************************* */
// Determine if a file is a folder or a supported image file type // Determine if a file is a folder or a supported image file type
FTYPE image_file_type(cchar *file) FTYPE image_file_type(ch *file)
{ {
int err, xcc, tcc; int err, xcc, tcc;
static int ftf = 1, tdcc = 0; static int ftf = 1, tdcc = 0;
cchar *ppx; ch *ppx;
char ppx2[8], *ppt, *RP; ch ppx2[8], *ppt, *RP;
STATB statB; STATB statB;
if (ftf) { if (ftf) {
if (thumbfolder && *thumbfolder == '/') // thumbnail top folder if (thumbfolder && *thumbfolder == '/') // thumbnail top folder
tdcc = strlen(thumbfolder); tdcc = strlen(thumbfolder);
myRAWtypes = zstrdup(" ","file-type"); // clear cache of found file types myRAWtypes = zstrdup(" ","file-type"); // clear cache of found file types
myVIDEOtypes = zstrdup(" ","file-type"); myVIDEOtypes = zstrdup(" ","file-type");
ftf = 0; ftf = 0;
} }
skipping to change at line 2608 skipping to change at line 2592
strcpy(ppx2+xcc," "); strcpy(ppx2+xcc," ");
zfree(RP); zfree(RP);
if (strcasestr(imagefiletypes,ppx2)) return IMAGE; // supported image type if (strcasestr(imagefiletypes,ppx2)) return IMAGE; // supported image type
if (strcasestr(myRAWtypes,ppx2))return RAW; // one of my RAW types if (strcasestr(myRAWtypes,ppx2))return RAW; // one of my RAW types
if (strcasestr(myVIDEOtypes,ppx2)) return VIDEO; // one of my VIDEO types if (strcasestr(myVIDEOtypes,ppx2)) return VIDEO; // one of my VIDEO types
if (strcasestr(RAWfiletypes,ppx2)) { // found in list of known RAW types if (strcasestr(RAWfiletypes,ppx2)) { // found in list of known RAW types
tcc = strlen(myRAWtypes) + xcc + 2; tcc = strlen(myRAWtypes) + xcc + 2;
ppt = (char *) zmalloc(tcc,"file-type"); // add to cache of my RAW types ppt = (ch *) zmalloc(tcc,"file-type"); // add to cache of my RAW types
strcpy(ppt,ppx2); strcpy(ppt,ppx2);
strcpy(ppt+xcc+1,myRAWtypes); strcpy(ppt+xcc+1,myRAWtypes);
zfree(myRAWtypes); zfree(myRAWtypes);
myRAWtypes = ppt; myRAWtypes = ppt;
return RAW; return RAW;
} }
if (! Ffmpeg) return OTHER; // missing ffmpeg program if (! Ffmpeg) return OTHER; // missing ffmpeg program
if (strcasestr(VIDEOfiletypes,ppx2)) { // found in known VIDEO types if (strcasestr(VIDEOfiletypes,ppx2)) { // found in known VIDEO types
tcc = strlen(myVIDEOtypes) + xcc + 2; tcc = strlen(myVIDEOtypes) + xcc + 2;
ppt = (char *) zmalloc(tcc,"file-type"); // add to cache of my VIDEO types ppt = (ch *) zmalloc(tcc,"file-type"); // add to cache of my VIDEO types
strcpy(ppt,ppx2); strcpy(ppt,ppx2);
strcpy(ppt+xcc+1,myVIDEOtypes); strcpy(ppt+xcc+1,myVIDEOtypes);
zfree(myVIDEOtypes); zfree(myVIDEOtypes);
myVIDEOtypes = ppt; myVIDEOtypes = ppt;
return VIDEO; return VIDEO;
} }
return OTHER; // not a known image file type return OTHER; // not a known image file type
} }
/******************************************************************************* */ /******************************************************************************* */
// Given a thumbnail file, get the corresponding image file. // Given a thumbnail file, get the corresponding image file.
// Returns null if no image file found. // Returns null if no image file found.
// Returned file is subject for zfree(). // Returned file is subject for zfree().
// image file: /image/folder/file.xxx // image file: /image/folder/file.xxx
// thumb folder: /thumb/folder // thumb folder: /thumb/folder
// thumb file: /thumb/folder/image/folder/file.xxx.jpeg // thumb file: /thumb/folder/image/folder/file.xxx.jpeg
char * thumb2imagefile(cchar *thumbfile) // simplified ch * thumb2imagefile(ch *thumbfile) // simplified
{ {
uint cc; uint cc;
char *imagefile; ch *imagefile;
static int Fdone = 0; static int Fdone = 0;
if (! thumbfolder || *thumbfolder != '/') { if (! thumbfolder || *thumbfolder != '/') {
if (! Fdone) Plog(0,"%s \n","no thumbnail folder"); if (! Fdone) Plog(0,"%s \n","no thumbnail folder");
Fdone++; Fdone++;
return 0; return 0;
} }
cc = strlen(thumbfolder); cc = strlen(thumbfolder);
if (cc > strlen(thumbfile) - 12) { // /thumbfolder/imagefolder/file.xxx.jpeg if (cc > strlen(thumbfile) - 12) { // /thumbfolder/imagefolder/file.xxx.jpeg
skipping to change at line 2670 skipping to change at line 2654
imagefile[cc-5] = 0; // /imagefolder/file.xxx imagefile[cc-5] = 0; // /imagefolder/file.xxx
if (regfile(imagefile)) return imagefile; // return if exists if (regfile(imagefile)) return imagefile; // return if exists
zfree(imagefile); // not found zfree(imagefile); // not found
return 0; return 0;
} }
// Given an image file, get the corresponding thumbnail file. // Given an image file, get the corresponding thumbnail file.
// The filespec is returned whether or not the file exists. // The filespec is returned whether or not the file exists.
// Returned file is subject for zfree(). // Returned file is subject for zfree().
char * image2thumbfile(cchar *imagefile) // simplified ch * image2thumbfile(ch *imagefile) // simplified
{ {
int cc1, cc2; int cc1, cc2;
char *RP, *thumbfile; ch *RP, *thumbfile;
static int Fdone = 0; static int Fdone = 0;
if (! thumbfolder || *thumbfolder != '/') { if (! thumbfolder || *thumbfolder != '/') {
if (! Fdone++) Plog(0,"%s \n","no thumbnail folder"); if (! Fdone++) Plog(0,"%s \n","no thumbnail folder");
return 0; return 0;
} }
RP = f_realpath(imagefile); // use real path RP = f_realpath(imagefile); // use real path
if (! RP) return 0; if (! RP) return 0;
if (! regfile(RP)) { zfree(RP); return 0; } if (! regfile(RP)) { zfree(RP); return 0; }
cc1 = strlen(thumbfolder); cc1 = strlen(thumbfolder);
cc2 = strlen(RP); cc2 = strlen(RP);
thumbfile = (char *) zmalloc(cc1+cc2+6,"image2thumbfile"); thumbfile = (ch *) zmalloc(cc1+cc2+6,"image2thumbfile");
strcpy(thumbfile,thumbfolder); // /thumb/folder strcpy(thumbfile,thumbfolder); // /thumb/folder
strcpy(thumbfile+cc1,RP); // .../image/folder/file.xxx strcpy(thumbfile+cc1,RP); // .../image/folder/file.xxx
strcpy(thumbfile+cc1+cc2,".jpeg"); // .../image/folder/file.xxx.jpeg strcpy(thumbfile+cc1+cc2,".jpeg"); // .../image/folder/file.xxx.jpeg
zfree(RP); zfree(RP);
return thumbfile; return thumbfile;
} }
// version to avoid use of zmalloc() & zfree() // version to avoid use of zmalloc() & zfree()
// output: char thumbfile[XFCC] // output: ch thumbfile[XFCC]
// returns 0 if OK, 1 if image file not found // returns 0 if OK, 1 if image file not found
int image2thumbfile2(cchar *imagefile, char *thumbfile) int image2thumbfile2(ch *imagefile, ch *thumbfile)
{ {
int cc1, cc2; int cc1, cc2;
char *RP; ch *RP;
static int Fdone = 0; static int Fdone = 0;
*thumbfile = 0; *thumbfile = 0;
if (! thumbfolder || *thumbfolder != '/') { if (! thumbfolder || *thumbfolder != '/') {
if (! Fdone++) Plog(0,"no thumbnail folder\n"); if (! Fdone++) Plog(0,"no thumbnail folder\n");
return 1; return 1;
} }
RP = f_realpath(imagefile); // use real path RP = f_realpath(imagefile); // use real path
skipping to change at line 2729 skipping to change at line 2713
zfree(RP); zfree(RP);
return 0; return 0;
} }
/******************************************************************************* */ /******************************************************************************* */
// check if thumbnail file is missing or stale. // check if thumbnail file is missing or stale.
// returns 1 new thumbnail NOT needed // returns 1 new thumbnail NOT needed
// 0 new thumbnail needed // 0 new thumbnail needed
int thumbfile_OK(cchar *imagefile) int thumbfile_OK(ch *imagefile)
{ {
int ftype; int ftype;
STATB statF, statB; STATB statF, statB;
char thumbfile[XFCC]; ch thumbfile[XFCC];
if (! regfile(imagefile,&statF)) return 1; // bad image file if (! regfile(imagefile,&statF)) return 1; // bad image file
ftype = image_file_type(imagefile); ftype = image_file_type(imagefile);
if (ftype != IMAGE && ftype != RAW && ftype != VIDEO) return 1; // not an image file or RAW file if (ftype != IMAGE && ftype != RAW && ftype != VIDEO) return 1; // not an image file or RAW file
image2thumbfile2(imagefile,thumbfile); // get thumbnail file for image file image2thumbfile2(imagefile,thumbfile); // get thumbnail file for image file
if (! regfile(thumbfile,&statB)) return 0; // thumbfile FNF if (! regfile(thumbfile,&statB)) return 0; // thumbfile FNF
if (statB.st_mtime != statF.st_mtime) return 0; // thumbnail is stale if (statB.st_mtime != statF.st_mtime) return 0; // thumbnail is stale
return 1; // thumbnail is up to date return 1; // thumbnail is up to date
skipping to change at line 2757 skipping to change at line 2741
// get "folder" or "broken" pixbuf using cached pixbuf image // get "folder" or "broken" pixbuf using cached pixbuf image
// caller must avoid gdk_object_unref() of returned pixbuf // caller must avoid gdk_object_unref() of returned pixbuf
PIXBUF * get_folder_pixbuf() PIXBUF * get_folder_pixbuf()
{ {
static int ftf = 1; static int ftf = 1;
static PIXBUF *bigpixbuf = 0; static PIXBUF *bigpixbuf = 0;
static PIXBUF *pixbuf = 0; static PIXBUF *pixbuf = 0;
static int psize = -1; static int psize = -1;
static char thumbfile[300] = ""; static ch thumbfile[300] = "";
GError *gerror = 0; GError *gerror = 0;
if (ftf) { if (ftf) {
ftf = 0; ftf = 0;
strncatv(thumbfile,300,zfuncs::zimagedir,"/folder.png",0); strncatv(thumbfile,300,zfuncs::zimagedir,"/folder.png",0);
bigpixbuf = gdk_pixbuf_new_from_file(thumbfile,&gerror); bigpixbuf = gdk_pixbuf_new_from_file(thumbfile,&gerror);
if (! bigpixbuf) { if (! bigpixbuf) {
Plog(0,"cannot make folder pixbuf: "); Plog(0,"cannot make folder pixbuf: ");
if (gerror) Plog(0,"%s",gerror->message); if (gerror) Plog(0,"%s",gerror->message);
Plog(0,"\n"); Plog(0,"\n");
skipping to change at line 2785 skipping to change at line 2769
psize = thumbsize; psize = thumbsize;
return pixbuf; return pixbuf;
} }
PIXBUF * get_broken_pixbuf() PIXBUF * get_broken_pixbuf()
{ {
static int ftf = 1; static int ftf = 1;
static PIXBUF *bigpixbuf = 0; static PIXBUF *bigpixbuf = 0;
static PIXBUF *pixbuf = 0; static PIXBUF *pixbuf = 0;
static int psize = -1; static int psize = -1;
static char thumbfile[300] = ""; static ch thumbfile[300] = "";
GError *gerror = 0; GError *gerror = 0;
if (ftf) { if (ftf) {
ftf = 0; ftf = 0;
strncatv(thumbfile,300,zfuncs::zimagedir,"/broken.png",0); strncatv(thumbfile,300,zfuncs::zimagedir,"/broken.png",0);
bigpixbuf = gdk_pixbuf_new_from_file(thumbfile,&gerror); bigpixbuf = gdk_pixbuf_new_from_file(thumbfile,&gerror);
if (! bigpixbuf) { if (! bigpixbuf) {
Plog(0,"cannot make broken pixbuf: "); Plog(0,"cannot make broken pixbuf: ");
if (gerror) Plog(0,"%s",gerror->message); if (gerror) Plog(0,"%s",gerror->message);
Plog(0,"\n"); Plog(0,"\n");
skipping to change at line 2814 skipping to change at line 2798
return pixbuf; return pixbuf;
} }
/******************************************************************************* */ /******************************************************************************* */
// create or replace thumbnail file if missing or stale. // create or replace thumbnail file if missing or stale.
// returns 0 thumbnail exists already, nothing was done (OK) // returns 0 thumbnail exists already, nothing was done (OK)
// 1 new thumbnail file created (OK) // 1 new thumbnail file created (OK)
// 2 cannot create PXB or make thumbnail file (error) // 2 cannot create PXB or make thumbnail file (error)
int update_thumbfile(cchar *imagefile) int update_thumbfile(ch *imagefile)
{ {
char *pp, thumbfile[XFCC]; ch *pp, thumbfile[XFCC];
PXB *imagepxb = 0, *thumbpxb = 0; PXB *imagepxb = 0, *thumbpxb = 0;
STATB statB; STATB statB;
int err, size, retstat; int err, size, retstat;
timeval thumbtimes[2]; timeval thumbtimes[2];
if (thumbfile_OK(imagefile)) return 0; // thumbnail file exists, not stale if (thumbfile_OK(imagefile)) return 0; // thumbnail file exists, not stale
err = image2thumbfile2(imagefile,thumbfile); // get thumbnail file for image file err = image2thumbfile2(imagefile,thumbfile); // get thumbnail file for image file
if (err) { retstat = 2; goto returnx; } if (err) { retstat = 2; goto returnx; }
skipping to change at line 2839 skipping to change at line 2823
*pp = 0; *pp = 0;
if (! dirfile(thumbfile)) // create thumbnail folder if needed if (! dirfile(thumbfile)) // create thumbnail folder if needed
err = zshell(0,"mkdir -p -m 0750 \"%s\"",thumbfile); err = zshell(0,"mkdir -p -m 0750 \"%s\"",thumbfile);
*pp = '/'; *pp = '/';
if (err && errno != EEXIST) { // happens, threads if (err && errno != EEXIST) { // happens, threads
Plog(0,"thumbnail mkdir failure: %s\n %s\n",thumbfile,strerror(errno)); Plog(0,"thumbnail mkdir failure: %s\n %s\n",thumbfile,strerror(errno));
retstat = 2; retstat = 2;
goto returnx; goto returnx;
} }
pp = (char *) strrchr(imagefile,'.'); pp = (ch *) strrchr(imagefile,'.');
if (! pp) { retstat = 2; goto returnx; } if (! pp) { retstat = 2; goto returnx; }
size = thumbfilesize; size = thumbfilesize;
if (strcasestr(".jpg .jpeg",pp)) if (strcasestr(".jpg .jpeg",pp))
thumbpxb = JPG_PXB_load(imagefile,size); // load JPEG file to PXB (reduced) thumbpxb = JPG_PXB_load(imagefile,size); // load JPEG file to PXB (reduced)
else if (strmatchcase(pp,".MPO")) // .MPO file (3D pair) else if (strmatchcase(pp,".MPO")) // .MPO file (3D pair)
thumbpxb = MPO_PXB_load(imagefile,size); // extract and load JPEG (reduced) thumbpxb = MPO_PXB_load(imagefile,size); // extract and load JPEG (reduced)
skipping to change at line 2882 skipping to change at line 2866
if (imagepxb) PXB_free(imagepxb); if (imagepxb) PXB_free(imagepxb);
if (thumbpxb) PXB_free(thumbpxb); if (thumbpxb) PXB_free(thumbpxb);
return retstat; return retstat;
} }
/******************************************************************************* */ /******************************************************************************* */
// Update thumbnail mod time to match corresponding image file // Update thumbnail mod time to match corresponding image file
// (avoid thumbnail refresh when image file metadata is modified) // (avoid thumbnail refresh when image file metadata is modified)
int thumbfile_set_mod_time(cchar *imagefile) int thumbfile_set_mod_time(ch *imagefile)
{ {
STATB statB; STATB statB;
char thumbfile[XFCC]; ch thumbfile[XFCC];
int err; int err;
timeval thumbtimes[2]; timeval thumbtimes[2];
if (! regfile(imagefile,&statB)) return ENOENT; // get image file mod time if (! regfile(imagefile,&statB)) return ENOENT; // get image file mod time
image2thumbfile2(imagefile,thumbfile); // get thumbnail file for image file image2thumbfile2(imagefile,thumbfile); // get thumbnail file for image file
if (! regfile(thumbfile)) return ENOENT; if (! regfile(thumbfile)) return ENOENT;
thumbtimes[0].tv_sec = thumbtimes[1].tv_sec = statB.st_mtim.tv_sec; // thumbnail mod time thumbtimes[0].tv_sec = thumbtimes[1].tv_sec = statB.st_mtim.tv_sec; // thumbnail mod time
thumbtimes[0].tv_usec = thumbtimes[1].tv_usec = 0; // = image file mod time thumbtimes[0].tv_usec = thumbtimes[1].tv_usec = 0; // = image file mod time
err = utimes(thumbfile,thumbtimes); err = utimes(thumbfile,thumbtimes);
return err; return err;
} }
/******************************************************************************* */ /******************************************************************************* */
// Remove thumbnail from disk (for deleted or renamed image file). // Remove thumbnail from disk (for deleted or renamed image file).
void delete_thumbfile(cchar *imagefile) void delete_thumbfile(ch *imagefile)
{ {
int err; int err;
char thumbfile[XFCC]; ch thumbfile[XFCC];
err = image2thumbfile2(imagefile,thumbfile); // get thumbnail file for image file err = image2thumbfile2(imagefile,thumbfile); // get thumbnail file for image file
if (err) return; if (err) return;
remove(thumbfile); remove(thumbfile);
return; return;
} }
/******************************************************************************* * /******************************************************************************* *
skipping to change at line 2938 skipping to change at line 2922
image file --> get_cache_thumb() <--> thumb cache (get/put) image file --> get_cache_thumb() <--> thumb cache (get/put)
| --> PIXBUF returned | --> PIXBUF returned
V V
image file --> update_thumbfile() --> thumb file on disk image file --> update_thumbfile() --> thumb file on disk
******************************************************************************** */ ******************************************************************************** */
namespace thumbnail_cache namespace thumbnail_cache
{ {
int ftf = 1; int ftf = 1;
char lockname[200]; ch lockname[200];
int cachesize = 2000; int cachesize = 1000;
// max thumbnails cached in memory // max thumbnails cached in memory 23.1
int maxhash = 5 * cachesize; // hash table, 5x cache size int maxhash = 5 * cachesize; // hash table, 5x cache size
int hashw = 20; // hash search width int hashw = 20; // hash search width
typedef struct { typedef struct {
char *imagefile; ch *imagefile;
PXB *pxb; // PXB with congruent pixbuf PXB *pxb; // PXB with congruent pixbuf
time_t mtime; time_t mtime;
int size; int size;
} thumbtab_t; } thumbtab_t;
char **filetab; // cached imagefiles ch **filetab; // cached imagefiles
int *indextab; // corresp. thumbtab indexes int *indextab; // corresp. thumbtab indexes
thumbtab_t *thumbtab; // corresp. cached thumbtab thumbtab_t *thumbtab; // corresp. cached thumbtab
int nextcache = 0; int nextcache = 0;
} }
// initialize cache at first call // initialize cache at first call
void init_cache_thumb() void init_cache_thumb()
{ {
using namespace thumbnail_cache; using namespace thumbnail_cache;
int cc; int cc;
ftf = 0; ftf = 0;
cc = (maxhash + hashw) * sizeof(char *); cc = (maxhash + hashw) * sizeof(ch *);
// allocate table space and clear // allocate table space and clear
filetab = (char **) zmalloc(cc,"thumb cache"); filetab = (ch **) zmalloc(cc,"thumb cache");
// (+ hashw to avoid wraparound logic) // (+ hashw to avoid wraparound logic)
memset(filetab,0,cc); memset(filetab,0,cc);
cc = (maxhash + hashw) * sizeof(int); cc = (maxhash + hashw) * sizeof(int);
indextab = (int *) zmalloc(cc,"thumb cache"); indextab = (int *) zmalloc(cc,"thumb cache");
memset(indextab,-1,cc); memset(indextab,-1,cc);
cc = cachesize * sizeof(thumbtab_t); cc = cachesize * sizeof(thumbtab_t);
thumbtab = (thumbtab_t *) zmalloc(cc,"thumb cache"); thumbtab = (thumbtab_t *) zmalloc(cc,"thumb cache");
preload_thumbs_start(); // start preload thumbs threads preload_thumbs_start(); // start preload thumbs threads
return; return;
} }
// get thumbnail from cache, or add to cache if missing // get thumbnail from cache, or add to cache if missing
// use given thumbnail PXB if not null // use given thumbnail PXB if not null
// create new thumbnail file if necessary, create thumbnail PXB // create new thumbnail file if necessary, create thumbnail PXB
PIXBUF * get_cache_thumb(cchar *imagefile, PXB *thumbpxb) PIXBUF * get_cache_thumb(ch *imagefile, PXB *thumbpxb)
{ {
using namespace thumbnail_cache; using namespace thumbnail_cache;
PXB *tempxb = 0; PXB *tempxb = 0;
char thumbfile[XFCC]; ch thumbfile[XFCC];
char *purgefile; ch *purgefile;
int Fii, Tii, Pii; int Fii, Tii, Pii;
int ii, err; int ii, err;
FTYPE ftype; FTYPE ftype;
time_t mtime; time_t mtime;
STATB statB; STATB statB;
if (ftf) init_cache_thumb(); // first call if (ftf) init_cache_thumb(); // first call
if (thumbsize == 0) return 0; // should not happen if (thumbsize == 0) return 0; // should not happen
skipping to change at line 3129 skipping to change at line 3113
resource_unlock(TClock); resource_unlock(TClock);
Plog(0,"get_cache_thumb() purgefile not in filetab \n"); Plog(0,"get_cache_thumb() purgefile not in filetab \n");
return get_broken_pixbuf(); return get_broken_pixbuf();
} }
// check if thumbnail and thumbsize is currently in the thumbnail cache // check if thumbnail and thumbsize is currently in the thumbnail cache
// return 0 if not found // return 0 if not found
// return 1 if found, or not needed (not image, not found, folder) // return 1 if found, or not needed (not image, not found, folder)
// used by preload_thumbs() // used by preload_thumbs()
int check_cache_thumb(cchar *imagefile) int check_cache_thumb(ch *imagefile)
{ {
using namespace thumbnail_cache; using namespace thumbnail_cache;
int ii, Fii, Tii; int ii, Fii, Tii;
FTYPE ftype; FTYPE ftype;
time_t mtime; time_t mtime;
STATB statB; STATB statB;
if (ftf) init_cache_thumb(); // first call if (ftf) init_cache_thumb(); // first call
skipping to change at line 3173 skipping to change at line 3157
Plog(0,"check_cache_thumb() index tab entry missing \n"); Plog(0,"check_cache_thumb() index tab entry missing \n");
return 0; return 0;
bug1: bug1:
Plog(0,"check_cache_thumb() indextab thumbtab no match \n"); Plog(0,"check_cache_thumb() indextab thumbtab no match \n");
return 0; return 0;
} }
// replace current cached thumbnail from updated thumbnail file // replace current cached thumbnail from updated thumbnail file
int replace_cache_thumb(cchar *imagefile, PXB *thumbpxb) int replace_cache_thumb(ch *imagefile, PXB *thumbpxb)
{ {
using namespace thumbnail_cache; using namespace thumbnail_cache;
int ii, Fii, Tii; int ii, Fii, Tii;
FTYPE ftype; FTYPE ftype;
time_t mtime; time_t mtime;
STATB statB; STATB statB;
PXB *thumbpxb2; PXB *thumbpxb2;
if (ftf) init_cache_thumb(); // first call if (ftf) init_cache_thumb(); // first call
skipping to change at line 3235 skipping to change at line 3219
{ {
void * preload_thumbs_thread(void *); void * preload_thumbs_thread(void *);
start_detached_thread(preload_thumbs_thread,0); start_detached_thread(preload_thumbs_thread,0);
return; return;
} }
// thread function - add thumbnails to thumbnail cache ahead of need // thread function - add thumbnails to thumbnail cache ahead of need
void * preload_thumbs_thread(void *) // thread runs continuously void * preload_thumbs_thread(void *) // thread runs continuously
{ {
int check_cache_thumb(cchar *imagefile); int check_cache_thumb(ch *imagefile);
int ii, jj, err, fnn, size; int ii, jj, err, fnn, size;
char thumbfile[XFCC]; ch thumbfile[XFCC];
PXB *tempxb = 0, *thumbpxb = 0; PXB *tempxb = 0, *thumbpxb = 0;
static char *imagefile = 0; static ch *imagefile = 0;
static int last_preload_start = 0; static int last_preload_start = 0;
while (true) // loop forever while (true) // loop forever
{ {
while (preload_trigger == 0) zsleep(0.001); // wait for gallery page change while (preload_trigger == 0) zsleep(0.001); // wait for gallery page change
preload_trigger = 0; preload_trigger = 0;
if (preload_start == last_preload_start) continue; if (preload_start == last_preload_start) continue;
last_preload_start = preload_start; last_preload_start = preload_start;
while (! resource_lock(GFlock)) zsleep(0.0001); // gallery is changing 22.30 while (! resource_lock(GFlock)) zsleep(0.0001); // gallery is changing 22.30
for (ii = 0; ii < 100; ii++) // look ahead 100 files for (ii = 0; ii < 100; ii++) // look ahead 100 files
{ {
if (FGWM != 'G') break; // not gallery view if (FGWM != 'G') break; // not gallery view
fnn = preload_start + ii; // gallery page last file + ii fnn = preload_start + ii; // gallery page last file + ii
if (fnn > Gfiles-1) break; // beyond last gallery file if (fnn > Gfiles-1) break; // beyond last gallery file
if (! Gindex[fnn].file) break; if (! Gindex[fnn].file) break;
if (Gindex[fnn].file[0] == '!') continue; // folder if (Gindex[fnn].folder) continue; // folder 23.1
if (imagefile) zfree(imagefile); // protect against gallery change 22.30 if (imagefile) zfree(imagefile); // protect against gallery change 22.30
imagefile = zstrdup(Gindex[fnn].file,"preload"); imagefile = zstrdup(Gindex[fnn].file,"preload");
jj = check_cache_thumb(imagefile); // thumbnail in cache already? jj = check_cache_thumb(imagefile); // thumbnail in cache already?
if (jj) continue; // yes if (jj) continue; // yes
err = update_thumbfile(imagefile); // check/create thumbnail file err = update_thumbfile(imagefile); // check/create thumbnail file
if (err > 1) continue; // fail if (err > 1) continue; // fail
skipping to change at line 3302 skipping to change at line 3286
} }
} }
/******************************************************************************* */ /******************************************************************************* */
// popup a new window with a larger image of a clicked thumbnail // popup a new window with a larger image of a clicked thumbnail
void gallery_popimage() void gallery_popimage()
{ {
static int ftf = 1, ii; static int ftf = 1, ii;
static char *popfiles[20]; // last 20 files static ch *popfiles[20]; // last 20 files
int ftype; int ftype;
if (ftf) { if (ftf) {
ftf = 0; // initz. empty file memory ftf = 0; // initz. empty file memory
for (ii = 0; ii < 20; ii++) for (ii = 0; ii < 20; ii++)
popfiles[ii] = 0; popfiles[ii] = 0;
ii = 0; ii = 0;
} }
if (! clicked_file) return; if (! clicked_file) return;
skipping to change at line 3332 skipping to change at line 3316
popup_image(popfiles[ii],MWIN,1,512); // popup window with image popup_image(popfiles[ii],MWIN,1,512); // popup window with image
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// select one image file by clicking a gallery thumbnail // select one image file by clicking a gallery thumbnail
// returned file is subject for zfree() // returned file is subject for zfree()
char galsel1_filename[XFCC]; ch galsel1_filename[XFCC];
char * gallery_select1(cchar *gfolder) ch * gallery_select1(ch *gfolder)
{ {
zdialog *zd; zdialog *zd;
int zstat; int zstat;
char *cfolder; ch *cfolder;
char fgwm[4]; ch fgwm[4];
fgwm[0] = FGWM; // save current view mode fgwm[0] = FGWM; // save current view mode
fgwm[1] = 0; fgwm[1] = 0;
cfolder = zstrdup(navi::galleryname,"gallery-select"); // and gallery folder cfolder = zstrdup(navi::galleryname,"gallery-select"); // and gallery folder
if (gfolder) { if (gfolder) {
gallery(gfolder,"init",0); // switch to caller's gallery gallery(gfolder,"init",0); // switch to caller's gallery
gallery(0,"sort",-2); // recall sort and position gallery(0,"sort",-2); // recall sort and position
gallery(0,"paint",-1); // paint gallery(0,"paint",-1); // paint
} }
skipping to change at line 3398 skipping to change at line 3382
if (zstat != 1) return 0; // no selection if (zstat != 1) return 0; // no selection
if (*galsel1_filename != '/') return 0; if (*galsel1_filename != '/') return 0;
if (! regfile(galsel1_filename)) return 0; // FNF if (! regfile(galsel1_filename)) return 0; // FNF
return f_realpath(galsel1_filename); // use real path return f_realpath(galsel1_filename); // use real path
} }
void gallery_select1_Lclick_func(int Nth) // called by gallery mouse function void gallery_select1_Lclick_func(int Nth) // called by gallery mouse function
{ {
char *imagefile = 0, *pp; ch *imagefile = 0, *pp;
int ftype; int ftype;
if (! zd_gallery_select1) return; // should not happen if (! zd_gallery_select1) return; // should not happen
if (Nth < 0) return; if (Nth < 0) return;
imagefile = gallery(0,"get",Nth); // get file at clicked position imagefile = gallery(0,"get",Nth); // get file at clicked position
if (! imagefile) return; if (! imagefile) return;
ftype = image_file_type(imagefile); // must be image or RAW file ftype = image_file_type(imagefile); // must be image or RAW file
if (ftype != IMAGE && ftype != RAW) { if (ftype != IMAGE && ftype != RAW) {
skipping to change at line 3431 skipping to change at line 3415
/******************************************************************************* */ /******************************************************************************* */
// Select multiple image files from thumbnail gallery window. // Select multiple image files from thumbnail gallery window.
// GSfiles[*]: list of selected image files, GScount entries. // GSfiles[*]: list of selected image files, GScount entries.
// Pre-selected files are passed in the same list, which is updated. // Pre-selected files are passed in the same list, which is updated.
// The dialog shows the list of files selected and can be edited. // The dialog shows the list of files selected and can be edited.
// Returned status: 0 = OK, 1 = user cancel, 2 = internal error // Returned status: 0 = OK, 1 = user cancel, 2 = internal error
namespace galselnames namespace galselnames
{ {
int dialog_event(zdialog *zd, cchar *event); int dialog_event(zdialog *zd, ch *event);
int find_file(cchar *imagefile); int find_file(ch *imagefile);
void insert_file(cchar *imagefile); void insert_file(ch *imagefile);
void remove_file(cchar *imagefile); void remove_file(ch *imagefile);
void Xclick_func(int Nth, char LR); void Xclick_func(int Nth, ch LR);
void callbackfunc(GtkWidget *textwidget, int line, int posn, int KBkey); void callbackfunc(GtkWidget *textwidget, int line, int posn, int KBkey);
void showthumb(); void showthumb();
GtkWidget *drawarea = 0; GtkWidget *drawarea = 0;
GtkWidget *Ftext = 0; GtkWidget *Ftext = 0;
int currline; int currline;
char *imagefile; ch *imagefile;
}; };
void gallery_select_clear() void gallery_select_clear()
{ {
using namespace galselnames; using namespace galselnames;
for (int ii = 0; ii < GScount; ii++) zfree(GSfiles[ii]); for (int ii = 0; ii < GScount; ii++) zfree(GSfiles[ii]);
GScount = 0; GScount = 0;
return; return;
} }
skipping to change at line 3584 skipping to change at line 3568
GScount = kk; GScount = kk;
} }
zdialog_free(zd); // kill dialog zdialog_free(zd); // kill dialog
zd_gallery_select = 0; zd_gallery_select = 0;
return 0; return 0;
} }
// gallery getfiles dialog event function // gallery getfiles dialog event function
int galselnames::dialog_event(zdialog *zd, cchar *event) int galselnames::dialog_event(zdialog *zd, ch *event)
{ {
using namespace galselnames; using namespace galselnames;
char *file, *ftemp; ch *file, *ftemp;
static char *removedfiles[100]; static ch *removedfiles[100];
// last 100 files removed // last 100 files removed
static int Nremoved = 0; static int Nremoved = 0;
int ii, Nth; int ii, Nth;
FTYPE ftype; FTYPE ftype;
if (strmatch(event,"escape")) zd->zstat = -2; // escape key if (strmatch(event,"escape")) zd->zstat = -2; // escape key
if (zd->zstat) { if (zd->zstat) {
if (zd->zstat == -1) { if (zd->zstat == -1) {
zd_gallery_select = 0; // [x] kill dialog 22.1 zd_gallery_select = 0; // [x] kill dialog 22.1
gallery(0,"paint",-1); gallery(0,"paint",-1);
skipping to change at line 3683 skipping to change at line 3667
if (strmatch(event,"addall")) // insert all files in image gallery if (strmatch(event,"addall")) // insert all files in image gallery
{ {
for (Nth = 0; ; Nth++) for (Nth = 0; ; Nth++)
{ {
if (GSselect == GSmax) { if (GSselect == GSmax) {
zmessageACK(Mwin,"exceed %d selected files",GSmax); zmessageACK(Mwin,"exceed %d selected files",GSmax);
break; break;
} }
ftemp = gallery(0,"get",Nth); // next file ftemp = gallery(0,"getR",Nth); // next file 23.1
if (! ftemp) break; if (! ftemp) break;
ftype = image_file_type(ftemp); // must be image or RAW file ftype = image_file_type(ftemp); // must be image or RAW file
if (ftype != IMAGE && ftype != RAW && ftype != VIDEO) { if (ftype != IMAGE && ftype != RAW && ftype != VIDEO) continue;
zfree(ftemp);
continue;
}
file = f_realpath(ftemp); // use real path file = f_realpath(ftemp); // use real path
if (! file) { if (! file) continue;
zfree(ftemp);
continue;
}
GSselect++; GSselect++;
textwidget_append(Ftext,0,"%s\n",file); // append - could be insert textwidget_append(Ftext,0,"%s\n",file); // append - could be insert
zfree(ftemp);
zfree(file); zfree(file);
} }
textwidget_scroll(Ftext,-1); // scroll to end textwidget_scroll(Ftext,-1); // scroll to end
currline = GSselect - 1; // position at last file currline = GSselect - 1; // position at last file
showthumb(); showthumb();
gallery(0,"paint",-1); // 22.1 gallery(0,"paint",-1); // 22.1
} }
return 1; return 1;
} }
// See if image file is in the file list already or not. // See if image file is in the file list already or not.
// Return the last matching line number or -1 if not found. // Return the last matching line number or -1 if not found.
int galselnames::find_file(cchar *imagefile) int galselnames::find_file(ch *imagefile)
{ {
using namespace galselnames; using namespace galselnames;
int line; int line;
char *ftemp; ch *ftemp;
for (line = GSselect-1; line >= 0; line--) for (line = GSselect-1; line >= 0; line--)
{ {
ftemp = textwidget_line(Ftext,line,1); // get file without \n ftemp = textwidget_line(Ftext,line,1); // get file without \n
if (! ftemp) continue; if (! ftemp) continue;
if (strmatch(ftemp,imagefile)) { if (strmatch(ftemp,imagefile)) {
zfree(ftemp); zfree(ftemp);
return line; return line;
} }
zfree(ftemp); zfree(ftemp);
} }
return -1; return -1;
} }
// add image file to list at current position, set thumbnail = file // add image file to list at current position, set thumbnail = file
void galselnames::insert_file(cchar *imagefile) void galselnames::insert_file(ch *imagefile)
{ {
using namespace galselnames; using namespace galselnames;
int ftype; int ftype;
char *RP; ch *RP;
if (GSselect == GSmax) { if (GSselect == GSmax) {
zmessageACK(Mwin,"exceed %d selected files",GSmax); zmessageACK(Mwin,"exceed %d selected files",GSmax);
return; return;
} }
ftype = image_file_type(imagefile); // must be image or RAW file ftype = image_file_type(imagefile); // must be image or RAW file
if (ftype != IMAGE && ftype != RAW && ftype != VIDEO) return; if (ftype != IMAGE && ftype != RAW && ftype != VIDEO) return;
RP = f_realpath(imagefile); // use real path RP = f_realpath(imagefile); // use real path
if (! RP) return; if (! RP) return;
skipping to change at line 3769 skipping to change at line 3746
textwidget_highlight_line(Ftext,currline); textwidget_highlight_line(Ftext,currline);
textwidget_scroll(Ftext,currline); textwidget_scroll(Ftext,currline);
showthumb(); // update thumbnail showthumb(); // update thumbnail
gallery(0,"paint",-1); // 22.1 gallery(0,"paint",-1); // 22.1
return; return;
} }
// remove image file at last position found, set thumbnail = next // remove image file at last position found, set thumbnail = next
// called when gallery thumbnail is right-clicked // called when gallery thumbnail is right-clicked
void galselnames::remove_file(cchar *imagefile) void galselnames::remove_file(ch *imagefile)
{ {
using namespace galselnames; using namespace galselnames;
int line; int line;
line = find_file(imagefile); // find last instance line = find_file(imagefile); // find last instance
if (line < 0) return; if (line < 0) return;
currline = line; currline = line;
showthumb(); showthumb();
textwidget_delete(Ftext,currline); textwidget_delete(Ftext,currline);
skipping to change at line 3807 skipping to change at line 3784
} }
void gallery_select_Rclick_func(int Nth) // right click, find and remove void gallery_select_Rclick_func(int Nth) // right click, find and remove
{ {
galselnames::Xclick_func(Nth,'R'); galselnames::Xclick_func(Nth,'R');
if (clicked_file) zfree(clicked_file); if (clicked_file) zfree(clicked_file);
clicked_file = 0; clicked_file = 0;
return; return;
} }
void galselnames::Xclick_func(int Nth, char LR) void galselnames::Xclick_func(int Nth, ch LR)
{ {
using namespace galselnames; using namespace galselnames;
char *imagefile; ch *imagefile;
FTYPE ftype; FTYPE ftype;
static int pNth = -1; // previously clicked file static int pNth = -1; // previously clicked file
int nn, incr; int nn, incr;
if (! zd_gallery_select) return; // should not happen if (! zd_gallery_select) return; // should not happen
if (Nth < 0) return; // gallery gone ? if (Nth < 0) return; // gallery gone ?
imagefile = gallery(0,"get",Nth); // get file at clicked position imagefile = gallery(0,"getR",Nth); // get file at clicked position 23.1
if (! imagefile) { if (! imagefile) {
pNth = -1; pNth = -1;
return; return;
} }
ftype = image_file_type(imagefile); // must be image or RAW file ftype = image_file_type(imagefile); // must be image or RAW file
if (ftype != IMAGE && ftype != RAW && ftype != VIDEO) { if (ftype != IMAGE && ftype != RAW && ftype != VIDEO) {
zfree(imagefile);
pNth = -1; pNth = -1;
return; return;
} }
if (LR == 'R') { // right click, unselect if (LR == 'R') { // right click, unselect
remove_file(imagefile); remove_file(imagefile);
zfree(imagefile);
return; return;
} }
if (! KBshiftkey) // no shift key if (! KBshiftkey) // no shift key
{ {
pNth = Nth; // possible start of range pNth = Nth; // possible start of range
insert_file(imagefile); // insert file at current position insert_file(imagefile); // insert file at current position
zfree(imagefile);
return; return;
} }
if (KBshiftkey) // shift key, end of range if (KBshiftkey) // shift key, end of range
{ {
if (pNth < 0) return; // no start of range, ignore if (pNth < 0) return; // no start of range, ignore
if (pNth > Nth) incr = -1; // range is descending if (pNth > Nth) incr = -1; // range is descending
else incr = +1; // ascending else incr = +1; // ascending
for (nn = pNth+incr; nn != Nth+incr; nn += incr) // add all files from pNth to Nth for (nn = pNth+incr; nn != Nth+incr; nn += incr) // add all files from pNth to Nth
{ // excluding pNth (already added) { // excluding pNth (already added)
imagefile = gallery(0,"get",nn); imagefile = gallery(0,"get",nn);
if (! imagefile) continue; if (! imagefile) continue;
ftype = image_file_type(imagefile); // only image and RAW files ftype = image_file_type(imagefile); // only image and RAW files
if (ftype != IMAGE && ftype != RAW && ftype != VIDEO) { if (ftype != IMAGE && ftype != RAW && ftype != VIDEO) continue;
zfree(imagefile);
continue;
}
insert_file(imagefile); insert_file(imagefile);
zfree(imagefile);
} }
pNth = -1; // no prior pNth = -1; // no prior
return; return;
} }
return; return;
} }
// process mouse or key click in files window: // process mouse or key click in files window:
// set new current position and set thumbnail = clicked file // set new current position and set thumbnail = clicked file
skipping to change at line 3914 skipping to change at line 3884
return; return;
} }
// show thumbnail for file at current position in select list // show thumbnail for file at current position in select list
void galselnames::showthumb() void galselnames::showthumb()
{ {
using namespace galselnames; using namespace galselnames;
GdkWindow *gdkwin; GdkWindow *gdkwin;
char thumbfile[XFCC]; ch thumbfile[XFCC];
PIXBUF *thumbpxb = 0; PIXBUF *thumbpxb = 0;
GError *gerror = 0; GError *gerror = 0;
int err; int err;
static draw_context_t draw_context; static draw_context_t draw_context;
cairo_t *cr; cairo_t *cr;
if (! GSselect) return; if (! GSselect) return;
if (currline < 0) return; if (currline < 0) return;
skipping to change at line 3956 skipping to change at line 3926
} }
draw_context_destroy(draw_context); draw_context_destroy(draw_context);
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// gallery menu, resizable thumbnail view // gallery menu, resizable thumbnail view
void m_thumbview(GtkWidget *, cchar *menu) void m_thumbview(GtkWidget *, ch *menu)
{ {
F1_help_topic = "thumb view"; F1_help_topic = "thumb view";
Plog(1,"m_thumbview \n"); Plog(1,"m_thumbview \n");
Fthumbview = 1; Fthumbview = 1;
if (thumbsize < 256) thumbsize = 256; if (thumbsize < 256) thumbsize = 256;
m_viewmode(0,"G"); m_viewmode(0,"G");
gallery(0,"paint",-1); gallery(0,"paint",-1);
return; return;
} }
// gallery menu, thumbnail with basic metadata view // gallery menu, thumbnail with basic metadata view
void m_metaview(GtkWidget *, cchar *menu) void m_metaview(GtkWidget *, ch *menu)
{ {
F1_help_topic = "meta view"; F1_help_topic = "meta view";
Plog(1,"m_metaview \n"); Plog(1,"m_metaview \n");
Fthumbview = 2; Fthumbview = 2;
m_viewmode(0,"G"); m_viewmode(0,"G");
gallery(0,"paint",-1); gallery(0,"paint",-1);
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// Show recently viewed image files. // Show recently viewed image files.
void m_recentfiles(GtkWidget *, cchar *menu) void m_recentfiles(GtkWidget *, ch *menu)
{ {
F1_help_topic = "recent files"; F1_help_topic = "recent files";
Plog(1,"m_recentfiles \n"); Plog(1,"m_recentfiles \n");
if (Findexvalid == 0) { if (Findexvalid == 0) {
zmessageACK(Mwin,"image index disabled"); // no image index zmessageACK(Mwin,"image index disabled"); // no image index
return; return;
} }
navi::gallerytype = RECENT; // gallery type = recent files navi::gallerytype = RECENT; // gallery type = recent files
gallery(recentfiles_file,"initF",0); // generate gallery of recent files gallery(recentfiles_file,"initF",0); // generate gallery of recent files
gallery(0,"paint",0); gallery(0,"paint",0);
m_viewmode(0,"G"); m_viewmode(0,"G");
return; return;
} }
// add a new file to the list of recent files, first position // add a new file to the list of recent files, first position
// ( < 1 millisec. typical at 1000 file limit) // ( < 1 millisec. typical at 1000 file limit)
void add_recent_file(cchar *newfile) void add_recent_file(ch *newfile)
{ {
zlist_t *ZLfiles; zlist_t *ZLfiles;
int ii; int ii;
ZLfiles = zlist_from_file(recentfiles_file); ZLfiles = zlist_from_file(recentfiles_file);
if (! ZLfiles) ZLfiles = zlist_new(0); if (! ZLfiles) ZLfiles = zlist_new(0);
ii = zlist_find(ZLfiles,newfile,0); // if file already present, remove it ii = zlist_find(ZLfiles,newfile,0); // if file already present, remove it
if (ii >= 0) zlist_remove(ZLfiles,ii); if (ii >= 0) zlist_remove(ZLfiles,ii);
zlist_insert(ZLfiles,newfile,0); // insert in 1st position zlist_insert(ZLfiles,newfile,0); // insert in 1st position
zlist_clear(ZLfiles,200); // truncate to 200 files zlist_clear(ZLfiles,200); // truncate to 200 files
zlist_to_file(ZLfiles,recentfiles_file); zlist_to_file(ZLfiles,recentfiles_file);
zlist_delete(ZLfiles); zlist_delete(ZLfiles);
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// Report the newest or most recently modified image files, // Report the newest or most recently modified image files,
// based on EXIF photo date or file mod date. // based on metadata photo date or file mod date.
namespace newfiles namespace newfiles
{ {
struct newfile_t { // new file record struct newfile_t { // new file record
char *file; ch *file;
// image file // image file
char fdate[16]; ch fdate[16];
// date-time, yyyymmddhhmmss // date-time, yyyymmddhhmmss
}; };
} }
// menu function // menu function
void m_newfiles(GtkWidget *, cchar *menu) void m_newfiles(GtkWidget *, ch *menu)
{ {
using namespace newfiles; using namespace newfiles;
int newfile_comp(cchar *rec1, cchar *rec2); int newfile_comp(ch *rec1, ch *rec2);
cchar *mess = "Use EXIF photo date or \n file modification date?"; ch *mess = "Use metadata photo date or \n file modification date?";
int ii, jj, cc, sort, Nxrec; int ii, jj, cc, sort, Nxrec;
xxrec_t *xxrec; xxrec_t *xxrec;
FILE *fid; FILE *fid;
newfile_t *newfile = 0; newfile_t *newfile = 0;
F1_help_topic = "newest files"; F1_help_topic = "newest files";
Plog(1,"m_newfiles \n"); Plog(1,"m_newfiles \n");
skipping to change at line 4065 skipping to change at line 4035
} }
if (Nxxrec == 0) { if (Nxxrec == 0) {
zmessageACK(Mwin,"no files found"); zmessageACK(Mwin,"no files found");
return; return;
} }
cc = Nxxrec * sizeof(newfile_t); // allocate memory cc = Nxxrec * sizeof(newfile_t); // allocate memory
newfile = (newfile_t *) zmalloc(cc,"newfiles"); newfile = (newfile_t *) zmalloc(cc,"newfiles");
if (menu && strmatch(menu,"EXIF")) sort = 1; if (menu && strmatch(menu,"metadata")) sort = 1;
else if (menu && strmatch(menu,"file")) sort = 2; else if (menu && strmatch(menu,"file")) sort = 2;
else sort = zdialog_choose(Mwin,"mouse",mess,"EXIF","File",null); else sort = zdialog_choose(Mwin,"mouse",mess,"metadata","File",null);
if (sort < 1) return; // cancel if (sort < 1) return; // cancel
for (ii = jj = 0; ii < Nxxrec; ii++) // loop image index table for (ii = jj = 0; ii < Nxxrec; ii++) // loop image index table
{ {
xxrec = xxrec_tab[ii]; xxrec = xxrec_tab[ii];
newfile[jj].file = xxrec->file; // image file newfile[jj].file = xxrec->file; // image file
if (sort == 1) { if (sort == 1) {
if (strmatch(xxrec->pdate,"null")) continue; // use EXIF photo date if (strmatch(xxrec->pdate,"null")) continue; // use metadata photo date
strncpy0(newfile[jj].fdate,xxrec->pdate,15); // ignore images without photo date strncpy0(newfile[jj].fdate,xxrec->pdate,15); // ignore images without photo date
} }
else strncpy0(newfile[jj].fdate,xxrec->fdate,15); // else use file mod date else strncpy0(newfile[jj].fdate,xxrec->fdate,15); // else use file mod date
jj++; // selected files jj++; // selected files
} }
Nxrec = jj; // final count Nxrec = jj; // final count
if (Nxrec > 1) // sort index recs. by file date if (Nxrec > 1) // sort index recs. by file date
HeapSort((char *) newfile, sizeof(newfile_t), Nxrec, newfile_comp); HeapSort((ch *) newfile, sizeof(newfile_t), Nxrec, newfile_comp);
fid = fopen(searchresults_file,"w"); // open output file fid = fopen(searchresults_file,"w"); // open output file
if (! fid) { if (! fid) {
zmessageACK(Mwin,"file error: %s",strerror(errno)); zmessageACK(Mwin,"file error: %s",strerror(errno));
goto cleanup; goto cleanup;
} }
for (ii = 0; ii < 1000 && ii < Nxrec; ii++) // output newest 1000 image files 22.35 for (ii = 0; ii < 1000 && ii < Nxrec; ii++) // output newest 1000 image files 22.35
fprintf(fid,"%s\n",newfile[ii].file); fprintf(fid,"%s\n",newfile[ii].file);
skipping to change at line 4116 skipping to change at line 4086
m_viewmode(0,"G"); m_viewmode(0,"G");
return; return;
} }
// Compare 2 newfile records by file date-time // Compare 2 newfile records by file date-time
// return <0 =0 >0 for rec2 < = > rec1 (descending sequence) // return <0 =0 >0 for rec2 < = > rec1 (descending sequence)
using namespace newfiles; using namespace newfiles;
int newfile_comp(cchar *rec1, cchar *rec2) int newfile_comp(ch *rec1, ch *rec2)
{ {
char *date1 = ((newfile_t *) rec1)->fdate; ch *date1 = ((newfile_t *) rec1)->fdate;
char *date2 = ((newfile_t *) rec2)->fdate; ch *date2 = ((newfile_t *) rec2)->fdate;
return strcmp(date2,date1); return strcmp(date2,date1);
} }
/******************************************************************************* */ /******************************************************************************* */
// menu function // menu function
// dialog to choose gallery sort order and sort the gallery // dialog to choose gallery sort order and sort the gallery
void m_gallery_sort(GtkWidget *, cchar *menu) // 22.35 void m_gallery_sort(GtkWidget *, ch *menu) // 22.35
{ {
zdialog *zd; zdialog *zd;
int zstat, nn; int zstat, nn;
char albumfile[200], *pp, *pp2; ch albumfile[200], *pp, *pp2;
cchar *resetmess = " Reset all galleries\n to file name ascending"; ch *resetmess = " Reset all galleries\n to file name ascending";
F1_help_topic = "gallery sort"; F1_help_topic = "gallery sort";
Plog(1,"m_gallery_sort \n"); Plog(1,"m_gallery_sort \n");
/*** /***
________________________________ _________________________________
| Gallery Sort | | Gallery Sort |
| | | |
| (o) File Name | | (o) File Name |
| (o) File Name/Number | | (o) File Name/Number |
| (o) File Mod Date/Time | | (o) File Mod Date/Time |
| (o) Photo Date/Time (EXIF) | | (o) Photo Date/Time (metadata) |
| (o) File Size (bytes) | | (o) File Size (bytes) |
| (o) Image Size (pixels) | | (o) Image Size (pixels) |
| (o) Metadata from Search | | (o) Metadata from Search |
// 22.20 // 22.20
| (o) ascending (o) descending | | (o) ascending (o) descending |
| | | |
| [x] reset all galleries | | [x] reset all galleries |
| to file name ascending | | to file name ascending |
| | | |
| [Apply] | | [Apply] |
|________________________________| |_________________________________|
***/ ***/
zd = zdialog_new("Gallery Sort",Mwin,"Apply",null); // user dialog zd = zdialog_new("Gallery Sort",Mwin,"Apply",null); // user dialog
zdialog_add_widget(zd,"hbox","hb1","dialog"); zdialog_add_widget(zd,"hbox","hb1","dialog");
zdialog_add_widget(zd,"label","space","hb1",0,"space=2"); zdialog_add_widget(zd,"label","space","hb1",0,"space=2");
zdialog_add_widget(zd,"vbox","vb1","hb1"); zdialog_add_widget(zd,"vbox","vb1","hb1");
zdialog_add_widget(zd,"radio","filename","vb1","File Name"); zdialog_add_widget(zd,"radio","filename","vb1","File Name");
zdialog_add_widget(zd,"radio","filenumber","vb1","File Name/Number"); zdialog_add_widget(zd,"radio","filenumber","vb1","File Name/Number");
zdialog_add_widget(zd,"radio","filedate","vb1","File Mod Date/Time"); zdialog_add_widget(zd,"radio","filedate","vb1","File Mod Date/Time");
zdialog_add_widget(zd,"radio","photodate","vb1","Photo Date/Time (EXIF)"); zdialog_add_widget(zd,"radio","photodate","vb1","Photo Date/Time (metadata)") ;
zdialog_add_widget(zd,"radio","filesize","vb1","File Size (bytes)"); zdialog_add_widget(zd,"radio","filesize","vb1","File Size (bytes)");
zdialog_add_widget(zd,"radio","pixelsize","vb1","Image Size (pixels)"); zdialog_add_widget(zd,"radio","pixelsize","vb1","Image Size (pixels)");
zdialog_add_widget(zd,"radio","metadata","vb1","Metadata from Search Function "); zdialog_add_widget(zd,"radio","metadata","vb1","Metadata from Search Function ");
zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5");
zdialog_add_widget(zd,"radio","ascending","hb2","ascending","space=4"); zdialog_add_widget(zd,"radio","ascending","hb2","ascending","space=4");
zdialog_add_widget(zd,"radio","descending","hb2","descending","space=2"); zdialog_add_widget(zd,"radio","descending","hb2","descending","space=2");
zdialog_add_widget(zd,"hbox","hbreset","dialog",0,"space=5"); zdialog_add_widget(zd,"hbox","hbreset","dialog",0,"space=5");
zdialog_add_widget(zd,"check","reset","hbreset",resetmess,"space=4"); zdialog_add_widget(zd,"check","reset","hbreset",resetmess,"space=4");
zdialog_add_ttip(zd,"metadata","metadata from Search Function, metadata repor t"); zdialog_add_ttip(zd,"metadata","metadata from Search Function, metadata repor t");
skipping to change at line 4281 skipping to change at line 4251
} }
/******************************************************************************* */ /******************************************************************************* */
// screen the current gallery for matching files // screen the current gallery for matching files
// output matching files to album "gallery_screen" // output matching files to album "gallery_screen"
namespace gallery_screen_names namespace gallery_screen_names
{ {
int Foldest, Fnewest, Fedited, Funedited, Finclude, Fexclude, Fkeep; int Foldest, Fnewest, Fedited, Funedited, Finclude, Fexclude, Fkeep;
char includetext[100], excludetext[100]; ch includetext[100], excludetext[100];
} }
// menu function // menu function
void m_gallery_screen(GtkWidget *, cchar *menu) // 22.35 void m_gallery_screen(GtkWidget *, ch *menu) // 22.35
{ {
using namespace gallery_screen_names; using namespace gallery_screen_names;
zdialog *zd; zdialog *zd;
int zstat, ii, jj, Nfiles, nfl; int zstat, ii, jj, Nfiles, nfl;
char albumfile[AFCC]; ch albumfile[AFCC];
char *pp1, *pp2; ch *pp1, *pp2;
char *rootname, **filelist; ch *rootname, **filelist;
FTYPE ftype; FTYPE ftype;
FILE *fid; FILE *fid;
int gallery_screen_dialog_event(zdialog *zd, cchar *event); int gallery_screen_dialog_event(zdialog *zd, ch *event);
F1_help_topic = "gallery screen"; F1_help_topic = "gallery screen";
Plog(1,"m_gallery_screen \n"); Plog(1,"m_gallery_screen \n");
if (gallerytype != FOLDER) { if (gallerytype != FOLDER) {
zmessageACK(Mwin,"gallery must be a FOLDER gallery"); zmessageACK(Mwin,"gallery must be a FOLDER gallery");
return; return;
} }
skipping to change at line 4394 skipping to change at line 4364
zmessageACK(Mwin,strerror(errno)); zmessageACK(Mwin,strerror(errno));
return; return;
} }
Nfiles = 0; Nfiles = 0;
rootname = 0; rootname = 0;
filelist = 0; filelist = 0;
for (ii = 0; ii < Gfiles; ii++) // loop files in current gallery for (ii = 0; ii < Gfiles; ii++) // loop files in current gallery
{ {
pp1 = gallery(0,"get",ii); pp1 = gallery(0,"getR",ii); // 23.1
if (! pp1) break; if (! pp1) break;
ftype = image_file_type(pp1); // must be image type file ftype = image_file_type(pp1); // must be image type file
if (ftype != IMAGE && ftype != RAW && ftype != VIDEO) if (ftype != IMAGE && ftype != RAW && ftype != VIDEO) continue;
continue;
pp2 = file_rootname(pp1); // skip until new rootname found pp2 = file_rootname(pp1); // skip until new rootname found
if (rootname && strmatch(pp2,rootname)) { if (rootname && strmatch(pp2,rootname)) {
zfree(pp2); zfree(pp2);
continue; continue;
} }
if (rootname) zfree(rootname); // next rootname if (rootname) zfree(rootname); // next rootname
rootname = pp2; rootname = pp2;
skipping to change at line 4486 skipping to change at line 4455
zstrcopy(curr_album,albumfile,"albums"); // make current album zstrcopy(curr_album,albumfile,"albums"); // make current album
zmessage_post_bold(Mwin,"20/20",3,"new album created"); zmessage_post_bold(Mwin,"20/20",3,"new album created");
album_show(); album_show();
return; return;
} }
// dialog event and completion function // dialog event and completion function
int gallery_screen_dialog_event(zdialog *zd, cchar *event) // 22.35 int gallery_screen_dialog_event(zdialog *zd, ch *event) // 22.35
{ {
using namespace gallery_screen_names; using namespace gallery_screen_names;
zdialog_fetch(zd,"oldest",Foldest); // include oldest versions only zdialog_fetch(zd,"oldest",Foldest); // include oldest versions only
zdialog_fetch(zd,"newest",Fnewest); // include newest versions only zdialog_fetch(zd,"newest",Fnewest); // include newest versions only
zdialog_fetch(zd,"edited",Fedited); // include edited files only zdialog_fetch(zd,"edited",Fedited); // include edited files only
zdialog_fetch(zd,"unedited",Funedited); // include unedited files only zdialog_fetch(zd,"unedited",Funedited); // include unedited files only
if (strstr("oldest newest",event)) // enforce mutual-exclusion if (strstr("oldest newest",event)) // enforce mutual-exclusion
if (Foldest || Fnewest) { if (Foldest || Fnewest) {
skipping to change at line 4524 skipping to change at line 4493
} }
} }
return 1; return 1;
} }
/******************************************************************************* */ /******************************************************************************* */
// set the gallery from the current image file physical folder // set the gallery from the current image file physical folder
void m_source_folder(GtkWidget*, cchar *menu) void m_source_folder(GtkWidget*, ch *menu)
{ {
F1_help_topic = "source folder"; F1_help_topic = "source folder";
Plog(1,"m_source_folder \n"); Plog(1,"m_source_folder \n");
if (! curr_file) return; if (! curr_file) return;
gallery(curr_file,"init",0); // new gallery gallery(curr_file,"init",0); // new gallery
gallery(curr_file,"paint",0); // position at curr. file gallery(curr_file,"paint",0); // position at curr. file
curr_file_posn = file_position(curr_file,0); // file position in gallery list curr_file_posn = file_position(curr_file,0); // file position in gallery list
m_viewmode(0,"G"); m_viewmode(0,"G");
return; return;
} }
skipping to change at line 4547 skipping to change at line 4516
// generate a clickable list of all image folders // generate a clickable list of all image folders
// show gallery for any folder clicked // show gallery for any folder clicked
namespace allfolders namespace allfolders
{ {
#define maxdirs 10000 #define maxdirs 10000
int Nlines = 0, Fall = 0; int Nlines = 0, Fall = 0;
int currline = 0; int currline = 0;
zdialog *zd; zdialog *zdpop;
typedef struct { typedef struct {
char *name; // /dir1/dir2/.../dirN folder name ch *name; // /dir1/dir2/.../dirN folder name
int Nsubs; // subfolder count 0-N int Nsubs; // subfolder count 0-N
int8 lev; // folder level 0-N, top/sub/sub ... int8 lev; // folder level 0-N, top/sub/sub ...
int8 exp; // folder status 0/1 = collapsed/expanded int8 exp; // folder status 0/1 = collapsed/expanded
int16 line; // textwidget line -1 = not displayed int16 line; // textwidget line -1 = not displayed
} dlist_t; } dlist_t;
dlist_t *dlist; dlist_t *dlist;
int drecl = sizeof(dlist_t); int drecl = sizeof(dlist_t);
int compfunc(cchar *rec1, cchar *rec2); int compfunc(ch *rec1, ch *rec2);
void callbackfunc(GtkWidget *, int line, int pos, int kbkey); void callbackfunc(GtkWidget *, int line, int pos, int kbkey);
void writetext(); void writetext();
} }
// menu function // menu function
void m_allfolders(GtkWidget *, cchar *) void m_allfolders(GtkWidget *, ch *)
{ {
using namespace allfolders; using namespace allfolders;
int ii, jj, cc, pcc, NF, err; int ii, jj, cc, pcc, NF, err;
char *dir, *pdir, **Flist; ch *dir, *pdir, **Flist;
F1_help_topic = "all folders"; F1_help_topic = "all folders";
Plog(1,"m_allfolders \n"); Plog(1,"m_allfolders \n");
/*** /***
________________________________ ________________________________
| All Folders | | All Folders |
| ____________________________ | | ____________________________ |
| | | | | | | |
skipping to change at line 4627 skipping to change at line 4596
dlist[Fall].name = zstrdup(Flist[jj],"allfolders"); dlist[Fall].name = zstrdup(Flist[jj],"allfolders");
Fall++; Fall++;
if (Fall == maxdirs) break; if (Fall == maxdirs) break;
} }
if (NF) zfree(Flist); if (NF) zfree(Flist);
if (Fall == maxdirs) break; if (Fall == maxdirs) break;
} }
if (Fall > 1) if (Fall > 1)
HeapSort((char *) dlist,drecl,Fall,compfunc); // sort alphabetically HeapSort((ch *) dlist,drecl,Fall,compfunc); // sort alphabetically
for (ii = 0; ii < Fall; ii++) // loop all folders for (ii = 0; ii < Fall; ii++) // loop all folders
{ {
dir = dlist[ii].name; // this folder name dir = dlist[ii].name; // this folder name
for (jj = ii-1; jj >= 0; jj--) { // search backwards for parent for (jj = ii-1; jj >= 0; jj--) { // search backwards for parent
pdir = dlist[jj].name; // previous folder name pdir = dlist[jj].name; // previous folder name
pcc = strlen(pdir); pcc = strlen(pdir);
if (strmatchN(dir,pdir,pcc) && dir[pcc] == '/') break; // this dir = prev dir + /... if (strmatchN(dir,pdir,pcc) && dir[pcc] == '/') break; // this dir = prev dir + /...
} }
if (jj >= 0) { // parent found if (jj >= 0) { // parent found
skipping to change at line 4649 skipping to change at line 4618
dlist[jj].Nsubs++; // add parent subdir count dlist[jj].Nsubs++; // add parent subdir count
} }
else dlist[ii].lev = 0; // no parent, level = 0 else dlist[ii].lev = 0; // no parent, level = 0
} }
for (ii = 0; ii < Fall; ii++) // loop all folders for (ii = 0; ii < Fall; ii++) // loop all folders
dlist[ii].exp = 0; // expand = no dlist[ii].exp = 0; // expand = no
report: report:
zd = popup_report_open("All Folders",Mwin,300,400,0,callbackfunc,"OK",0); // open report window 22.15 zdpop = popup_report_open("All Folders",Mwin,300,400,0,callbackfunc,"OK",0); // open report window 22.15
writetext(); // write top folders to window writetext(); // write top folders to window
currline = 0; // first entry currline = 0; // first entry
return; return;
} }
// sort compare function // sort compare function
int allfolders::compfunc(cchar *rec1, cchar *rec2) int allfolders::compfunc(ch *rec1, ch *rec2)
{ {
dlist_t *dir1 = (dlist_t *) rec1; dlist_t *dir1 = (dlist_t *) rec1;
dlist_t *dir2 = (dlist_t *) rec2; dlist_t *dir2 = (dlist_t *) rec2;
int nn; int nn;
nn = strcasecmp(dir1->name,dir2->name); nn = strcasecmp(dir1->name,dir2->name);
if (nn) return nn; if (nn) return nn;
nn = strcmp(dir1->name,dir2->name); nn = strcmp(dir1->name,dir2->name);
return nn; return nn;
} }
// folder list mouse function // folder list mouse function
void allfolders::callbackfunc(GtkWidget *textwidget, int line, int pos, int kbke y) void allfolders::callbackfunc(GtkWidget *textwidget, int line, int pos, int kbke y)
{ {
using namespace allfolders; using namespace allfolders;
int ii; int ii;
char *pline, *pp; ch *pline, *pp;
static int Fbusy = 0; static int Fbusy = 0;
if (Fbusy++) return; // stop re-entry 22.30 if (Fbusy++) return; // stop re-entry 22.30
if (Fblock("allfolders","block edits")) goto returnx; // check pending, block if (Fblock("allfolders","block edits")) goto returnx; // check pending, block
if (line < 0) // KB key if (line < 0) // KB key
{ {
if (kbkey == GDK_KEY_F1) { // key F1 pressed, show help if (kbkey == GDK_KEY_F1) { // key F1 pressed, show help
showz_docfile(Mwin,"userguide",F1_help_topic); showz_docfile(Mwin,"userguide",F1_help_topic);
skipping to change at line 4749 skipping to change at line 4718
return; return;
} }
// write all visible folders to text window // write all visible folders to text window
void allfolders::writetext() void allfolders::writetext()
{ {
using namespace allfolders; using namespace allfolders;
int ii = 0, jj, line = 0; int ii = 0, jj, line = 0;
char *pp, indent[100]; ch *pp, indent[100];
cchar *expbutt; ch *expbutt;
memset(indent,' ',100); memset(indent,' ',100);
popup_report_clear(zd); popup_report_clear(zdpop);
while (ii < Fall) // loop all folders while (ii < Fall) // loop all folders
{ {
jj = dlist[ii].lev * 4; // indent 4 blanks per folder level jj = dlist[ii].lev * 4; // indent 4 blanks per folder level
if (jj > 99) jj = 99; if (jj > 99) jj = 99;
indent[jj] = 0; indent[jj] = 0;
if (dlist[ii].Nsubs == 0) expbutt = " "; // no subdirs, no expand button if (dlist[ii].Nsubs == 0) expbutt = " "; // no subdirs, no expand button
else if (dlist[ii].exp) expbutt = "[-]"; // prepare [+] or [-] else if (dlist[ii].exp) expbutt = "[-]"; // prepare [+] or [-]
else expbutt = "[+]"; else expbutt = "[+]";
pp = strrchr(dlist[ii].name,'/'); pp = strrchr(dlist[ii].name,'/');
if (! pp) continue; if (! pp) continue;
popup_report_write2(zd,0,"%s %s %s \n",indent,expbutt,pp+1); // ... [x] dirname popup_report_write2(zdpop,0,"%s %s %s \n",indent,expbutt,pp+1); // ... [x] dirname
indent[jj] = ' '; indent[jj] = ' ';
dlist[ii].line = line; // text line for this folder dlist[ii].line = line; // text line for this folder
line++; line++;
if (dlist[ii].exp) { // if folder expanded, continue if (dlist[ii].exp) { // if folder expanded, continue
ii++; ii++;
continue; continue;
} }
for (jj = ii + 1; jj < Fall; jj++) { // not expanded, find next folder for (jj = ii + 1; jj < Fall; jj++) { // not expanded, find next folder
skipping to change at line 4791 skipping to change at line 4760
} }
Nlines = line; Nlines = line;
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// menu function to pre-select files for feeding album, batch and script functi ons // menu function to pre-select files for feeding album, batch and script functi ons
void m_select_files(GtkWidget *, cchar *) void m_select_files(GtkWidget *, ch *)
{ {
char albumfile[200]; ch albumfile[200];
FILE *fid; FILE *fid;
int err, ii; int err, ii;
F1_help_topic = "select image files"; F1_help_topic = "select image files";
Plog(1,"m_select_files \n"); Plog(1,"m_select_files \n");
snprintf(albumfile,200,"%s/selected_files",albums_folder); // "selected files" album snprintf(albumfile,200,"%s/selected_files",albums_folder); // "selected files" album
err = gallery_select(); err = gallery_select();
skipping to change at line 4826 skipping to change at line 4795
fprintf(fid,"%s\n",GSfiles[ii]); fprintf(fid,"%s\n",GSfiles[ii]);
fclose(fid); fclose(fid);
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// rename the current folder // rename the current folder
void m_rename_folder(GtkWidget *, cchar *menu) // 22.15 void m_rename_folder(GtkWidget *, ch *menu) // 22.15
{ {
int rename_folder_dialog_event(zdialog *zd, cchar *event); int rename_folder_dialog_event(zdialog *zd, ch *event);
zdialog *zd; zdialog *zd;
int zstat, err; int zstat, err;
char oldname[XFCC], newname[XFCC]; ch oldname[XFCC], newname[XFCC];
F1_help_topic = "rename folder"; F1_help_topic = "rename folder";
Plog(1,"m_rename_folder \n"); Plog(1,"m_rename_folder \n");
if (! galleryname) { if (! galleryname) {
zmessageACK(Mwin,"no current gallery"); zmessageACK(Mwin,"no current gallery");
return; return;
} }
skipping to change at line 4913 skipping to change at line 4882
album_folder_rename(oldname,newname); // update filenames in album files album_folder_rename(oldname,newname); // update filenames in album files
gallery(newname,"init",0); // refresh gallery gallery(newname,"init",0); // refresh gallery
gallery(0,"paint",-1); gallery(0,"paint",-1);
return; return;
} }
// zdialog event and completion function // zdialog event and completion function
int rename_folder_dialog_event(zdialog *zd, cchar *event) int rename_folder_dialog_event(zdialog *zd, ch *event)
{ {
if (zd->zstat) zdialog_destroy(zd); if (zd->zstat) zdialog_destroy(zd);
return 1; return 1;
} }
/******************************************************************************* */ /******************************************************************************* */
// create a new subfolder under the current folder // create a new subfolder under the current folder
void m_add_subfolder(GtkWidget *, cchar *menu) // 22.11 void m_add_subfolder(GtkWidget *, ch *menu) // 22.11
{ {
int add_subfolder_dialog_event(zdialog *zd, cchar *event); int add_subfolder_dialog_event(zdialog *zd, ch *event);
zdialog *zd; zdialog *zd;
int zstat, err; int zstat, err;
char pathname[XFCC], subfolder[100]; ch pathname[XFCC], subfolder[100];
F1_help_topic = "add subfolder"; F1_help_topic = "add subfolder";
Plog(1,"m_add_subfolder \n"); Plog(1,"m_add_subfolder \n");
if (! galleryname) { if (! galleryname) {
zmessageACK(Mwin,"no current gallery"); zmessageACK(Mwin,"no current gallery");
return; return;
} }
skipping to change at line 4997 skipping to change at line 4966
gallery(galleryname,"init",0); gallery(galleryname,"init",0);
gallery(0,"paint",-1); gallery(0,"paint",-1);
zmessageACK(Mwin,"new subfolder created: \n %s",pathname); zmessageACK(Mwin,"new subfolder created: \n %s",pathname);
return; return;
} }
// zdialog event and completion function // zdialog event and completion function
int add_subfolder_dialog_event(zdialog *zd, cchar *event) int add_subfolder_dialog_event(zdialog *zd, ch *event)
{ {
if (zd->zstat) zdialog_destroy(zd); if (zd->zstat) zdialog_destroy(zd);
return 1; return 1;
} }
/******************************************************************************* */ /******************************************************************************* */
namespace bookmarknames namespace bookmarknames
{ {
#define maxbmks 50 #define maxbmks 50
char *bookmarks[maxbmks]; // bookmark names and files ch *bookmarks[maxbmks]; // bookmark names and files
int Nbmks; // count of entries int Nbmks; // count of entries
int bmkposn; // current entry, 0-last int bmkposn; // current entry, 0-last
zdialog *zd_bookmark; zdialog *zd_bookmark;
GtkWidget *textwidget; GtkWidget *textwidget;
} }
void bookmarks_load(); void bookmarks_load();
void bookmarks_refresh(); void bookmarks_refresh();
// select a bookmark and jump gallery to selected bookmark thumbnail // select a bookmark and jump gallery to selected bookmark thumbnail
void m_bookmarks(GtkWidget *, cchar *) void m_bookmarks(GtkWidget *, ch *)
{ {
using namespace bookmarknames; using namespace bookmarknames;
int bookmarks_dialog_event(zdialog *zd, cchar *event); int bookmarks_dialog_event(zdialog *zd, ch *event);
void bookmarks_callbackfunc(GtkWidget *, int line, int pos, int kbkey); void bookmarks_callbackfunc(GtkWidget *, int line, int pos, int kbkey);
zdialog *zd; zdialog *zd;
/*** /***
_______________________________________________ _______________________________________________
| Bookmarks | | Bookmarks |
|-----------------------------------------------| |-----------------------------------------------|
| bookmarkname1 /topdir/.../filename1.jpg | | bookmarkname1 /topdir/.../filename1.jpg |
| bookmarkname2 /topdir/.../filename2.jpg | | bookmarkname2 /topdir/.../filename2.jpg |
skipping to change at line 5071 skipping to change at line 5040
bookmarks_refresh(); // update bookmarks list in dialog bookmarks_refresh(); // update bookmarks list in dialog
zdialog_resize(zd,400,300); zdialog_resize(zd,400,300);
zdialog_set_modal(zd); zdialog_set_modal(zd);
zdialog_run(zd,bookmarks_dialog_event,"mouse"); // run dialog zdialog_run(zd,bookmarks_dialog_event,"mouse"); // run dialog
return; return;
} }
// dialog event and completion function // dialog event and completion function
int bookmarks_dialog_event(zdialog *zd, cchar *event) int bookmarks_dialog_event(zdialog *zd, ch *event)
{ {
using namespace bookmarknames; using namespace bookmarknames;
int zstat; int zstat;
if (strmatch(event,"escape")) zd->zstat = -2; // escape key if (strmatch(event,"escape")) zd->zstat = -2; // escape key
zstat = zd->zstat; zstat = zd->zstat;
if (! zstat) return 1; // wait for completion if (! zstat) return 1; // wait for completion
zdialog_free(zd); zdialog_free(zd);
skipping to change at line 5093 skipping to change at line 5062
if (zstat == 1) m_edit_bookmarks(0,0); // [edit bookmarks] button if (zstat == 1) m_edit_bookmarks(0,0); // [edit bookmarks] button
return 1; return 1;
} }
// mouse click function to receive clicked bookmarks // mouse click function to receive clicked bookmarks
void bookmarks_callbackfunc(GtkWidget *, int line, int pos, int kbkey) void bookmarks_callbackfunc(GtkWidget *, int line, int pos, int kbkey)
{ {
using namespace bookmarknames; using namespace bookmarknames;
char *file; ch *file;
if (kbkey == GDK_KEY_F1) { // key F1 pressed, show help if (kbkey == GDK_KEY_F1) { // key F1 pressed, show help
showz_docfile(Mwin,"userguide",F1_help_topic); showz_docfile(Mwin,"userguide",F1_help_topic);
return; return;
} }
if (! zd_bookmark) return; if (! zd_bookmark) return;
if (Fblock("bookmarks","block edits")) return; // check pend, block if (Fblock("bookmarks","block edits")) return; // check pend, block
skipping to change at line 5126 skipping to change at line 5095
m_viewmode(0,"G"); m_viewmode(0,"G");
Fblock("bookmarks",0); // no close zdialog Fblock("bookmarks",0); // no close zdialog
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// edit bookmarks // edit bookmarks
void m_edit_bookmarks(GtkWidget *, cchar *) void m_edit_bookmarks(GtkWidget *, ch *)
{ {
using namespace bookmarknames; using namespace bookmarknames;
int edit_bookmarks_dialog_event(zdialog *zd, cchar *event); int edit_bookmarks_dialog_event(zdialog *zd, ch *event);
void edit_bookmarks_callbackfunc(GtkWidget *, int line, int pos, int kbkey); void edit_bookmarks_callbackfunc(GtkWidget *, int line, int pos, int kbkey);
zdialog *zd; zdialog *zd;
cchar *bmk_add = "Click a list position. Click a gallery thumbnail for the new bookmark.\n" ch *bmk_add = "Click a list position. Click a gallery thumbnail for the new bookmark.\n"
"Bookmark for thumbnail will be added. Change the name and press [Rename]."; "Bookmark for thumbnail will be added. Change the name and press [Rename].";
/*** /***
_______________________________________________ _______________________________________________
| Edit Bookmarks | | Edit Bookmarks |
| | | |
| Click list position. Click thumbnail to add. | | Click list position. Click thumbnail to add. |
|-----------------------------------------------| |-----------------------------------------------|
| bookmarkname1 /topdir/.../filename1.jpg | | bookmarkname1 /topdir/.../filename1.jpg |
| bookmarkname2 /topdir/.../filename2.jpg | | bookmarkname2 /topdir/.../filename2.jpg |
skipping to change at line 5195 skipping to change at line 5164
return; return;
} }
// load bookmarks list from bookmarks file // load bookmarks list from bookmarks file
void bookmarks_load() void bookmarks_load()
{ {
using namespace bookmarknames; using namespace bookmarknames;
int err; int err;
char buff[XFCC], bmkfile[200]; ch buff[XFCC], bmkfile[200];
char *pp, *pp2; ch *pp, *pp2;
FILE *fid; FILE *fid;
Nbmks = 0; Nbmks = 0;
err = get_zfilespec("user","bookmarks",bmkfile); // read bookmarks file err = get_zfilespec("user","bookmarks",bmkfile); // read bookmarks file
if (! err) { if (! err) {
fid = fopen(bmkfile,"r"); fid = fopen(bmkfile,"r");
if (fid) { if (fid) {
while (true) { while (true) {
pp = fgets_trim(buff,XFCC,fid,1); // next bookmark rec. pp = fgets_trim(buff,XFCC,fid,1); // next bookmark rec.
if (! pp) break; if (! pp) break;
skipping to change at line 5228 skipping to change at line 5197
bmkposn = Nbmks; // next free position bmkposn = Nbmks; // next free position
return; return;
} }
// mouse click function to select existing bookmark from list // mouse click function to select existing bookmark from list
void edit_bookmarks_callbackfunc(GtkWidget *, int line, int pos, int kbkey) void edit_bookmarks_callbackfunc(GtkWidget *, int line, int pos, int kbkey)
{ {
using namespace bookmarknames; using namespace bookmarknames;
char bookmarkname[32]; ch bookmarkname[32];
if (kbkey == GDK_KEY_F1) { // key F1 pressed, show help if (kbkey == GDK_KEY_F1) { // key F1 pressed, show help
showz_docfile(Mwin,"userguide",F1_help_topic); showz_docfile(Mwin,"userguide",F1_help_topic);
return; return;
} }
if (! zd_edit_bookmarks) return; if (! zd_edit_bookmarks) return;
if (Nbmks < 1) return; if (Nbmks < 1) return;
if (line < 0) line = 0; if (line < 0) line = 0;
if (line > Nbmks-1) line = Nbmks-1; if (line > Nbmks-1) line = Nbmks-1;
skipping to change at line 5252 skipping to change at line 5221
zdialog_stuff(zd_edit_bookmarks,"bmkname",bookmarkname); zdialog_stuff(zd_edit_bookmarks,"bmkname",bookmarkname);
return; return;
} }
// mouse click function to receive clicked thumbnails for new/revised bookmarks // mouse click function to receive clicked thumbnails for new/revised bookmarks
void edit_bookmarks_Lclick_func(int Nth) void edit_bookmarks_Lclick_func(int Nth)
{ {
using namespace bookmarknames; using namespace bookmarknames;
char *imagefile, *newbookmark; ch *imagefile, *newbookmark;
char *pp, bookmarkname[32]; ch *pp, bookmarkname[32];
int cc; int cc;
if (! zd_edit_bookmarks) return; if (! zd_edit_bookmarks) return;
if (Nth < 0) return; // gallery gone ? if (Nth < 0) return; // gallery gone ?
imagefile = gallery(0,"get",Nth); // get file at clicked position imagefile = gallery(0,"getR",Nth); // get file at clicked position 23.1
if (! imagefile) return; if (! imagefile) return;
pp = strrchr(imagefile,'/'); // get file name or last subfolder name pp = strrchr(imagefile,'/'); // get file name or last subfolder name
if (! pp) return; // to use as default bookmark name if (! pp) return; // to use as default bookmark name
strncpy0(bookmarkname,pp+1,31); // max. 30 chars. + null strncpy0(bookmarkname,pp+1,31); // max. 30 chars. + null
cc = strlen(imagefile) + 34; // construct bookmark record: cc = strlen(imagefile) + 34; // construct bookmark record:
newbookmark = (char *) zmalloc(cc,"bookmarks"); // filename /folders.../filename newbookmark = (ch *) zmalloc(cc,"bookmarks"); // filename /folders.../filename
snprintf(newbookmark,cc,"%-30s %s",bookmarkname,imagefile); snprintf(newbookmark,cc,"%-30s %s",bookmarkname,imagefile);
zfree(imagefile);
if (Nbmks == maxbmks) { // if list full, remove first if (Nbmks == maxbmks) { // if list full, remove first
zfree(bookmarks[0]); zfree(bookmarks[0]);
Nbmks--; Nbmks--;
for (int ii = 0; ii < Nbmks; ii++) for (int ii = 0; ii < Nbmks; ii++)
bookmarks[ii] = bookmarks[ii+1]; bookmarks[ii] = bookmarks[ii+1];
} }
if (Nbmks == 0) bmkposn = 0; // 1st bookmark --> 0 if (Nbmks == 0) bmkposn = 0; // 1st bookmark --> 0
else bmkposn++; // else clicked position + 1 else bmkposn++; // else clicked position + 1
skipping to change at line 5297 skipping to change at line 5265
bookmarks_refresh(); // update bookmarks list in dialog bookmarks_refresh(); // update bookmarks list in dialog
zdialog_stuff(zd_edit_bookmarks,"bmkname",bookmarkname); zdialog_stuff(zd_edit_bookmarks,"bmkname",bookmarkname);
return; return;
} }
// dialog event and completion function // dialog event and completion function
int edit_bookmarks_dialog_event(zdialog *zd, cchar *event) int edit_bookmarks_dialog_event(zdialog *zd, ch *event)
{ {
using namespace bookmarknames; using namespace bookmarknames;
char bmkfile[200]; ch bmkfile[200];
char bookmarkname[32]; ch bookmarkname[32];
FILE *fid; FILE *fid;
int cc; int cc;
if (strmatch(event,"escape")) zd->zstat = -2; // escape key if (strmatch(event,"escape")) zd->zstat = -2; // escape key
if (strmatch(event,"delete")) // delete bookmark at position if (strmatch(event,"delete")) // delete bookmark at position
{ {
if (bmkposn < 0 || bmkposn > Nbmks-1) return 1; if (bmkposn < 0 || bmkposn > Nbmks-1) return 1;
for (int ii = bmkposn; ii < Nbmks-1; ii++) for (int ii = bmkposn; ii < Nbmks-1; ii++)
bookmarks[ii] = bookmarks[ii+1]; bookmarks[ii] = bookmarks[ii+1];
skipping to change at line 5360 skipping to change at line 5328
Fblock("edit_bookmarks",0); Fblock("edit_bookmarks",0);
return 1; return 1;
} }
// private function to update dialog widget with new bookmarks list // private function to update dialog widget with new bookmarks list
void bookmarks_refresh() void bookmarks_refresh()
{ {
using namespace bookmarknames; using namespace bookmarknames;
char bookmarkline[XFCC+32]; ch bookmarkline[XFCC+32];
char blanks[33] = " "; ch blanks[33] = " ";
int cc; int cc;
if (! zd_edit_bookmarks && ! zd_bookmark) return; if (! zd_edit_bookmarks && ! zd_bookmark) return;
textwidget_clear(textwidget); // clear bookmarks list textwidget_clear(textwidget); // clear bookmarks list
for (int ii = 0; ii < Nbmks; ii++) { // write bookmarks list for (int ii = 0; ii < Nbmks; ii++) { // write bookmarks list
strncpy0(bookmarkline,bookmarks[ii],31); strncpy0(bookmarkline,bookmarks[ii],31);
cc = utf8len(bookmarkline); // compensate multibyte chars. cc = utf8len(bookmarkline); // compensate multibyte chars.
strncat(bookmarkline,blanks,32-cc); strncat(bookmarkline,blanks,32-cc);
strcat(bookmarkline,bookmarks[ii]+32); strcat(bookmarkline,bookmarks[ii]+32);
textwidget_append(textwidget,0,"%s\n",bookmarkline); textwidget_append(textwidget,0,"%s\n",bookmarkline);
} }
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// set the video frame for a video thumbnail // set the video frame for a video thumbnail
// (video file popup menu) // (video file popup menu)
void m_thumbframe(GtkWidget *, cchar *) void m_thumbframe(GtkWidget *, ch *)
{ {
zdialog *zd; zdialog *zd;
STATB statB; STATB statB;
int ftype, zstat, err; int ftype, zstat, err;
int minutes, seconds; int minutes, seconds;
char *pp, framefile[200]; ch *pp, framefile[200];
char *videofile = 0, thumbfile[XFCC]; ch *videofile = 0, thumbfile[XFCC];
PXB *framepxb = 0, *thumbpxb = 0; PXB *framepxb = 0, *thumbpxb = 0;
timeval thumbtimes[2]; timeval thumbtimes[2];
cchar *tip = "Play video and stop at desired frame \n" ch *tip = "Play video and stop at desired frame \n"
"Note playback time in minutes and seconds"; "Note playback time in minutes and seconds";
F1_help_topic = "video files"; F1_help_topic = "video files";
Plog(1,"m_thumbframe \n"); Plog(1,"m_thumbframe \n");
if (clicked_file) { // use clicked file if present if (clicked_file) { // use clicked file if present
videofile = clicked_file; videofile = clicked_file;
clicked_file = 0; clicked_file = 0;
} }
skipping to change at line 5500 skipping to change at line 5468
if (videofile) zfree(videofile); if (videofile) zfree(videofile);
if (framepxb) PXB_free(framepxb); if (framepxb) PXB_free(framepxb);
if (thumbpxb) PXB_free(thumbpxb); if (thumbpxb) PXB_free(thumbpxb);
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// dummy menu entry as target for "Show Hidden Files" KB shortcut // dummy menu entry as target for "Show Hidden Files" KB shortcut
void m_show_hidden(GtkWidget *, cchar *) void m_show_hidden(GtkWidget *, ch *)
{ {
Plog(1,"m_show_hidden \n"); Plog(1,"m_show_hidden \n");
KBaction("Show Hidden"); KBaction("Show Hidden");
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// dummy menu entry as target for "Current Album" KB shortcut // dummy menu entry as target for "Current Album" KB shortcut
void m_current_album(GtkWidget *, cchar *) void m_current_album(GtkWidget *, ch *)
{ {
Plog(1,"m_current_album \n"); Plog(1,"m_current_album \n");
navi::newalbum_menu_event(0,0); navi::newalbum_menu_event(0,0);
return; return;
} }
 End of changes. 222 change blocks. 
331 lines changed or deleted 291 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)