Index: picedit.c ================================================================== --- picedit.c +++ picedit.c @@ -77,10 +77,18 @@ if(st) sqlite3_finalize(st); if(fp) fclose(fp); free(nam); free(buf); fprintf(stderr,"Done\n"); + sqlite3_exec(userdb, + "CREATE TRIGGER `PICEDIT_T1` BEFORE INSERT ON `PICEDIT` BEGIN" + " SELECT RAISE(FAIL,'Duplicate name') FROM `PICEDIT` WHERE `NAME`=NEW.`NAME`;" + "END;" + "CREATE TRIGGER `PICEDIT_T2` BEFORE UPDATE OF `NAME` ON `PICEDIT` BEGIN" + " SELECT RAISE(FAIL,'Duplicate name') FROM `PICEDIT` WHERE `NAME`=NEW.`NAME`;" + "END;" + ,0,0,0); return r; } static void save_picture_file(void) { sqlite3_stmt*st; @@ -186,10 +194,32 @@ if(m&1) x=s-x-1; if(m&2) y=s-y-1; } memcpy(d,buf,s*s); } + +static void block_rotate(Uint8*d,Uint8 s,Uint8 w,Uint8 h,Uint8 m) { + Uint8*b=malloc(w*h); + Uint8*p=b; + int x,y; + if(!b) fatal("Allocation failed\n"); + if(w!=h && (m&4)) goto end; + for(y=0;ydata+(m.y+1)*pict[sel]->size+m.x; for(y=0;ysize; goto redraw; + case SDLK_F1: + if(!m.w) m.w=m.h=pict[sel]->size; + block_rotate(pict[sel]->data+(m.y+1)*pict[sel]->size+m.x,pict[sel]->size,m.w,m.h,5); + goto redraw; + case SDLK_F2: + if(!m.w) m.w=m.h=pict[sel]->size; + block_rotate(pict[sel]->data+(m.y+1)*pict[sel]->size+m.x,pict[sel]->size,m.w,m.h,6); + goto redraw; + case SDLK_F3: + if(!m.w) m.w=m.h=pict[sel]->size; + block_rotate(pict[sel]->data+(m.y+1)*pict[sel]->size+m.x,pict[sel]->size,m.w,m.h,2); + goto redraw; + case SDLK_F4: + if(!m.w) m.w=m.h=pict[sel]->size; + block_rotate(pict[sel]->data+(m.y+1)*pict[sel]->size+m.x,pict[sel]->size,m.w,m.h,1); + goto redraw; case SDLK_F5: resize: m.x=m.y=m.w=m.h=0; xx=yy=-1; p=(Uint8*)screen_prompt("Size? (1 to 255, or P to paste)"); if(!p || !*p) goto redraw; if(*p=='p' || *p=='P') { @@ -590,11 +636,11 @@ pict[sel]->size=i; if(*p=='p' || *p=='P') memcpy(pict[sel]->data,pclip->data,(i+1)*i); else memset(pict[sel]->data,0,(i+1)*i); goto redraw; case SDLK_F6: - if(pict[15]) break; + if(pict[14]) break; for(sel=0;sel<15;sel++) if(!pict[sel]) break; goto resize; case SDLK_F7: if(!sel && !pict[1]) break; free(pict[sel]); @@ -654,10 +700,49 @@ free(pict[i]); } } + +static int add_picture(int t) { + sqlite3_stmt*st; + const char*s=screen_prompt("Enter name of new picture:"); + int i; + if(!s || !*s) return 0; + if(sqlite3_prepare_v2(userdb,"INSERT INTO `PICEDIT`(`NAME`,`TYPE`,`DATA`) SELECT REPLACE(?1||'.IMG','.IMG.IMG','.IMG'),1,X'';",-1,&st,0)) { + screen_message(sqlite3_errmsg(userdb)); + return 0; + } + sqlite3_bind_text(st,1,s,-1,0); + i=sqlite3_step(st); + sqlite3_finalize(st); + if(i!=SQLITE_DONE) { + screen_message(sqlite3_errmsg(userdb)); + return 0; + } + edit_picture(sqlite3_last_insert_rowid(userdb)); + return 1; +} + +static int delete_picture(void) { + sqlite3_stmt*st; + const char*s=screen_prompt("Enter name of picture to delete:"); + int i; + if(!s || !*s) return 0; + if(sqlite3_prepare_v2(userdb,"DELETE FROM `PICEDIT` WHERE `NAME`=REPLACE(?1||'.IMG','.IMG.IMG','.IMG');",-1,&st,0)) { + screen_message(sqlite3_errmsg(userdb)); + return 0; + } + sqlite3_bind_text(st,1,s,-1,0); + i=sqlite3_step(st); + sqlite3_finalize(st); + if(i!=SQLITE_DONE) { + screen_message(sqlite3_errmsg(userdb)); + return 0; + } + return 1; +} static void set_caption(void) { char buf[256]; snprintf(buf,255,"Free Hero Mesh - %s - Picture",basefilename); SDL_WM_SetCaption(buf,buf); @@ -719,10 +804,17 @@ case SDLK_UP: case SDLK_KP8: if(sc) --sc; goto redraw; case SDLK_DOWN: case SDLK_KP2: ++sc; goto redraw; case SDLK_END: case SDLK_KP1: sc=max-screen->h/8+1; goto redraw; case SDLK_PAGEUP: case SDLK_KP9: sc-=screen->h/8-1; goto redraw; case SDLK_PAGEDOWN: case SDLK_KP3: sc+=screen->h/8-1; goto redraw; + case SDLK_F1: + if(max<65535) max+=add_picture(1); + else screen_message("Too many pictures"); + goto redraw; + case SDLK_F2: + max-=delete_picture(); + goto redraw; case SDLK_F3: *ids=ask_picture_id("Edit:"); if(*ids) edit_picture(*ids); goto redraw; } Index: picedit.doc ================================================================== --- picedit.doc +++ picedit.doc @@ -2,10 +2,18 @@ To start the picture editor, use the -p switch. In this case, the puzzle set files are not required to exist; the .xclass file will be created if necessary, and the other ones are ignored. +This allows creating the graphics for the classes of objects in the puzzle +set. The class definition file will associate one or more pictures with +each class, using the names given in the picture file. + +Each named picture can have up to fifteen variants. Only one variant is +used; which one is used depends on the .altImage and .imageSize settings, +which can be defined by the end user. + === Main menu === The main menu displays the list of the names of all pictures. This list is sorted by name. @@ -54,10 +62,24 @@ Allows selecting a colour without using the mouse. Home Selects transparency as the current colour. +F1 + Rotate marked area clockwise by 90 degrees. The marked area must be + square in order for this to work. + +F2 + Rotate marked area counterclockwise by 90 degrees. The marked area must + be square in order for this to work. + +F3 + Flip marked area verticaly. + +F4 + Flip marked area horizontally. + F5 Resizes the current image variant. It will ask for the size; enter a number from 1 to 255 to set the size (which is always square), and then it will resize and clear the image. If you enter P then it will become a copy of the contents of the clipboard; this won't work if the contents @@ -64,11 +86,11 @@ of the clipboard is not square. F6 Add a new image variant. It will ask for the size, like with F5, except this adds a new one rather than replacing the existing one. The maximum - number of image variants is sixteen. + number of image variants is fifteen. F7 Delete the current image variant. You cannot delete all of the variants of an image; you must have at least one.