/* * imgmover.c * * Simple C application using raylib to cselect/rotate/classify/arrange photos. * * History: * 20250902 Rewrite using parts of old prototype. * 20250920 Reimplemented all scroll functionality. * * Author: Dario Rodriguez dario@darionomono.com * (c) Dario Rodriguez 2025 * This program is licensed under the terms of GNU GPL v2.1+ */ #include #include #include #include #include #include #include #include #include #if !defined(__linux__) && !defined(ANDROID) #include "win32_pipe.h" #endif #include "rayui.h" #include "bg.h" #define DEFAULTWIDTH 1280 #define DEFAULTHEIGHT 768 //#define LEFTIMAGESIDELEN 326 #define LEFTIMAGESIDELEN 64 #define SCROLLTHRESHOLD (LEFTIMAGESIDELEN/3) #define WHEELSTEP LEFTIMAGESIDELEN #define SEP '/' #define SIZEBGLOAD (3*((DEFAULTWIDTH+(LEFTIMAGESIDELEN-1))/LEFTIMAGESIDELEN)*((DEFAULTHEIGHT+(LEFTIMAGESIDELEN-1))/LEFTIMAGESIDELEN)) #define DEFAULTDIRDATAHEIGHT 492 #define ADDREMOVEDIRDATAHEIGHT 128 #define UTF8DOWNARROW "\xe2\x86\x86" /* U+2186 in UTF-8 */ #define DEFAULTDIRDATATRIANGLEW 35 #define BLOCKLISTINGBUF 2048 #define BLOCKLISTINGELEMS 1024 #define BLOCKDIRDATA 16 #define MYFUNC "UNKNOWN" #if 0 #define IMDEBUG(a) fprintf(stderr,"%s:%i: %s: %s\n",__FILE__,__LINE__,MYFUNC,a) #define IMDEBUG2(a) fprintf(stderr,"%s:%i: %s: ",__FILE__,__LINE__,MYFUNC),fprintf a #else #define IMDEBUG(a) #define IMDEBUG2(a) #endif // RIGHTSIDEMARGIN=FONTBIGSIZE/2 typedef struct thumb_t { whxy_t whxy; whxy_t screenwhxy; Texture2D texture; int has_texture; int has_failedload; } thumb_t; typedef struct listingdata_t { thumb_t left; thumb_t right; char *name; /* first byte in the name is the type, next is the name, i.e. a directory is "dhome" and a file is "f.bashrc" (this is done for easier sorting) */ } listingdata_t; typedef struct listing_t { int sizeelems; int usedelems; listingdata_t *elems; int sizebuf; int usedbuf; char *buf; int has_leftwhxy; int has_rightwhxy; whxy_t lastleftwhxy; } listing_t; typedef struct dirdata_t { int height; char *dirname; listing_t listing; int leftscrollpos; } dirdata_t; typedef struct texture_t { char currentpath[2048]; Texture2D texture; int texturew; int textureh; int has_texture; int has_failedload; whxy_t source; /* be able to detect a "double click" */ } texture_t; typedef struct body_t { rayui_t *rayui; char *rootdir; whxy_t whxy; whxy_t backwhxy; int leftsize; int sizedirdata; dirdata_t **dirdata; int currentdirdata; int rightscrollpos; font_t *ptrfont; font_t *ptrfontbig; font_t *ptrfonthuge; texture_t texture; int is_displayingtexture; texture_t bigtexture; int flag_drawbigtexture; whxy_t dirdataadd; Font roundedbox; bg_t *bg; char selectedpath[2048]; } body_t; typedef struct im_t { rayui_t *rayui; mousedata_t mousedata; body_t *body; } im_t; im_t *im_init(char *rootdir); void im_free(im_t *im); body_t *im_body_init(rayui_t *rayui, int w, int h, int x, int y, int leftsidesize, char *rootdir); void im_body_free(body_t *body); int im_body_add(body_t *body,char *dir); int im_body_tryselect(body_t *body, Vector2 mousepos); int im_body_mouse(body_t *body, mousedata_t *mousedata); int im_body_draw(body_t *body, mousedata_t *mousedata, int windowwidth, int windowheight, int *needs_nextredraw); static int strptrcmp(void *a,void *b); int listing_get(listing_t *listing, char *pathprefix, char *path, int flag_sort); void listing_freedata(listing_t *listing); int listing_fillwhxy(listing_t *listing, font_t *font, int w, int sidelen, int is_left, int rightsidemargin); int is_imagefilename(char *filename); int texture_load(texture_t *texture, char *fullpath, int maxw, int maxh, bg_t *bg); int texture_draw(texture_t *texture, int x0, int y0, int maxw, int maxh); int texture_freedata(texture_t *texture); int imutil_aspectmaximize(int w, int h, int maxw, int maxh, int *neww, int *newh); int main(int argc, char *argv[]) { im_t *im; char *rootdir; int needs_nextredraw; if(argc<2 || strcmp(argv[argc-1],"--help")==0) { global_messagebox("imgmover\n\nSyntax: %s \n",(argc>0)?argv[0]:"imgmover"); return(1); } rootdir=argv[1]; bg_staticinit(); if((im=im_init(rootdir))==NULL) { global_messagebox("%s","Couldn't init"); return(1); } while(!WindowShouldClose()) { rayui_timereset(im->rayui); needs_nextredraw=0; rayui_getmousedata(im->rayui,&(im->mousedata)); /* process mouse actions */ if(im->mousedata.click_avail) im_body_mouse(im->body, &(im->mousedata)); /* draw screen contents */ BeginDrawing(); ClearBackground(RAYWHITE); rayui_scrollablerectreset(im->rayui,&(im->mousedata)); im_body_draw(im->body,&(im->mousedata),im->rayui->w,im->rayui->h,&needs_nextredraw); if(needs_nextredraw==0 && im->mousedata.has_mousechanges==0 && im->mousedata.scrollspeed==0) { /* Wait for new events when calling EndDrawing() */ EnableEventWaiting(); } else { /* EndDrawing() doesn't wait for new events, returns immediately */ DisableEventWaiting(); } EndDrawing(); } im_free(im),im=NULL; bg_staticfini(); return(0); } im_t * im_init(char *rootdir) { im_t *im; char *errstr; if((im=calloc(1,sizeof(im_t)))==NULL) { im_free(im),im=NULL; return(NULL); /* insuf. mem. */ } if((errstr="init interface")==NULL || (im->rayui=rayui_init(DEFAULTWIDTH,DEFAULTHEIGHT,"Image Mover",NULL))==NULL || (errstr="Couldn't init interface data")==NULL || (im->body=im_body_init(im->rayui,im->rayui->w,im->rayui->h, 0, 0, im->rayui->w*2/3, rootdir))==NULL ) { global_messagebox("Couldn't %s",errstr); im_free(im),im=NULL; return(NULL); /* insuf. mem. */ } /* add the starting directory */ im_body_add(im->body,""); return(im); } void im_free(im_t *im) { if(im==NULL) return; if(im->body!=NULL) im_body_free(im->body),im->body=NULL; if(im->rayui!=NULL) rayui_free(im->rayui),im->rayui=NULL; free(im),im=NULL; } body_t * im_body_init(rayui_t *rayui, int w, int h, int x, int y, int leftsidesize, char *rootdir) { body_t *body; char *errstr; static char sep[]={SEP,'\0'}; if(rayui->font==NULL || rayui->fontbig==NULL || rayui->fonthuge==NULL || rootdir==NULL) { global_messagebox("im_body_init sanity check failed"); return(NULL); /* sanity check failed */ } if((errstr="Insuf. mem. for body")==NULL || (body=calloc(1,sizeof(body_t)))==NULL || (errstr="Insuf. mem. for rootdir str")==NULL || (body->rootdir=strdup(rootdir))==NULL || (errstr="Error init bg")==NULL || (body->bg=bg_init(SIZEBGLOAD))==NULL ) { global_messagebox("%s",errstr); im_body_free(body),body=NULL; return(NULL); } body->rayui=rayui; FILLWHXY(body->whxy,w,h,x,y); #if 1 fprintf(stderr,"im_body_init: %ix%i+%i+%i\n",UNROLLWHXY(body->whxy)); #endif body->leftsize=leftsidesize; body->ptrfont=rayui->font; body->ptrfontbig=rayui->fontbig; body->ptrfonthuge=rayui->fonthuge; if(body->rootdir[0]!='\0' && strcmp(body->rootdir,sep)!=0 && body->rootdir[strlen(body->rootdir)-1]==sep[0]) body->rootdir[strlen(body->rootdir)-1]='\0'; /* rootdir doesn't need the final '/' */ /* init rounded box glyph (a really big zero) */ { int codepoints[]={'O','+','-'}; body->roundedbox=LoadFontFromMemory(".ttf",rayui->defaultfontdata,rayui->sizedefaultfontdata,ADDREMOVEDIRDATAHEIGHT*4,codepoints,sizeof(codepoints)/sizeof(codepoints[0])); } return(body); } void im_body_free(body_t *body) { int i; dirdata_t *dirdata; if(body==NULL) return; /* nothing to do */ if(body->dirdata!=NULL) { for(i=0;isizedirdata;i++) { if((dirdata=body->dirdata[i])==NULL) continue; if(dirdata->dirname!=NULL) free(dirdata->dirname),dirdata->dirname=NULL; listing_freedata(&(dirdata->listing)); free(dirdata),dirdata=body->dirdata[i]=NULL; } free(body->dirdata),body->dirdata=NULL,body->sizedirdata=0; } texture_freedata(&(body->texture)); texture_freedata(&(body->bigtexture)); if(body->rootdir!=NULL) free(body->rootdir),body->rootdir=NULL; /* NOTE: Cannot call UnloadFont(body->roundedbox) as the data was not malloc'd; see https://github.com/raysan5/raylib/blob/master/examples/others/embedded_files_loading.c */ if(body->bg!=NULL) bg_free(body->bg),body->bg=NULL; free(body),body=NULL; return; } int im_body_add(body_t *body,char *dir) { int i; dirdata_t *dirdata; if(body==NULL || dir==NULL) return(-1); /* sanity check failed */ for(i=0;isizedirdata;i++) { if(body->dirdata[i]==NULL) break; } if(i==body->sizedirdata) { /* dirdata container full, add more slots */ dirdata_t **newdirdata; if((newdirdata=realloc(body->dirdata,sizeof(dirdata_t *)*(body->sizedirdata+BLOCKDIRDATA)))==NULL) return(-1); /* insuf. mem. */ body->dirdata=newdirdata; memset(body->dirdata+body->sizedirdata,0,sizeof(dirdata_t *)*BLOCKDIRDATA); body->sizedirdata+=BLOCKDIRDATA; } if((dirdata=body->dirdata[i]=calloc(1,sizeof(dirdata_t)))==NULL || (dirdata->dirname=strdup(dir))==NULL ) { if(dirdata!=NULL) free(dirdata),dirdata=body->dirdata[i]=NULL; return(-1); /* insuf. mem. */ } dirdata->height=DEFAULTDIRDATAHEIGHT; dirdata->dirname=strdup(dir); listing_get(&(dirdata->listing),body->rootdir,dir,1); return(0); } int im_body_tryselect(body_t *body, Vector2 mousepos) { int i; listing_t *listing; listingdata_t *elem; if(body==NULL || body->currentdirdata<0 || body->currentdirdata>=body->sizedirdata || body->dirdata[body->currentdirdata]==NULL || body->currentdirdata>=body->sizedirdata) return(-1); /* sanity check failed */ body->selectedpath[0]='\0'; if(!is_global_insidewhxy(mousepos,&(body->whxy),0) || mousepos.x>body->leftsize) return(-1); /* outside leftside */ listing=&(body->dirdata[body->currentdirdata]->listing); for(i=0;iusedelems;i++) { elem=listing->elems+i; if(is_global_insidewhxy(mousepos,&(elem->left.screenwhxy),0)) { strncpy(body->selectedpath,elem->name,sizeof(body->selectedpath)); body->selectedpath[sizeof(body->selectedpath)-1]='\0'; return(0); /* found */ } } return(-1); /* no thumbnail found for pos */ } int im_body_mouse(body_t *body, mousedata_t *mousedata) { int i; char *ptr; dirdata_t *dirdata; listingdata_t *ld; int margin; if(body==NULL || mousedata==NULL || body->currentdirdata<0 || body->currentdirdata>=body->sizedirdata || body->dirdata[body->currentdirdata]==NULL) return(-1); /* sanity check error */ dirdata=body->dirdata[body->currentdirdata]; /* wheel */ body->dirdata[body->currentdirdata]->leftscrollpos-=(int)mousedata->wheel.y*WHEELSTEP; if(is_rayui_scrolling(body->rayui,mousedata,"body.leftside",&(body->dirdata[body->currentdirdata]->leftscrollpos))) fprintf(stderr,"SCROLLING bosy.leftside newscrollpos:%i\n",body->dirdata[body->currentdirdata]->leftscrollpos); /* nothing to do, will fix coors for both wheel and scrolling in the next lines */ body->dirdata[body->currentdirdata]->leftscrollpos=(body->dirdata[body->currentdirdata]->leftscrollpos<0)?0:body->dirdata[body->currentdirdata]->leftscrollpos; if(body->dirdata[body->currentdirdata]->leftscrollpos>dirdata->listing.lastleftwhxy.y) body->dirdata[body->currentdirdata]->leftscrollpos=dirdata->listing.lastleftwhxy.y; /* check if we have to process a click */ if(mousedata->click_avail==0 || mousedata->lmbreleased==0) return(0); /* nothing else to do */ /* show image in full screen */ if(body->flag_drawbigtexture) { if(mousedata->lmbreleased) body->flag_drawbigtexture=0; return(0); /* nothing else to do */ } margin=body->ptrfont->height/4; if(body->is_displayingtexture && mousedata->lmbreleased && is_global_insidewhxy(mousedata->mousepos,&(body->texture.source),margin) && body->selectedpath[0]=='\0') { body->flag_drawbigtexture=1; return(0); /* nothing else to do */ } /* leftside backbutton */ if(is_global_insidewhxy(mousedata->mousepos,&(body->backwhxy),0)) { static char sep[]={SEP}; if((ptr=strrchr(dirdata->dirname,sep[0]))!=NULL) { /* previous dir */ *ptr='\0'; } else { /* root dir */ dirdata->dirname[0]='\0'; } listing_get(&(dirdata->listing),body->rootdir,dirdata->dirname,1); body->dirdata[body->currentdirdata]->leftscrollpos=0; mousedata->click_avail=0; return(0); } /* leftside directories */ for(i=0;ilisting.usedelems;i++) { ld=dirdata->listing.elems+i; if(ld->name[0]!='d') continue; if(is_global_insidewhxy(mousedata->mousepos,&(ld->left.screenwhxy),0)) { char *newname,*oldprefix; int l,l0,l1; static char sep[]={SEP}; oldprefix=(dirdata->dirname[0]==SEP && dirdata->dirname[1]=='\0')?"":dirdata->dirname; l0=strlen(oldprefix); l1=strlen(ld->name+1); l=l0+((l0>0)?1:0)+l1+1; if((newname=malloc(l))==NULL) return(-1); /* insuf. mem. */ if(l0>0) { memcpy(newname,oldprefix,l0); newname[l0]=sep[0]; } memcpy(newname+l0+((l0>0)?1:0),ld->name+1,l1); newname[l0+((l0>0)?1:0)+l1]='\0'; free(dirdata->dirname),dirdata->dirname=NULL; dirdata->dirname=newname; listing_get(&(dirdata->listing),body->rootdir,dirdata->dirname,1); body->dirdata[body->currentdirdata]->leftscrollpos=0; mousedata->click_avail=0; return(0); } } /* dirdata processing */ if(body->selectedpath[0]=='\0') { /* dirdata select */ if(mousedata->mousepos.x>body->leftsize && mousedata->mousepos.y>body->whxy.y) { int righty; for(righty=body->whxy.y,i=0;isizedirdata;i++) { if(body->dirdata[i]==NULL) continue; if(mousedata->mousepos.y>=righty && mousedata->mousepos.y<(righty+body->dirdata[i]->height) && i!=body->currentdirdata) { body->currentdirdata=i; mousedata->click_avail=0; return(0); } righty+=body->dirdata[i]->height; } } /* detect click on "add dirdata" button */ if(is_global_insidewhxy(mousedata->mousepos,&(body->dirdataadd),0)) { im_body_add(body,body->dirdata[body->currentdirdata]->dirname); mousedata->click_avail=0; return(0); } /* dirdata remove */ #warning TODO } /* unselect selectedpath */ if(mousedata->lmbpressed==0 && body->selectedpath[0]!='\0') { if(mousedata->mousepos.x>body->leftsize && mousedata->mousepos.y>body->whxy.y) { int righty; for(righty=body->whxy.y,i=0;isizedirdata;i++) { if(body->dirdata[i]==NULL) continue; if(mousedata->mousepos.y>=righty && mousedata->mousepos.y<(righty+body->dirdata[i]->height) && i!=body->currentdirdata && strcmp(body->dirdata[i]->dirname,body->dirdata[body->currentdirdata]->dirname)!=0) { #warning TODO #if 1 fprintf(stderr,"WOULD MOVE \"%s/%s\" to \"%s\"\n",body->dirdata[body->currentdirdata]->dirname,body->selectedpath+1,body->dirdata[i]->dirname); #endif mousedata->click_avail=0; break; } righty+=body->dirdata[i]->height; } } body->selectedpath[0]='\0'; } return(0); } #ifdef MYFUNC #undef MYFUNC #define MYFUNC "im_body_draw" #endif int im_body_draw(body_t *body, mousedata_t *mousedata, int windowwidth, int windowheight, int *needs_nextredraw) { int i,k,margin,righty; int lastx,lasty; dirdata_t *dirdata; listingdata_t *elem; Vector2 v2,m2; font_t *font,*fontbig,*fonthuge; int is_leftside; int flag_skiprightside; int flag_skipall; int xoff,yoff; thumb_t *thumb; char statustooltip[1024]; char imageundermouse[1024]; thumb_t *selectedthumb; IMDEBUG("Pre-sanitycheck"); if(body==NULL) return(-1); font=body->ptrfont; fontbig=body->ptrfontbig; fonthuge=body->ptrfonthuge; FILLWHXY(body->backwhxy,0,0,0,0); margin=font->height/4; body->is_displayingtexture=0; selectedthumb=NULL; /* if we are displaying a full screenimage... */ if(body->flag_drawbigtexture && body->texture.has_texture) { /* draw image in full screen */ int maxw,maxh; IMDEBUG("begin draw"); maxw=windowwidth; maxh=windowheight-body->whxy.y; if(body->bigtexture.has_texture==0 || strcmp(body->bigtexture.currentpath,body->texture.currentpath)!=0) { #if 1 fprintf(stderr,"~~~ TEXTURE_LOAD FOR BIGTEXTURE \"%s\"\n",body->texture.currentpath); #endif bg_add(body->bg,body->texture.currentpath,1); texture_load(&(body->bigtexture),body->texture.currentpath,maxw,maxh,body->bg); } if(body->bigtexture.has_texture && strcmp(body->bigtexture.currentpath,body->texture.currentpath)==0) { int x0,y0; x0=0; y0=body->whxy.y; texture_draw(&(body->bigtexture),x0,y0,maxw,maxh); return(0); /* all done */ } else { #if 0 #warning TEMP body->flag_drawbigtexture=0; /* error loading big texture, draw screen normally */ #endif } } /* calculate positions */ IMDEBUG("calculate positions"); for(i=0;isizedirdata;i++) { if(body->dirdata[i]==NULL) continue; if(body->dirdata[i]->listing.has_rightwhxy==0) { int sidelen; sidelen=body->dirdata[i]->height-(fontbig->height+fontbig->height/4+font->height+margin*4+fontbig->height/4); listing_fillwhxy(&(body->dirdata[i]->listing),body->ptrfont,body->whxy.w-(body->whxy.x+body->leftsize),sidelen,0,0); body->dirdata[i]->listing.has_rightwhxy=1; } if(i==body->currentdirdata && body->dirdata[i]->listing.has_leftwhxy==0) { listing_fillwhxy(&(body->dirdata[i]->listing),body->ptrfont,body->leftsize,LEFTIMAGESIDELEN,1,0); body->dirdata[i]->listing.has_leftwhxy=1; } } /* draw left side background */ IMDEBUG("draw left bg"); { whxy_t whxy; FILLWHXY(whxy,body->leftsize, body->whxy.h,body->whxy.x,body->whxy.y); rayui_scrollablerectadd(body->rayui,mousedata,&whxy,"body.leftside",body->dirdata[body->currentdirdata]->leftscrollpos,(int (*)(void *, Vector2))im_body_tryselect,body,SCROLLTHRESHOLD); } DrawRectangle(body->whxy.x,body->whxy.y,body->leftsize, body->whxy.h, (Color){ 215, 215, 215, 255 } ); IMDEBUG2((stderr,"%ix%i+%i+%i\n",body->leftsize, body->whxy.h,body->whxy.x,body->whxy.y)); /* draw right side background */ IMDEBUG2((stderr,"body->whxy:%ix%i+%i+%i\n",UNROLLWHXY(body->whxy))); IMDEBUG2((stderr,"body->leftsize:%i\n",body->leftsize)); IMDEBUG("draw right bg"); DrawRectangle(body->whxy.x+body->leftsize,body->whxy.y,body->whxy.w-body->leftsize, body->whxy.h, (Color){ 227, 227, 227, 255 } ); IMDEBUG2((stderr,"DrawRectangle(body->whxy.x(%i)+body->leftsize(%i),body->whxy.y(%i),body->whxy.w(%i)-body->leftsize(%i), body->whxy.h(%i), (Color){ 227, 227, 227, 255 } );\n" ,body->whxy.x,body->leftsize,body->whxy.y,body->whxy.w,body->leftsize, body->whxy.h)); IMDEBUG2((stderr,"%ix%i+%i+%i\n",body->whxy.w-body->leftsize, body->whxy.h,body->whxy.x+body->leftsize,body->whxy.y)); /* reset lazy load marks */ bg_resetmarks(body->bg); /* first pass, draw leftside, second pass, draw all of rightside */ statustooltip[0]='\0'; for(is_leftside=1,flag_skiprightside=flag_skipall=0;is_leftside>=0 && flag_skiprightside==0 && flag_skipall==0;is_leftside--) { for(i=(is_leftside)?body->currentdirdata:0,righty=body->whxy.y;flag_skipall==0 && ((is_leftside && i==body->currentdirdata) || (!is_leftside && isizedirdata));i++) { int sidelen; if((dirdata=body->dirdata[i])==NULL) continue; if(is_leftside && !(i==body->currentdirdata)) continue; /* this element is not in leftside */ sidelen=(is_leftside)?LEFTIMAGESIDELEN:dirdata->height-(fontbig->height+fontbig->height/4+font->height+margin*4+fontbig->height/4); /* draw left side back arrow if is_leftside and not in root dir */ if(is_leftside && !(dirdata->dirname[0]=='\0' || (dirdata->dirname[0]==SEP && dirdata->dirname[1]=='\0'))) { m2=MeasureTextEx(fontbig->font,UTF8DOWNARROW,fontbig->height,0); v2.x=(float) (body->whxy.x+fontbig->height/2); v2.y=(float) (body->whxy.y+fontbig->height/4+(fontbig->height-v2.x)/2)-body->dirdata[body->currentdirdata]->leftscrollpos; FILLWHXY(body->backwhxy,m2.x+fontbig->height/4,m2.x+fontbig->height/4,v2.x-fontbig->height/4,v2.y-fontbig->height/8); #if 0 DrawTexture(fontbig->font.texture, 0, 0, WHITE); /* font glyphs -- see https://github.com/raysan5/raylib/issues/2022 */ DrawRectangle(UNROLLXYWH(body->backwhxy),((Color){ 0,255,0,255 })); /* hit zone */ #endif if((v2.y+fontbig->height)>=0) DrawTextPro(fontbig->font,UTF8DOWNARROW,(Vector2){v2.x+m2.x,v2.y},(Vector2){0,0},90.0,fontbig->height,0,(Color){65,65,65,255}); } if(is_leftside) { /* ...dirname */ v2.y=(float) (body->whxy.y+fontbig->height/4-body->dirdata[body->currentdirdata]->leftscrollpos); if((v2.y+fontbig->height)>=0) { m2=MeasureTextEx(fontbig->font,dirdata->dirname,fontbig->height,0); v2.x=(float) (body->whxy.x+fontbig->height/2)+(body->leftsize-(body->whxy.x+fontbig->height)-m2.x)/2; DrawTextEx(fontbig->font ,dirdata->dirname ,v2 ,fontbig->height ,0 ,(Color){ 65, 65, 65, 255 } ); } } else { /* rightside */ /* ...bg */ DrawRectangle(body->whxy.x+body->leftsize,righty,body->whxy.w-body->leftsize, dirdata->height,(i==body->currentdirdata)?((Color){ 168, 168, 168, 255 }):((Color){ 227, 227, 227, 255 })); /* ...bottom separator */ DrawRectangle(body->whxy.x+body->leftsize,righty+dirdata->height-1,body->whxy.w-body->leftsize, 1, (Color){ 221, 221, 221, 255 } ); /* ...dirname */ DrawTextEx(fontbig->font ,dirdata->dirname ,(Vector2) {body->whxy.x+body->leftsize+fontbig->height/2,righty+fontbig->height/4} ,fontbig->height ,0 ,(i==body->currentdirdata)?((Color){ 240, 240, 240, 255 }):((Color){ 65, 65, 65, 255 }) ); } /* directories */ xoff=((is_leftside)?0:body->leftsize); yoff=((is_leftside)?body->whxy.y:righty)+fontbig->height/4+fontbig->height+font->height/4-(is_leftside?body->dirdata[body->currentdirdata]->leftscrollpos:0); if(is_leftside && dirdata->dirname[0]=='\0') yoff-=fontbig->height/4+fontbig->height; for(k=0,lastx=lasty=0;klisting.usedelems;k++) { elem=dirdata->listing.elems+k; thumb=(is_leftside)?&(elem->left):&(elem->right); if(elem->name[0]!='d' || strcmp(elem->name,"d.")==0 || strcmp(elem->name,"d..")==0) { if(elem->name[0]=='d') FILLWHXY(thumb->screenwhxy,0,0,0,0); continue; } if((thumb->whxy.y+yoff)>(body->whxy.y+body->whxy.h) || thumb->whxy.w==0 || thumb->whxy.h==0) { #warning TODO: if !is_leftside, draw "..." in huge font using lastx,lasty as reference break; } if((thumb->whxy.y+yoff+thumb->whxy.h)<0) { FILLWHXY(thumb->screenwhxy,0,0,0,0); continue; } FILLWHXY(thumb->screenwhxy,thumb->whxy.w,thumb->whxy.h,thumb->whxy.x+xoff,thumb->whxy.y+yoff); DrawRectangleLines(thumb->screenwhxy.x,thumb->screenwhxy.y,thumb->screenwhxy.w,thumb->screenwhxy.h,((Color){ 65, 65, 65, 255 })); DrawTextEx(font->font,elem->name+1,(Vector2){thumb->screenwhxy.x+margin,thumb->screenwhxy.y+margin},font->height,0,((Color){ 65, 65, 65, 255 })); lastx=thumb->screenwhxy.x+thumb->screenwhxy.w,lasty=thumb->screenwhxy.y+thumb->screenwhxy.h; } for(;klisting.usedelems;k++) { elem=dirdata->listing.elems+k; if(elem->name[0]!='d') continue; thumb=(is_leftside)?&(elem->left):&(elem->right); FILLWHXY(thumb->screenwhxy,0,0,0,0); } /* files */ imageundermouse[0]='\0'; for(k=0,lastx=lasty=0;klisting.usedelems;k++) { Texture2D *te; whxy_t *whxy; elem=dirdata->listing.elems+k; thumb=(is_leftside)?&(elem->left):&(elem->right); whxy=&(thumb->whxy); te=&(thumb->texture); int has_imagedrawn; if(elem->name[0]!='f' && elem->name[0]!='l') continue; if((whxy->y+yoff)>(body->whxy.y+body->whxy.h) || whxy->w==0 || whxy->h==0) { #warning TODO: if !is_leftside, draw "..." in huge font using lastx,lasty as reference break; } if(is_leftside && is_global_insidewhxy(mousedata->mousepos,&(thumb->screenwhxy),margin)) { strncpy(statustooltip,elem->name+1,sizeof(statustooltip)); statustooltip[sizeof(statustooltip)-1]='\0'; } /* show image */ has_imagedrawn=0; if(is_imagefilename(elem->name+1) && !(thumb->screenwhxy.y>(body->whxy.y+body->whxy.h) || (thumb->screenwhxy.y+thumb->screenwhxy.h)whxy.y)) { if(is_global_insidewhxy(mousedata->mousepos,&(thumb->screenwhxy),0)) { snprintf(imageundermouse,sizeof(imageundermouse),"%s/%s/%s",body->rootdir,dirdata->dirname,elem->name+1); imageundermouse[sizeof(imageundermouse)-1]='\0'; } if(thumb->has_texture==0 && thumb->has_failedload==0) { bgload_t *bgload; char fullpath[2048]; *needs_nextredraw=1; snprintf(fullpath,sizeof(fullpath),"%s/%s/%s",body->rootdir,dirdata->dirname,elem->name+1); fullpath[sizeof(fullpath)-1]='\0'; bgload=bg_get(body->bg,fullpath); if(bgload!=NULL && bgload->has_data!=0) { Image im; im=ImageCopy(bgload->image); if(IsImageValid(im)) { int neww,newh; Image im2,impixel; #if 1 fprintf(stderr,"Loaded %s\n",fullpath); { int oldw=im.width,oldh=im.height; #endif im2=GenImageColor(sidelen,sidelen,(Color){0,0,0,255}); imutil_aspectmaximize(im.width,im.height,sidelen,sidelen,&neww,&newh); ImageResize(&im,neww,newh); impixel=ImageCopy(im); ImageResize(&impixel,1,1); #if 1 if(neww>sidelen || newh>sidelen) fprintf(stderr,"elem:\"%s\" sidelen:%i old:%ix%i new:%ix%i\n",elem->name+1,sidelen,oldw,oldh,neww,newh); } #endif ImageDraw(&im2,impixel,(Rectangle) {0,0,1,1},(Rectangle) {0,0,sidelen,sidelen},(Color){255,255,255,255}); ImageDraw(&im2,im,(Rectangle) {0,0,neww,newh},(Rectangle) {(sidelen-neww)/2,(sidelen-newh)/2,neww,newh},(Color){255,255,255,255}); *te=LoadTextureFromImage(im2); UnloadImage(im); UnloadImage(im2); thumb->has_texture=1; } else { thumb->has_failedload=1; } } else if(bgload==NULL) { bg_add(body->bg,fullpath,0); } } if(thumb->has_texture!=0) { FILLWHXY(thumb->screenwhxy,whxy->w,whxy->h,whxy->x+xoff,whxy->y+yoff); DrawTexture(*te,thumb->screenwhxy.x,thumb->screenwhxy.y,WHITE); has_imagedrawn=1; lastx=whxy->x+whxy->w,lasty=whxy->y+whxy->h+yoff; if(is_leftside && mousedata->rmbdown==0 && is_global_insidewhxy(mousedata->mousepos,&(thumb->screenwhxy),margin) && mousedata->scrollspeed==0) { /* draw image in rightside */ char fullpath[2048]; int maxw,maxh; maxw=windowwidth-(body->leftsize-DEFAULTDIRDATATRIANGLEW); maxh=windowheight-body->whxy.y; snprintf(fullpath,sizeof(fullpath),"%s/%s/%s",body->rootdir,dirdata->dirname,elem->name+1); fullpath[sizeof(fullpath)-1]='\0'; if((body->texture.has_texture==0 && !(body->texture.has_failedload && strcmp(body->texture.currentpath,fullpath)==0)) || strcmp(body->texture.currentpath,fullpath)!=0 ) { texture_load(&(body->texture),fullpath,maxw,maxh,body->bg); } if(body->texture.has_texture && strcmp(body->texture.currentpath,fullpath)==0) { int x0,y0; x0=body->leftsize-DEFAULTDIRDATATRIANGLEW; y0=body->whxy.y; texture_draw(&(body->texture),x0,y0,maxw,maxh); body->is_displayingtexture=1; memcpy(&(body->texture.source),&(thumb->screenwhxy),sizeof(body->texture.source)); flag_skiprightside=1; } } } } if(has_imagedrawn==0) { char *ptr; char shortname[1024]; whxy_t *pos; int l; font_t *myfont=(is_leftside)?fonthuge:font; pos=is_leftside?&(elem->left.whxy):&(elem->right.whxy); FILLWHXY(thumb->screenwhxy,whxy->w,whxy->h,whxy->x+xoff,whxy->y+yoff); DrawRectangle(thumb->screenwhxy.x,thumb->screenwhxy.y,thumb->screenwhxy.w,thumb->screenwhxy.h,((Color){0,0,0,64})); if((ptr=strchr(elem->name+1,'.'))!=NULL) { m2=MeasureTextEx(myfont->font,ptr,myfont->height,0); DrawTextEx(myfont->font,ptr,(Vector2){whxy->x+xoff+(sidelen-m2.x)/2,whxy->y+yoff+(font->height)/2+(whxy->w-myfont->height)/2},myfont->height,0,(Color){ 0,0,0,96 }); } ptr=(ptr==NULL)?elem->name+1:ptr; l=(ptr-(elem->name+1)); l=(l>=sizeof(shortname))?sizeof(shortname)-1:l; memcpy(shortname,elem->name+1,l); shortname[l]='\0'; DrawRectangle(pos->x+xoff,pos->y+yoff,pos->w,font->height+font->height/2,((Color){0,0,0,64})); DrawTextEx(font->font,shortname,(Vector2){pos->x+xoff+font->height/4,pos->y+yoff+font->height/4},font->height,0,(Color){ 192,192,192,255 }); lastx=whxy->x+xoff+whxy->w,lasty=whxy->y+yoff+whxy->h; } /* show selected rectangle */ if(is_leftside && strcmp(body->selectedpath,elem->name)==0) { Color c=((Color){0,0,255,64}); DrawRectangle(thumb->screenwhxy.x,thumb->screenwhxy.y,thumb->screenwhxy.w,thumb->screenwhxy.h,c); c=((Color){0,0,255,255}); DrawRectangle(thumb->screenwhxy.x,thumb->screenwhxy.y,thumb->screenwhxy.w,2,c); DrawRectangle(thumb->screenwhxy.x,thumb->screenwhxy.y+2,2,thumb->screenwhxy.h-4,c); DrawRectangle(thumb->screenwhxy.x+thumb->screenwhxy.w-2,thumb->screenwhxy.y+2,2,thumb->screenwhxy.h-4,c); DrawRectangle(thumb->screenwhxy.x,thumb->screenwhxy.y+thumb->screenwhxy.h-2,thumb->screenwhxy.w,2,c); selectedthumb=thumb; } } if(imageundermouse[0]!='\0') bg_add(body->bg,imageundermouse,0); /* to prioritise loading this image */ for(;klisting.usedelems;k++) { elem=dirdata->listing.elems+k; if(elem->name[0]!='f' && elem->name[0]!='l') continue; thumb=(is_leftside)?&(elem->left):&(elem->right); FILLWHXY(thumb->screenwhxy,0,0,0,0); } /* ...finishing touchs */ if(is_leftside) { ; } else { if(i==body->currentdirdata) { /* draw right side "current" marker inside left side area */ DrawTriangle((Vector2){((float)body->whxy.x)+body->leftsize,((float)righty)}, (Vector2){((float)body->whxy.x)+body->leftsize-DEFAULTDIRDATATRIANGLEW,((float)righty)+dirdata->height/2}, (Vector2){((float)body->whxy.x)+body->leftsize,((float)righty)+dirdata->height-1}, (Color){ 168, 168, 168, 255 } ); } else if(body->selectedpath[0]!='\0' && mousedata->mousepos.x>body->leftsize && mousedata->mousepos.y>=righty && mousedata->mousepos.y<(righty+dirdata->height) && strcmp(body->dirdata[i]->dirname,body->dirdata[body->currentdirdata]->dirname)!=0) { whxy_t whxy; Color c=((Color){0,0,255,64}); FILLWHXY(whxy,body->whxy.w-body->leftsize,dirdata->height,body->leftsize,righty); DrawRectangle(whxy.x,whxy.y,whxy.w,whxy.h,c); c=((Color){0,0,255,255}); DrawRectangle(whxy.x,whxy.y,whxy.w,2,c); DrawRectangle(whxy.x,whxy.y+2,2,whxy.h-4,c); DrawRectangle(whxy.x+whxy.w-2,whxy.y+2,2,whxy.h-4,c); DrawRectangle(whxy.x,whxy.y+whxy.h-2,whxy.w,2,c); } /* advance to next element */ righty+=dirdata->height; } } } if(flag_skiprightside==0 && (righty+DEFAULTDIRDATAHEIGHT)<=(body->whxy.y+body->whxy.h)) { GlyphInfo gi; int xoff; int margin; margin=20; FILLWHXY(body->dirdataadd,(body->whxy.x+body->whxy.w-ADDREMOVEDIRDATAHEIGHT-margin),righty+margin,ADDREMOVEDIRDATAHEIGHT,ADDREMOVEDIRDATAHEIGHT); gi=GetGlyphInfo(body->roundedbox,'O'); xoff=0; DrawTexturePro(body->roundedbox.texture ,(Rectangle){0.0+xoff,0.0,(float)gi.image.width+5,(float)gi.image.height+2} ,(Rectangle) { (float) body->dirdataadd.x, (float) body->dirdataadd.y, (float) body->dirdataadd.w, (float)body->dirdataadd.h} ,(Vector2){0.0,0.0} ,0.0 ,(Color){ 168, 168, 168, 255 } ); DrawRectangle(body->dirdataadd.x+13+12,body->dirdataadd.y+13,body->dirdataadd.w-26-24, (float)body->dirdataadd.h-26,(Color){ 168, 168, 168, 255 }); DrawRectangle(body->dirdataadd.x+13,body->dirdataadd.y+13+12,body->dirdataadd.w-26, (float)body->dirdataadd.h-26-24,(Color){ 168, 168, 168, 255 }); xoff+=gi.image.width+4; gi=GetGlyphInfo(body->roundedbox,'+'); DrawTexturePro(body->roundedbox.texture ,(Rectangle){xoff,0.0,(float)gi.image.width,(float)gi.image.height} ,(Rectangle) { (float) body->dirdataadd.x+30-2, (float) body->dirdataadd.y+30, (float) body->dirdataadd.w-60, (float)body->dirdataadd.h-60} ,(Vector2){0.0,0.0} ,0.0 ,(Color){ 227, 227, 227, 255 } ); } else { memset(&(body->dirdataadd),0,sizeof(body->dirdataadd)); } /* if moving elem, show line from orig to mousedata->mousepos */ if(body->selectedpath[0]!='\0' && selectedthumb!=NULL) { Color c=((Color){0,0,255,255}); DrawLineEx((Vector2){(float)(selectedthumb->screenwhxy.x+selectedthumb->screenwhxy.w/2),(float)(selectedthumb->screenwhxy.y+selectedthumb->screenwhxy.h/2)},mousedata->mousepos,2.0,c); } /* show tooltip */ if(statustooltip[0]!='\0') { m2=MeasureTextEx(font->font,statustooltip,font->height,0); DrawRectangle(0,windowheight-1-margin*2-font->height,m2.x+margin*2,font->height+margin*2,((Color){0,0,0,96})); DrawTextEx(font->font,statustooltip,(Vector2){margin,windowheight-1-margin-font->height},font->height,0,(Color){ 255,255,255,128 }); } /* free not used bg load items (only if idle, as it takes time) */ if(mousedata->scrollspeed==0 && *needs_nextredraw==0) bg_freeunmarked(body->bg); return(0); } static int strptrcmp(void *a,void *b) { return(strcmp(((listingdata_t *)a)->name,((listingdata_t *)b)->name)); } #ifdef MYFUNC #undef MYFUNC #define MYFUNC "listing_get" #endif int listing_get(listing_t *listing, char *pathprefix, char *parampath, int flag_sort) { int i,l; DIR *d; struct dirent *de; unsigned char dtype; char path[1024]; listingdata_t *ld; if(listing==NULL) return(-1); /* sanity check failed */ /* free old textures */ for(i=0;iusedelems;i++) { ld=listing->elems+i; if(ld->left.has_texture) { UnloadTexture(ld->left.texture); ld->left.has_texture=0; ld->left.has_failedload=0; } if(ld->right.has_texture) { UnloadTexture(ld->right.texture); ld->right.has_texture=0; ld->right.has_failedload=0; } } /* reset struct */ listing->usedelems=listing->usedbuf=0; memset(listing->elems,0,sizeof(listingdata_t)*listing->sizeelems); listing->has_leftwhxy=listing->has_rightwhxy=0; /* fill listing */ if(pathprefix==NULL && parampath==NULL) return(-1); /* nothing to fill */ snprintf(path,sizeof(path),"%s%c%s",(pathprefix!=NULL)?pathprefix:"",SEP,(parampath!=NULL)?parampath:""); path[sizeof(path)-1]='\0'; if((d=opendir(path))==NULL) return(-1); /* dir not found */ while((de=readdir(d))!=NULL) { l=strlen(de->d_name); dtype='u'; #ifdef _DIRENT_HAVE_D_TYPE dtype=(de->d_type==DT_BLK)?'b' :(de->d_type==DT_CHR)?'c' :(de->d_type==DT_DIR)?'d' :(de->d_type==DT_FIFO)?'p' :(de->d_type==DT_LNK)?'l' :(de->d_type==DT_REG)?'f' :(de->d_type==DT_SOCK)?'s' :'u'; #endif if(dtype=='u') { char stpath[2048]; struct stat st; mode_t m; snprintf(stpath,sizeof(stpath),"%s%c%s",path,SEP,de->d_name); stpath[sizeof(stpath)-1]='\0'; if(stat(stpath,&st)==0 && (m=(st.st_mode&S_IFMT))!=0) { dtype=(m==S_IFBLK)?'b' :(m==S_IFCHR)?'c' :(m==S_IFDIR)?'d' :(m==S_IFIFO)?'p' #ifdef S_IFLNK :(m==S_IFLNK)?'l' #endif :(m==S_IFREG)?'f' #ifdef S_IFSOCK :(m==S_IFSOCK)?'s' #endif :'u'; } } /* check for space for this elem (and get space if necessary) */ if(listing->usedelems==listing->sizeelems) { listingdata_t *newelems; if((newelems=realloc(listing->elems,sizeof(listingdata_t)*(listing->sizeelems+BLOCKLISTINGELEMS)))==NULL) { closedir(d),d=NULL; return(-1); /* insuf. mem. */ } listing->elems=newelems; memset(listing->elems+listing->sizeelems,0,sizeof(listingdata_t)*BLOCKLISTINGELEMS); listing->sizeelems+=BLOCKLISTINGELEMS; } /* check for space for this elem data (and get space if necessary) */ if((listing->sizebuf+l+2)>listing->sizebuf) { int i; char *newbuf; int newsize; int off; newsize=listing->sizebuf+l+2+BLOCKLISTINGBUF-1; newsize/=BLOCKLISTINGBUF; newsize*=BLOCKLISTINGBUF; if((newbuf=realloc(listing->buf,newsize))==NULL) { closedir(d),d=NULL; return(-1); /* insuf. mem. */ } /* the elem data buffer has a new pointer, fix previous entries */ for(i=0;iusedelems;i++) { off=(listing->elems[i].name)-listing->buf; listing->elems[i].name=newbuf+off; } listing->buf=newbuf; listing->sizebuf+=BLOCKLISTINGELEMS; } /* store the data */ listing->elems[listing->usedelems++].name=listing->buf+listing->usedbuf; listing->buf[listing->usedbuf++]=dtype; memcpy(listing->buf+listing->usedbuf,de->d_name,l+1); IMDEBUG(listing->buf+listing->usedbuf); listing->usedbuf+=l+1; } closedir(d),d=NULL; if(flag_sort) qsort(listing->elems,listing->usedelems,sizeof(listingdata_t ),(int (*)(const void *, const void *)) strptrcmp); return(0); } void listing_freedata(listing_t *listing) { if(listing==NULL) return; /* nothing to do */ if(listing->elems!=NULL) { int i; listingdata_t *ld; for(i=0;iusedelems;i++) { ld=listing->elems+i; if(ld->left.has_texture) { UnloadTexture(ld->left.texture); ld->left.has_texture=0; ld->left.has_failedload=0; } if(ld->right.has_texture) { UnloadTexture(ld->right.texture); ld->right.has_texture=0; ld->right.has_failedload=0; } } free(listing->elems),listing->elems=NULL,listing->sizeelems=listing->usedelems=0; } if(listing->buf!=NULL) free(listing->buf),listing->buf=NULL,listing->sizebuf=listing->usedbuf=0; return; } int listing_fillwhxy(listing_t *listing, font_t *font, int w, int sidelen, int is_leftside, int rightsidemargin) { int x0,y0,x1; int k,x,y; Vector2 m2; int margin; listingdata_t *elem; thumb_t *thumb; if(listing==NULL || font==NULL) return(-1); /* sanity check failed */ margin=font->height/4; if(is_leftside) memset(&(listing->lastleftwhxy),0,sizeof(listing->lastleftwhxy)); /* directories */ if(is_leftside) { x0=font->height/2; x1=w-DEFAULTDIRDATATRIANGLEW-font->height/2; y0=0; } else { x0=rightsidemargin; x1=w-font->height/2; y0=0; } for(k=0,x=x0,y=y0;kusedelems;k++) { elem=listing->elems+k; thumb=(is_leftside)?&(elem->left):&(elem->right); if(elem->name[0]!='d' || strcmp(elem->name,"d.")==0 || strcmp(elem->name,"d..")==0) continue; m2=MeasureTextEx(font->font,elem->name+1,font->height,0); if((x+margin*2+m2.x)>x1 && !(is_leftside==0 && y>y0)) x=x0,y+=font->height+margin*2+font->height/4; if(is_leftside==0 && y>y0) { FILLWHXY(thumb->whxy,0,0,0,0); continue; } FILLWHXY(thumb->whxy,margin*2+m2.x,margin*2+font->height,x,y); if(is_leftside && (thumb->whxy.y+thumb->whxy.h)>(listing->lastleftwhxy.y+listing->lastleftwhxy.h)) memcpy(&(listing->lastleftwhxy),&(thumb->whxy),sizeof(whxy_t)); x+=margin*2+m2.x+font->height/4; } y+=((x==x0)?0:font->height+margin*2+font->height/4); /* files */ if(is_leftside) y0=y; else y0+=margin*2+font->height+margin; for(k=0,x=x0,y=y0;kusedelems;k++) { elem=listing->elems+k; thumb=(is_leftside)?&(elem->left):&(elem->right); if(elem->name[0]!='f' && elem->name[0]!='l') continue; if(!is_leftside && y>y0) { FILLWHXY(thumb->whxy,0,0,0,0); continue; } if((x+margin*2+sidelen)>x1 && !(is_leftside==0 && y>y0)) x=x0,y+=sidelen+margin*2; if(is_leftside==0 && y>y0) { FILLWHXY(thumb->whxy,0,0,0,0); continue; } FILLWHXY(thumb->whxy,sidelen,sidelen,x,y); if(is_leftside && (thumb->whxy.y+thumb->whxy.h)>(listing->lastleftwhxy.y+listing->lastleftwhxy.h)) memcpy(&(listing->lastleftwhxy),&(thumb->whxy),sizeof(whxy_t)); x+=margin*2+sidelen; } return(0); } int is_imagefilename(char *filename) { char *ptr; int i; char *knownext[]={".jpg",".jpeg",".JPG",".JPEG",".Jpg",".Jpeg" ,".png",".PNG",".Png" ,".tga",".TGA",".Tga" ,".bmp",".BMP",".Bmp" ,".psd",".PSD",".Psd" ,".gif",".GIF",".Gif" ,".hdr",".HDR",".Hdr" ,".pic",".PIC",".Pic" ,".pnm",".PNM",".Pnm" }; if(filename==NULL) return(0); /* sanity check failed */ if((ptr=strrchr(filename,'.'))==NULL) return(0); /* no extension found */ for(i=0;i<(sizeof(knownext)/sizeof(knownext[0]));i++) { if(strcmp(ptr,knownext[i])==0) return(1); /* it has a known ext */ } return(0); /* not in the knownext list */ } int texture_load(texture_t *texture, char *fullpath, int maxw, int maxh, bg_t *bg) { Image im; int neww,newh; bgload_t *bgload; if(texture==NULL || fullpath==NULL) return(-1); /* sanity check failed */ if(texture->has_texture) { UnloadTexture(texture->texture); texture->currentpath[0]='\0'; texture->has_texture=0; texture->has_failedload=0; } if(bg!=NULL && (bgload=bg_get(bg,texture->currentpath))!=NULL && bgload->has_data!=0) { im=ImageCopy(bgload->image); } else { #if 0 #warning TEST CODE return(-1); /* if not loaded in background, return -1 to indicate "not ready" */ #else im=global_loadimage(fullpath); #endif } if(IsImageValid(im)) { imutil_aspectmaximize(im.width,im.height,maxw,maxh,&neww,&newh); ImageResize(&im,neww,newh); texture->texture=LoadTextureFromImage(im); UnloadImage(im); strncpy(texture->currentpath,fullpath,sizeof(texture->currentpath)); texture->currentpath[sizeof(texture->currentpath)-1]='\0'; texture->has_texture=1; texture->has_failedload=0; texture->texturew=neww; texture->textureh=newh; } else { strncpy(texture->currentpath,fullpath,sizeof(texture->currentpath)); texture->currentpath[sizeof(texture->currentpath)-1]='\0'; texture->has_texture=0; texture->has_failedload=1; } return(0); } int texture_draw(texture_t *texture, int x0, int y0, int maxw, int maxh) { if(texture==NULL || texture->has_texture==0) return(-1); /* sanity check failed */ DrawRectangle(x0,y0,maxw,maxh,(Color){ 215, 215, 215, 255 } ); DrawTexture(texture->texture,x0+(maxw-texture->texturew)/2,y0+(maxh-texture->textureh)/2,WHITE); return(0); } int texture_freedata(texture_t *texture) { if(texture==NULL) return(-1); /* sanity check failed */ if(texture->has_texture) { UnloadTexture(texture->texture); texture->currentpath[0]='\0'; texture->has_texture=0; texture->has_failedload=0; } return(0); } int imutil_aspectmaximize(int w, int h, int maxw, int maxh, int *neww, int *newh) { if(neww==NULL || newh==NULL || w==0 || h==0 || maxw==0 || maxh==0) return(-1); if((w/h)>(maxw/maxh) || (maxw==maxh && w>h)) { *neww=maxw; *newh=h*maxw/w; } else { /* (w/h)<=(maxw/maxh) */ *newh=maxh; *neww=w*maxh/h; } return(0); }