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 |