...
|
...
|
@@ -26,6 +26,7 @@
|
26
|
26
|
* Add show using all window with right button.
|
27
|
27
|
* 20250316 Add android target support.
|
28
|
28
|
* Delay loading images if over fps deadline.
|
|
29
|
+ * Scroll by finger. Big image on double click.
|
29
|
30
|
*
|
30
|
31
|
* Author: Dario Rodriguez dario@darionomono.com
|
31
|
32
|
* (c) Dario Rodriguez 2025
|
...
|
...
|
@@ -46,7 +47,9 @@
|
46
|
47
|
|
47
|
48
|
#define UTF8DOWNARROW "\xe2\x86\x86" /* U+2186 in UTF-8 */
|
48
|
49
|
|
|
50
|
+#ifndef ANDROID
|
49
|
51
|
#define SIMANDROID
|
|
52
|
+#endif
|
50
|
53
|
|
51
|
54
|
#define TARGETFPS 30
|
52
|
55
|
|
...
|
...
|
@@ -74,6 +77,8 @@
|
74
|
77
|
#define FONTHUGESIZE 48
|
75
|
78
|
#endif
|
76
|
79
|
|
|
80
|
+#define SCROLLTHRESHOLD (LEFTIMAGESIDELEN/3)
|
|
81
|
+
|
77
|
82
|
#if defined(SIMANDROID)
|
78
|
83
|
#undef ROOTDIR
|
79
|
84
|
#define ROOTDIR "/var/www/default/animeshot/"
|
...
|
...
|
@@ -192,6 +197,7 @@ typedef struct texture_t {
|
192
|
197
|
int textureh;
|
193
|
198
|
int has_texture;
|
194
|
199
|
int has_failedload;
|
|
200
|
+ xywh_t source; /* be able to detect a "double click" */
|
195
|
201
|
} texture_t;
|
196
|
202
|
|
197
|
203
|
typedef struct body_t {
|
...
|
...
|
@@ -208,7 +214,9 @@ typedef struct body_t {
|
208
|
214
|
font_t *ptrfontbig;
|
209
|
215
|
font_t *ptrfonthuge;
|
210
|
216
|
texture_t texture;
|
|
217
|
+ int is_displayingtexture;
|
211
|
218
|
texture_t bigtexture;
|
|
219
|
+ int flag_drawbigtexture;
|
212
|
220
|
} body_t;
|
213
|
221
|
|
214
|
222
|
typedef struct im_t {
|
...
|
...
|
@@ -264,17 +272,23 @@ int is_imagefilename(char *filename);
|
264
|
272
|
Image imutil_loadimage(const char *filename);
|
265
|
273
|
void imutil_fpsreset(void);
|
266
|
274
|
int imutil_fpsleft(void);
|
|
275
|
+long long imutil_milliseconds(void);
|
267
|
276
|
|
268
|
277
|
int
|
269
|
278
|
main(int argc, char *argv[])
|
270
|
279
|
{
|
271
|
280
|
im_t *im;
|
272
|
|
- Vector2 mousepos,wheel,oldmousepos;
|
|
281
|
+ Vector2 mousepos,wheel,oldmousepos,scrollstartpos;
|
273
|
282
|
int flag_ignorelmb;
|
274
|
283
|
int lmbpressed,lmbreleased,lmbdown,rmbdown,oldlmbdown,oldrmbdown;
|
275
|
284
|
int click_avail;
|
276
|
285
|
int has_mousechanges;
|
277
|
286
|
int needs_nextredraw;
|
|
287
|
+ long long scrollstart;
|
|
288
|
+ long long scrolllast;
|
|
289
|
+ int scrollspeed;
|
|
290
|
+ int is_scrolling;
|
|
291
|
+ int leftscrollposstart;
|
278
|
292
|
char *sel_menu,*sel_submenu;
|
279
|
293
|
if((im=im_init("Fichero\nAjustes\nSalir\n\nEditar\nNuevo directorio\n\nAyuda\nInformación sobre el programa\n\n",ROOTDIR))==NULL) {
|
280
|
294
|
return(1);
|
...
|
...
|
@@ -283,6 +297,8 @@ main(int argc, char *argv[])
|
283
|
297
|
mousepos=(Vector2) {.x=0,.y=0};
|
284
|
298
|
lmbdown=rmbdown=-1;
|
285
|
299
|
needs_nextredraw=1;
|
|
300
|
+ scrollstart=0;
|
|
301
|
+ is_scrolling=0;
|
286
|
302
|
while(!WindowShouldClose()) {
|
287
|
303
|
imutil_fpsreset();
|
288
|
304
|
oldmousepos=mousepos;
|
...
|
...
|
@@ -296,21 +312,57 @@ main(int argc, char *argv[])
|
296
|
312
|
rmbdown=IsMouseButtonDown(1);
|
297
|
313
|
click_avail=1;
|
298
|
314
|
has_mousechanges=(lmbdown!=oldlmbdown || rmbdown!=oldrmbdown || mousepos.x!=oldmousepos.x || mousepos.y!=oldmousepos.y || wheel.x!=0 || wheel.y!=0)?1:0;
|
299
|
|
- needs_nextredraw=(has_mousechanges==0 && needs_nextredraw==0)?0:1;
|
300
|
|
- if(needs_nextredraw==0) {
|
301
|
|
- BeginDrawing();
|
302
|
|
- EndDrawing();
|
303
|
|
- continue;
|
304
|
|
- }
|
305
|
315
|
needs_nextredraw=0;
|
|
316
|
+ /* process scrolling */
|
|
317
|
+ if(lmbdown==1 && oldlmbdown==0 && scrollstart==0 && mousepos.y>im->body->xywh.y) {
|
|
318
|
+ scrollstart=imutil_milliseconds();
|
|
319
|
+ scrollstartpos=mousepos;
|
|
320
|
+ leftscrollposstart=im->body->leftscrollpos;
|
|
321
|
+ }
|
|
322
|
+ if(scrollstart!=0 && lmbdown==0) {
|
|
323
|
+ scrollstart=0;
|
|
324
|
+ if(is_scrolling)
|
|
325
|
+ click_avail=0; /* this click is the mouseup of the scroll */
|
|
326
|
+ }
|
|
327
|
+ is_scrolling=(scrollstart==0)?0:is_scrolling;
|
|
328
|
+ if(is_scrolling==0 && scrollstart!=0) {
|
|
329
|
+ float t;
|
|
330
|
+ t=scrollstartpos.y-mousepos.y;
|
|
331
|
+ t=(t<0)?-t:t;
|
|
332
|
+ if(t>SCROLLTHRESHOLD) {
|
|
333
|
+ is_scrolling=1;
|
|
334
|
+ scrolllast=0;
|
|
335
|
+ }
|
|
336
|
+ t=scrollstartpos.x-mousepos.x;
|
|
337
|
+ t=(t<0)?-t:t;
|
|
338
|
+ if(t>SCROLLTHRESHOLD)
|
|
339
|
+ is_scrolling=0,scrollstart=0;
|
|
340
|
+ }
|
|
341
|
+ if(is_scrolling) {
|
|
342
|
+ long long tcur,tdif;
|
|
343
|
+ long long ycur;
|
|
344
|
+ tcur=imutil_milliseconds();
|
|
345
|
+ tdif=tcur-scrolllast;
|
|
346
|
+ ycur=scrollstartpos.y-mousepos.y;
|
|
347
|
+ scrollspeed=(tdif>0)?(oldmousepos.y-mousepos.y)*100000/tdif:0;
|
|
348
|
+ im->body->leftscrollpos=leftscrollposstart+ycur;
|
|
349
|
+ scrolllast=tcur;
|
|
350
|
+ }
|
|
351
|
+ if(is_scrolling==0 && scrollspeed!=0) {
|
|
352
|
+ scrollspeed=scrollspeed*4/5;
|
|
353
|
+ im->body->leftscrollpos+=scrollspeed;
|
|
354
|
+ }
|
306
|
355
|
/* process clicks on menus */
|
307
|
356
|
if(click_avail) {
|
308
|
357
|
sel_menu=sel_submenu=NULL;
|
309
|
358
|
im_menubar_mouse(im->menubar, mousepos, lmbpressed, lmbreleased, lmbdown, &click_avail, &sel_menu, &sel_submenu);
|
310
|
359
|
if(sel_menu!=NULL && sel_submenu!=NULL) {
|
|
360
|
+
|
311
|
361
|
#if 1
|
312
|
362
|
fprintf(stderr,"SELECTED: \"%s\"->\"%s\"\n",sel_menu,sel_submenu);
|
313
|
363
|
#endif
|
|
364
|
+ if(strcmp(sel_submenu,"Salir")==0)
|
|
365
|
+ break; /* exit from main loop */
|
314
|
366
|
}
|
315
|
367
|
}
|
316
|
368
|
if(click_avail)
|
...
|
...
|
@@ -353,6 +405,13 @@ fprintf(stderr,"SELECTED: \"%s\"->\"%s\"\n",sel_menu,sel_submenu);
|
353
|
405
|
}
|
354
|
406
|
}
|
355
|
407
|
#endif
|
|
408
|
+ if(has_mousechanges==0 && needs_nextredraw==0) {
|
|
409
|
+ /* Wait for new events when calling EndDrawing() */
|
|
410
|
+ EnableEventWaiting();
|
|
411
|
+ } else {
|
|
412
|
+ /* EndDrawing() doesn't wait for new events, returns immediately */
|
|
413
|
+ DisableEventWaiting();
|
|
414
|
+ }
|
356
|
415
|
EndDrawing();
|
357
|
416
|
}
|
358
|
417
|
im_free(im),im=NULL;
|
...
|
...
|
@@ -764,6 +823,7 @@ im_body_mouse(body_t *body, Vector2 mousepos, Vector2 wheel, int lmbpressed, int
|
764
|
823
|
char *ptr;
|
765
|
824
|
dirdata_t *dirdata;
|
766
|
825
|
listingdata_t *ld;
|
|
826
|
+ int margin;
|
767
|
827
|
if(body==NULL || click_avail==NULL || body->currentdirdata<0 || body->currentdirdata>=body->sizedirdata || body->dirdata[body->currentdirdata]==NULL)
|
768
|
828
|
return(-1); /* sanity check error */
|
769
|
829
|
dirdata=body->dirdata[body->currentdirdata];
|
...
|
...
|
@@ -775,6 +835,17 @@ im_body_mouse(body_t *body, Vector2 mousepos, Vector2 wheel, int lmbpressed, int
|
775
|
835
|
/* check if we have to process a click */
|
776
|
836
|
if(*click_avail==0 || lmbreleased==0)
|
777
|
837
|
return(0); /* nothing else to do */
|
|
838
|
+ /* show image in full screen */
|
|
839
|
+ if(body->flag_drawbigtexture) {
|
|
840
|
+ if(lmbreleased)
|
|
841
|
+ body->flag_drawbigtexture=0;
|
|
842
|
+ return(0); /* nothing else to do */
|
|
843
|
+ }
|
|
844
|
+ margin=body->ptrfont->height/4;
|
|
845
|
+ if(body->is_displayingtexture && lmbreleased && is_imutil_insidexywh(mousepos,&(body->texture.source),margin)) {
|
|
846
|
+ body->flag_drawbigtexture=1;
|
|
847
|
+ return(0); /* nothing else to do */
|
|
848
|
+ }
|
778
|
849
|
/* leftside backbutton */
|
779
|
850
|
if(is_imutil_insidexywh(mousepos,&(body->backxywh),0)) {
|
780
|
851
|
static char sep[]={SEP};
|
...
|
...
|
@@ -845,6 +916,25 @@ im_body_draw(body_t *body, Vector2 mousepos, int lmbdown, int rmbdown, int windo
|
845
|
916
|
fonthuge=body->ptrfonthuge;
|
846
|
917
|
FILLXYWH(body->backxywh,0,0,0,0);
|
847
|
918
|
margin=font->height/4;
|
|
919
|
+ body->is_displayingtexture=0;
|
|
920
|
+ /* if we are displaying a full screenimage... */
|
|
921
|
+ if(body->flag_drawbigtexture && body->texture.has_texture) {
|
|
922
|
+ /* draw image in full screen */
|
|
923
|
+ int maxw,maxh;
|
|
924
|
+ maxw=windowwidth;
|
|
925
|
+ maxh=windowheight-body->xywh.y;
|
|
926
|
+ if(body->bigtexture.has_texture==0 || strcmp(body->bigtexture.currentpath,body->texture.currentpath)!=0)
|
|
927
|
+ texture_load(&(body->bigtexture),body->texture.currentpath,maxw,maxh);
|
|
928
|
+ if(body->bigtexture.has_texture && strcmp(body->bigtexture.currentpath,body->texture.currentpath)==0) {
|
|
929
|
+ int x0,y0;
|
|
930
|
+ x0=0;
|
|
931
|
+ y0=body->xywh.y;
|
|
932
|
+ texture_draw(&(body->bigtexture),x0,y0,maxw,maxh);
|
|
933
|
+ return(0); /* all done */
|
|
934
|
+ } else {
|
|
935
|
+ body->flag_drawbigtexture=0; /* error loading big texture, draw screen normally */
|
|
936
|
+ }
|
|
937
|
+ }
|
848
|
938
|
/* calculate positions */
|
849
|
939
|
for(i=0;i<body->sizedirdata;i++) {
|
850
|
940
|
if(body->dirdata[i]==NULL)
|
...
|
...
|
@@ -1011,7 +1101,7 @@ fprintf(stderr,"elem:\"%s\" sidelen:%i old:%ix%i new:%ix%i\n",elem->name+1,sidel
|
1011
|
1101
|
DrawTexture(*te,thumb->screenxywh.x,thumb->screenxywh.y,WHITE);
|
1012
|
1102
|
has_imagedrawn=1;
|
1013
|
1103
|
lastx=xywh->x+xywh->w,lasty=xywh->y+xywh->h+yoff;
|
1014
|
|
- if(is_leftside && lmbdown==0 && rmbdown==0 && is_imutil_insidexywh(mousepos,&(thumb->screenxywh),margin)) {
|
|
1104
|
+ if(is_leftside && rmbdown==0 && is_imutil_insidexywh(mousepos,&(thumb->screenxywh),margin)) {
|
1015
|
1105
|
/* draw image in rightside */
|
1016
|
1106
|
char fullpath[2048];
|
1017
|
1107
|
int maxw,maxh;
|
...
|
...
|
@@ -1029,31 +1119,11 @@ fprintf(stderr,"elem:\"%s\" sidelen:%i old:%ix%i new:%ix%i\n",elem->name+1,sidel
|
1029
|
1119
|
x0=body->leftsize-DEFAULTDIRDATATRIANGLEW;
|
1030
|
1120
|
y0=body->xywh.y;
|
1031
|
1121
|
texture_draw(&(body->texture),x0,y0,maxw,maxh);
|
|
1122
|
+ body->is_displayingtexture=1;
|
|
1123
|
+ memcpy(&(body->texture.source),&(thumb->screenxywh),sizeof(body->texture.source));
|
1032
|
1124
|
flag_skiprightside=1;
|
1033
|
1125
|
}
|
1034
|
1126
|
}
|
1035
|
|
- if(is_leftside && lmbdown==0 && rmbdown!=0 && is_imutil_insidexywh(mousepos,&(thumb->screenxywh),margin)) {
|
1036
|
|
- /* draw image in full screen */
|
1037
|
|
- char fullpath[2048];
|
1038
|
|
- int maxw,maxh;
|
1039
|
|
- maxw=windowwidth;
|
1040
|
|
- maxh=windowheight-body->xywh.y;
|
1041
|
|
- snprintf(fullpath,sizeof(fullpath),"%s/%s/%s",body->rootdir,dirdata->dirname,elem->name+1);
|
1042
|
|
- fullpath[sizeof(fullpath)-1]='\0';
|
1043
|
|
- if((body->bigtexture.has_texture==0 && !(body->bigtexture.has_failedload && strcmp(body->bigtexture.currentpath,fullpath)==0))
|
1044
|
|
- || strcmp(body->bigtexture.currentpath,fullpath)!=0
|
1045
|
|
- ) {
|
1046
|
|
- texture_load(&(body->bigtexture),fullpath,maxw,maxh);
|
1047
|
|
- }
|
1048
|
|
- if(body->bigtexture.has_texture && strcmp(body->bigtexture.currentpath,fullpath)==0) {
|
1049
|
|
- int x0,y0;
|
1050
|
|
- x0=0;
|
1051
|
|
- y0=body->xywh.y;
|
1052
|
|
- texture_draw(&(body->bigtexture),x0,y0,maxw,maxh);
|
1053
|
|
- flag_skipall=1;
|
1054
|
|
- break;
|
1055
|
|
- }
|
1056
|
|
- }
|
1057
|
1127
|
}
|
1058
|
1128
|
}
|
1059
|
1129
|
if(has_imagedrawn==0) {
|
...
|
...
|
@@ -1639,3 +1709,13 @@ imutil_fpsleft(void)
|
1639
|
1709
|
return(1);
|
1640
|
1710
|
}
|
1641
|
1711
|
|
|
1712
|
+long long
|
|
1713
|
+imutil_milliseconds(void)
|
|
1714
|
+{
|
|
1715
|
+ long long res;
|
|
1716
|
+ struct timeval now;
|
|
1717
|
+ gettimeofday(&now,NULL);
|
|
1718
|
+ res=((long long) (now.tv_sec))*1000000L+((long long) (now.tv_usec));
|
|
1719
|
+ return(res);
|
|
1720
|
+}
|
|
1721
|
+
|