From b42bd0afad3b5b48b8fb5a7a0b5675bb285fce7e Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Sun, 13 Feb 2011 21:08:41 +0000 Subject: [PATCH 1/9] Create branch for CPC Mode 5 drawing git-svn-id: svn://pulkomandy.tk/GrafX2/branches/cpcmode5@1717 416bcca6-2ee7-4201-b75f-2eb2f807beb1 From 4e60f5ad7470bbb7ffc718a84845d4d66a87c4b8 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Sun, 13 Feb 2011 21:20:45 +0000 Subject: [PATCH 2/9] Import the WIP CPC-Mode5 code from the sourcearchive git-svn-id: svn://pulkomandy.tk/GrafX2/branches/cpcmode5@1718 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- src/Makefile | 9 +- src/brush.c | 109 ++++++++++- src/buttons_effects.c | 2 +- src/const.h | 4 +- src/engine.c | 4 + src/graph.c | 68 ++++++- src/graph.h | 1 + src/help.c | 6 +- src/helpfile.h | 6 + src/hotkeys.c | 10 + src/loadsave.c | 7 +- src/misc.c | 22 +++ src/misc.h | 3 + src/miscfileformats.c | 435 ++++++++++++++++++++++++++++++++---------- src/oldies.c | 411 +++++++++++++++++++++++++++++++++++++++ src/oldies.h | 24 +++ src/pages.c | 54 ++++-- src/struct.h | 10 +- 18 files changed, 1031 insertions(+), 154 deletions(-) create mode 100644 src/oldies.c create mode 100644 src/oldies.h diff --git a/src/Makefile b/src/Makefile index ee8fe8a0..fb0c92d5 100644 --- a/src/Makefile +++ b/src/Makefile @@ -152,9 +152,8 @@ else RMDIR = rmdir CP = cp BIN = ../bin/grafx2 - PLATFORMOBJ = $(OBJDIR)/haiku.o COPT = -W -Wall -c -g `sdl-config --cflags` $(TTFCOPT) -I/boot/common/include - LOPT = `sdl-config --libs` -lSDL_image -lpng -ljpeg -lz $(TTFLOPT) -lfreetype -lbe + LOPT = `sdl-config --libs` -lSDL_image -lpng -ljpeg -lz $(TTFLOPT) CC = gcc OBJDIR = ../obj/haiku ZIP = zip @@ -303,7 +302,7 @@ endif .PHONY : all debug release clean depend zip version force install uninstall # This is the list of the objects we want to build. Dependancies are built by "make depend" automatically. -OBJ = $(OBJDIR)/main.o $(OBJDIR)/init.o $(OBJDIR)/graph.o $(OBJDIR)/sdlscreen.o $(OBJDIR)/misc.o $(OBJDIR)/special.o $(OBJDIR)/buttons.o $(OBJDIR)/palette.o $(OBJDIR)/help.o $(OBJDIR)/operatio.o $(OBJDIR)/pages.o $(OBJDIR)/loadsave.o $(OBJDIR)/readline.o $(OBJDIR)/engine.o $(OBJDIR)/filesel.o $(OBJDIR)/op_c.o $(OBJDIR)/readini.o $(OBJDIR)/saveini.o $(OBJDIR)/shade.o $(OBJDIR)/keyboard.o $(OBJDIR)/io.o $(OBJDIR)/version.o $(OBJDIR)/text.o $(OBJDIR)/SFont.o $(OBJDIR)/setup.o $(OBJDIR)/pxsimple.o $(OBJDIR)/pxtall.o $(OBJDIR)/pxwide.o $(OBJDIR)/pxdouble.o $(OBJDIR)/pxtriple.o $(OBJDIR)/pxtall2.o $(OBJDIR)/pxwide2.o $(OBJDIR)/pxquad.o $(OBJDIR)/windows.o $(OBJDIR)/brush.o $(OBJDIR)/realpath.o $(OBJDIR)/mountlist.o $(OBJDIR)/input.o $(OBJDIR)/hotkeys.o $(OBJDIR)/transform.o $(OBJDIR)/pversion.o $(OBJDIR)/factory.o $(PLATFORMOBJ) $(OBJDIR)/fileformats.o $(OBJDIR)/miscfileformats.o $(OBJDIR)/libraw2crtc.o $(OBJDIR)/brush_ops.o $(OBJDIR)/buttons_effects.o $(OBJDIR)/layers.o +OBJ = $(OBJDIR)/main.o $(OBJDIR)/init.o $(OBJDIR)/graph.o $(OBJDIR)/sdlscreen.o $(OBJDIR)/misc.o $(OBJDIR)/special.o $(OBJDIR)/buttons.o $(OBJDIR)/palette.o $(OBJDIR)/help.o $(OBJDIR)/operatio.o $(OBJDIR)/pages.o $(OBJDIR)/loadsave.o $(OBJDIR)/readline.o $(OBJDIR)/engine.o $(OBJDIR)/filesel.o $(OBJDIR)/op_c.o $(OBJDIR)/readini.o $(OBJDIR)/saveini.o $(OBJDIR)/shade.o $(OBJDIR)/keyboard.o $(OBJDIR)/io.o $(OBJDIR)/version.o $(OBJDIR)/text.o $(OBJDIR)/SFont.o $(OBJDIR)/setup.o $(OBJDIR)/pxsimple.o $(OBJDIR)/pxtall.o $(OBJDIR)/pxwide.o $(OBJDIR)/pxdouble.o $(OBJDIR)/pxtriple.o $(OBJDIR)/pxtall2.o $(OBJDIR)/pxwide2.o $(OBJDIR)/pxquad.o $(OBJDIR)/windows.o $(OBJDIR)/brush.o $(OBJDIR)/realpath.o $(OBJDIR)/mountlist.o $(OBJDIR)/input.o $(OBJDIR)/hotkeys.o $(OBJDIR)/transform.o $(OBJDIR)/pversion.o $(OBJDIR)/factory.o $(PLATFORMOBJ) $(OBJDIR)/fileformats.o $(OBJDIR)/miscfileformats.o $(OBJDIR)/libraw2crtc.o $(OBJDIR)/brush_ops.o $(OBJDIR)/buttons_effects.o $(OBJDIR)/layers.o $(OBJDIR)/oldies.o SKIN_FILES = ../share/grafx2/skins/skin_classic.png ../share/grafx2/skins/skin_modern.png ../share/grafx2/skins/skin_DPaint.png ../share/grafx2/skins/font_Classic.png ../share/grafx2/skins/font_Fun.png ../share/grafx2/skins/font_Fairlight.png ../share/grafx2/skins/font_Melon.png ../share/grafx2/skins/font_DPaint.png ../share/grafx2/skins/skin_scenish.png ../share/grafx2/skins/font_Seen.png @@ -388,10 +387,6 @@ depend : $(OBJDIR)/winres.o : gfx2.ico echo "1 ICON \"gfx2.ico\"" | $(WINDRES) -o $(OBJDIR)/winres.o -# Compile the C++ file needed in Haiku to use the API -$(OBJDIR)/haiku.o : haiku.cpp - g++ -c haiku.cpp -o $(OBJDIR)/haiku.o - clean : $(DELCOMMAND) $(OBJ) $(DELCOMMAND) $(BIN) diff --git a/src/brush.c b/src/brush.c index 63014847..de28b7fd 100644 --- a/src/brush.c +++ b/src/brush.c @@ -125,14 +125,119 @@ void Display_paintbrush(short x,short y,byte color,byte is_preview) byte temp_color; // color de la brosse en cours d'affichage int position; byte * temp; + byte old_color; - if (is_preview==0 || Mouse_K==0) // pas de curseur si on est en preview et - // en train de cliquer + if (is_preview && Mouse_K) // pas de curseur si on est en preview et + return; // en train de cliquer + + if (Main_current_layer < 4) + { + if (is_preview) + goto single_pixel; + else + { + // Flood-fill the enclosing area + if (x= 0 && y >= 0 + && (color=Effect_function(x,y,color)) != (old_color=Read_pixel_from_current_layer(x,y)) + && (!((Stencil_mode) && (Stencil[old_color]))) + && (!((Mask_mode) && (Mask_table[Read_pixel_from_spare_screen(x,y)]))) + ) + { + short min_x,width,min_y,height; + short xx,yy; + + // determine area + switch(Main_current_layer) + { + case 0: + default: + // Full layer + min_x=0; + min_y=0; + width=Main_image_width; + height=Main_image_height; + break; + case 1: + case 2: + // Line + min_x=0; + min_y=y; + width=Main_image_width; + height=1; + break; + case 3: + // Segment + min_x=x / 48 * 48; + min_y=y; + width=48; + height=1; + break; + //case 4: + // // 8x8 + // min_x=x / 8 * 8; + // min_y=y / 8 * 8; + // width=8; + // height=8; + // break; + } + // Clip the bottom edge. + // (Necessary if image height is not a multiple) + if (min_y+height>=Main_image_height) + height=Main_image_height-min_y; + // Clip the right edge. + // (Necessary if image width is not a multiple) + if (min_x+width>=Main_image_width) + width=Main_image_width-min_x; + + for (yy=min_y; yy0) && (height>0) ) + Clear_brush(min_x-Main_offset_X, + min_y-Main_offset_Y, + 0,0, + width,height,0, + Main_image_width); + + if (Main_magnifier_mode != 0) + { + Compute_clipped_dimensions_zoom(&min_x,&min_y,&width,&height); + xx=min_x; + yy=min_y; + + if ( (width>0) && (height>0) ) + { + // Corrections dues au Zoom: + min_x=(min_x-Main_magnifier_offset_X)*Main_magnifier_factor; + min_y=(min_y-Main_magnifier_offset_Y)*Main_magnifier_factor; + height=min_y+(height*Main_magnifier_factor); + if (height>Menu_Y) + height=Menu_Y; + + Clear_brush_scaled(Main_X_zoom+min_x,min_y, + xx,yy, + width,height,0, + Main_image_width, + Horizontal_line_buffer); + } + } + // End of graphic feedback + } + } + return; + } switch (Paintbrush_shape) { case PAINTBRUSH_SHAPE_NONE : // No paintbrush. for colorpicker for example break; case PAINTBRUSH_SHAPE_POINT : // !!! TOUJOURS EN PREVIEW !!! + single_pixel: if ( (Paintbrush_X>=Limit_left) && (Paintbrush_X<=Limit_right) && (Paintbrush_Y>=Limit_top) diff --git a/src/buttons_effects.c b/src/buttons_effects.c index eb62b93d..c76d1190 100644 --- a/src/buttons_effects.c +++ b/src/buttons_effects.c @@ -546,7 +546,7 @@ void Button_Colorize_mode(void) switch(Colorize_current_mode) { case 0 : - Effect_function=Effect_interpolated_colorize; + Effect_function=Effect_layer_copy; break; case 1 : Effect_function=Effect_additive_colorize; diff --git a/src/const.h b/src/const.h index 5b146183..e4c60590 100644 --- a/src/const.h +++ b/src/const.h @@ -37,7 +37,7 @@ #define BETA1 98 ///< Version number for gfx2.cfg (3/4) #define BETA2 0 ///< Version number for gfx2.cfg (4/4) #define MAX_VIDEO_MODES 100 ///< Maximum number of video modes Grafx2 can propose. -#define NB_SHORTCUTS 181 ///< Number of actions that can have a key combination associated to it. +#define NB_SHORTCUTS 183 ///< Number of actions that can have a key combination associated to it. #define NB_ZOOM_FACTORS 15 ///< Number of zoom levels available in the magnifier. #define MENU_WIDTH 254 ///< Width of the menu (not counting the palette) #define MENU_HEIGHT 44 ///< Height of the menu. @@ -435,6 +435,8 @@ enum SPECIAL_ACTIONS SPECIAL_LAYER7_TOGGLE, SPECIAL_LAYER8_SELECT, SPECIAL_LAYER8_TOGGLE, + SPECIAL_FORMAT_CHECKER, + SPECIAL_FORMAT_CHECKER_MENU, NB_SPECIAL_SHORTCUTS ///< Number of special shortcuts }; diff --git a/src/engine.c b/src/engine.c index 7a4dcea7..514d4ea8 100644 --- a/src/engine.c +++ b/src/engine.c @@ -1084,6 +1084,10 @@ void Main_handler(void) Layer_activate((key_index-SPECIAL_LAYER1_TOGGLE)/2, RIGHT_SIDE); action++; break; + case SPECIAL_FORMAT_CHECKER: + C64_FLI_enforcer(); + action++; + break; } } } // End of special keys diff --git a/src/graph.c b/src/graph.c index 06c78114..c393ebc0 100644 --- a/src/graph.c +++ b/src/graph.c @@ -2853,6 +2853,15 @@ byte Effect_smooth(word x,word y,__attribute__((unused)) byte color) // l'écran feedback car il s'agit de ne } // pas modifier l'écran courant. +byte Effect_layer_copy(word x,word y,byte color) +{ + if (colorPages->Nb_layers) + { + return *((y)*Main_image_width+(x)+Main_backups->Pages->Image[color]); + } + return Read_pixel_from_feedback_screen(x,y); +} + void Horizontal_grid_line(word x_pos,word y_pos,word width) { int x; @@ -2896,6 +2905,10 @@ byte Read_pixel_from_current_screen (word x,word y) #ifndef NOLAYERS byte depth; byte color; + + if (Main_current_layer==4) + return *(Main_backups->Pages->Image[Main_current_layer] + x+y*Main_image_width); + color = *(Main_screen+y*Main_image_width+x); if (color != Main_backups->Pages->Transparent_color) // transparent color return color; @@ -2909,9 +2922,48 @@ byte Read_pixel_from_current_screen (word x,word y) void Pixel_in_current_screen (word x,word y,byte color,int with_preview) { - #ifndef NOLAYERS - byte depth = *(Main_visible_image_depth_buffer.Image+x+y*Main_image_width); + #ifndef NOLAYERS + if ( Main_current_layer == 4) + { + if (color<4) + { + // Paste in layer + *(Main_backups->Pages->Image[Main_current_layer] + x+y*Main_image_width)=color; + // Paste in depth buffer + *(Main_visible_image_depth_buffer.Image+x+y*Main_image_width)=color; + // Fetch pixel color from the target raster layer + color=*(Main_backups->Pages->Image[color] + x+y*Main_image_width); + // Draw that color on the visible image buffer + *(x+y*Main_image_width+Main_screen)=color; + + if (with_preview) + Pixel_preview(x,y,color); + } + } + else if (Main_current_layer<4 && (Main_layers_visible & (1<<4))) + { + byte depth; + + // Paste in layer *(Main_backups->Pages->Image[Main_current_layer] + x+y*Main_image_width)=color; + // Search depth + depth = *(Main_backups->Pages->Image[4] + x+y*Main_image_width); + + if ( depth == Main_current_layer) + { + // Draw that color on the visible image buffer + *(x+y*Main_image_width+Main_screen)=color; + + if (with_preview) + Pixel_preview(x,y,color); + } + } + else + { + byte depth; + + *(Main_backups->Pages->Image[Main_current_layer] + x+y*Main_image_width)=color; + depth = *(Main_visible_image_depth_buffer.Image+x+y*Main_image_width); if ( depth <= Main_current_layer) { if (color == Main_backups->Pages->Transparent_color) // transparent color @@ -2923,13 +2975,15 @@ void Pixel_in_current_screen (word x,word y,byte color,int with_preview) if (with_preview) Pixel_preview(x,y,color); } - #else - *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer])=color; - if (with_preview) - Pixel_preview(x,y,color); - #endif + } + #else + *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer])=color; + if (with_preview) + Pixel_preview(x,y,color); + #endif } + void Pixel_in_current_layer(word x,word y, byte color) { *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer])=color; diff --git a/src/graph.h b/src/graph.h index 34a6f634..27724c5f 100644 --- a/src/graph.h +++ b/src/graph.h @@ -38,6 +38,7 @@ byte Effect_shade(word x,word y,byte color); byte Effect_quick_shade(word x,word y,byte color); byte Effect_tiling(word x,word y,byte color); byte Effect_smooth(word x,word y,byte color); +byte Effect_layer_copy(word x,word y,byte color); void Display_foreback(void); diff --git a/src/help.c b/src/help.c index 1fee8884..9fcf976e 100644 --- a/src/help.c +++ b/src/help.c @@ -31,8 +31,6 @@ #include #elif defined (__linux__) #include -#elif defined(__HAIKU__) - #include "haiku.h" #endif #include "const.h" @@ -64,7 +62,7 @@ word * Shortcut(word shortcut_number) return &(Config_Key[shortcut_number & 0xFF][0]); } -// Nom de la touche actuallement assignée à un raccourci d'après son numéro +// Nom de la touche actuallement assignée à un raccourci d'après son numéro // de type 0x100+BOUTON_* ou SPECIAL_* const char * Keyboard_shortcut_value(word shortcut_number) { @@ -672,8 +670,6 @@ void Button_Stats(void) statfs(Main_current_directory,&disk_info); mem_size=(qword) disk_info.f_bfree * (qword) disk_info.f_bsize; } -#elif defined(__HAIKU__) - mem_size = haiku_get_free_space(Main_current_directory); #else // Free disk space is only for shows. Other platforms can display 0. #warning "Missing code for your platform !!! Check and correct please :)" diff --git a/src/helpfile.h b/src/helpfile.h index 0351dc6d..5e246059 100644 --- a/src/helpfile.h +++ b/src/helpfile.h @@ -312,6 +312,12 @@ static const T_Help_table helptable_help[] = HELP_LINK (" 6 : %s", SPECIAL_LAYER6_TOGGLE) HELP_LINK (" 7 : %s", SPECIAL_LAYER7_TOGGLE) HELP_LINK (" 8 : %s", SPECIAL_LAYER8_TOGGLE) + HELP_TEXT ("") + HELP_LINK (" Format check : %s", SPECIAL_FORMAT_CHECKER) + HELP_LINK (" Format check menu: %s", SPECIAL_FORMAT_CHECKER_MENU) + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TEXT ("") }; static const T_Help_table helptable_credits[] = { diff --git a/src/hotkeys.c b/src/hotkeys.c index 764275bb..46150eb7 100644 --- a/src/hotkeys.c +++ b/src/hotkeys.c @@ -1477,6 +1477,14 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { true, SDLK_HOME|MOD_ALT, // Alt + Home 0}, + {181, + "Format checker", + "Performs a format check on the", + "current image.", + "", + true, + 0, + 0}, }; word Ordering[NB_SHORTCUTS]= @@ -1662,4 +1670,6 @@ word Ordering[NB_SHORTCUTS]= 0x100+BUTTON_LAYER_UP, 0x100+BUTTON_LAYER_DOWN, 0x100+BUTTON_LAYER_MENU, + SPECIAL_FORMAT_CHECKER, + SPECIAL_FORMAT_CHECKER_MENU, }; diff --git a/src/loadsave.c b/src/loadsave.c index 3aacd162..b8f1075e 100644 --- a/src/loadsave.c +++ b/src/loadsave.c @@ -134,7 +134,7 @@ void Load_SDL_Image(T_IO_Context *); // ENUM Name TestFunc LoadFunc SaveFunc PalOnly Comment Layers Ext Exts T_Format File_formats[NB_KNOWN_FORMATS] = { - {FORMAT_ALL_IMAGES, "(all)", NULL, NULL, NULL, 0, 0, 0, "", "gif;png;bmp;pcx;pkm;lbm;iff;img;sci;scq;scf;scn;sco;pi1;pc1;cel;neo;kcf;pal;c64;koa;tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff;ico"}, + {FORMAT_ALL_IMAGES, "(all)", NULL, NULL, NULL, 0, 0, 0, "", "gif;png;bmp;pcx;pkm;lbm;iff;img;sci;scq;scf;scn;sco;pi1;pc1;cel;neo;kcf;pal;c64;koa;koala;fli;bml;cdu;prg;tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff;ico"}, {FORMAT_ALL_FILES, "(*.*)", NULL, NULL, NULL, 0, 0, 0, "", "*"}, {FORMAT_GIF, " gif", Test_GIF, Load_GIF, Save_GIF, 0, 1, 1, "gif", "gif"}, #ifndef __no_pnglib__ @@ -152,7 +152,7 @@ T_Format File_formats[NB_KNOWN_FORMATS] = { {FORMAT_NEO, " neo", Test_NEO, Load_NEO, Save_NEO, 0, 0, 0, "neo", "neo"}, {FORMAT_KCF, " kcf", Test_KCF, Load_KCF, Save_KCF, 1, 0, 0, "kcf", "kcf"}, {FORMAT_PAL, " pal", Test_PAL, Load_PAL, Save_PAL, 1, 0, 0, "pal", "pal"}, - {FORMAT_C64, " c64", Test_C64, Load_C64, Save_C64, 0, 1, 0, "c64", "c64;koa"}, + {FORMAT_C64, " c64", Test_C64, Load_C64, Save_C64, 0, 1, 0, "c64", "c64;koa;koala;fli;bml;cdu;prg"}, {FORMAT_SCR, " cpc", NULL, NULL, Save_SCR, 0, 0, 0, "cpc", "cpc;scr"}, {FORMAT_MISC,"misc.",NULL, NULL, NULL, 0, 0, 0, "", "tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff;ico"}, }; @@ -430,8 +430,7 @@ void Pre_load(T_IO_Context *context, short width, short height, long file_size, // On efface le commentaire précédent Window_rectangle(45,70,32*8,8,MC_Light); // Affichage du commentaire - if (Get_fileformat(format)->Comment) - Print_in_window(45,70,Main_comment,MC_Black,MC_Light); + Print_in_window(45,70,context->Comment,MC_Black,MC_Light); // Calcul des données nécessaires à l'affichage de la preview: if (ratio == PIXEL_WIDE && diff --git a/src/misc.c b/src/misc.c index bc750078..de374850 100644 --- a/src/misc.c +++ b/src/misc.c @@ -826,6 +826,28 @@ double Fround(double n, unsigned d) return floor(n * exp + 0.5) / exp; } +/// Count number of bits in a word (16bit). +/// Based on Wikipedia article for Hamming_weight, it's optimized +/// for cases when zeroes are more frequent. +int Popcount_word(word x) +{ + word count; + for (count=0; x; count++) + x &= x-1; + return count; +} + +/// Count number of bits in a dword (32bit). +/// Based on Wikipedia article for Hamming_weight, it's optimized +/// for cases when zeroes are more frequent. +int Popcount_dword(dword x) +{ + dword count; + for (count=0; x; count++) + x &= x-1; + return count; +} + // Fonction retournant le libellé d'une mode (ex: " 320x200") char * Mode_label(int mode) diff --git a/src/misc.h b/src/misc.h index 523f143d..bd365211 100644 --- a/src/misc.h +++ b/src/misc.h @@ -165,3 +165,6 @@ int Max(int a,int b); char* Mode_label(int mode); int Convert_videomode_arg(const char *argument); + +int Popcount_word(word x); +int Popcount_dword(dword x); diff --git a/src/miscfileformats.c b/src/miscfileformats.c index 6c032a7b..28453236 100644 --- a/src/miscfileformats.c +++ b/src/miscfileformats.c @@ -39,6 +39,7 @@ #include "sdlscreen.h" #include "struct.h" #include "windows.h" +#include "oldies.h" //////////////////////////////////// PAL //////////////////////////////////// // @@ -444,24 +445,24 @@ void Load_PKM(T_IO_Context * context) // Trouver quels sont les octets de reconnaissance void Find_recog(byte * recog1, byte * recog2) { - dword Find_recon[256]; // Table d'utilisation de couleurs + dword color_usage[256]; // Table d'utilisation de couleurs byte best; // Meilleure couleur pour recon (recon1 puis recon2) dword NBest; // Nombre d'occurences de cette couleur word index; // On commence par compter l'utilisation de chaque couleurs - Count_used_colors(Find_recon); + Count_used_colors(color_usage); // Ensuite recog1 devient celle la moins utilisée de celles-ci *recog1=0; best=1; NBest=INT_MAX; // Une même couleur ne pourra jamais être utilisée 1M de fois. for (index=1;index<=255;index++) - if (Find_recon[index]File_name, context->File_directory); if ((file=fopen(filename,"wb"))) { // On regarde si des couleurs >16 sont utilisées dans l'image - for (x_pos=16;((x_pos<256) && (!Utilisation[x_pos]));x_pos++); + for (x_pos=16;((x_pos<256) && (!color_usage[x_pos]));x_pos++); if (x_pos==256) { @@ -1173,10 +1174,10 @@ void Save_KCF(T_IO_Context * context) int pal_index; int color_index; int index; - dword Utilisation[256]; // Table d'utilisation de couleurs + dword color_usage[256]; // Table d'utilisation de couleurs // On commence par compter l'utilisation de chaque couleurs - Count_used_colors(Utilisation); + Count_used_colors(color_usage); File_error=0; Get_full_filename(filename, context->File_name, context->File_directory); @@ -1185,7 +1186,7 @@ void Save_KCF(T_IO_Context * context) // Sauvegarde de la palette // On regarde si des couleurs >16 sont utilisées dans l'image - for (index=16;((index<256) && (!Utilisation[index]));index++); + for (index=16;((index<256) && (!color_usage[index]));index++); if (index==256) { @@ -2035,6 +2036,7 @@ void Save_NEO(T_IO_Context * context) } //////////////////////////////////// C64 //////////////////////////////////// + void Test_C64(T_IO_Context * context) { FILE* file; @@ -2050,14 +2052,15 @@ void Test_C64(T_IO_Context * context) file_size = File_length_file(file); switch (file_size) { - case 1000: // screen or color - case 1002: // (screen or color) + loadaddr case 8000: // raw bitmap case 8002: // raw bitmap with loadaddr - case 9000: // bitmap + screen - case 9002: // bitmap + screen + loadaddr + case 9000: // bitmap + ScreenRAM + case 9002: // bitmap + ScreenRAM + loadaddr case 10001: // multicolor case 10003: // multicolor + loadaddr + case 17472: // FLI (BlackMail) + case 17474: // FLI (BlackMail) + loadaddr + case 10277: // multicolor CDU-Paint + loadaddr File_error = 0; break; default: // then we don't know for now. @@ -2071,7 +2074,7 @@ void Test_C64(T_IO_Context * context) } } -void Load_C64_hires(T_IO_Context *context, byte *bitmap, byte *colors) +void Load_C64_hires(T_IO_Context *context, byte *bitmap, byte *screen_ram) { int cx,cy,x,y,c[4],pixel,color; @@ -2079,8 +2082,8 @@ void Load_C64_hires(T_IO_Context *context, byte *bitmap, byte *colors) { for(cx=0; cx<40; cx++) { - c[0]=colors[cy*40+cx]&15; - c[1]=colors[cy*40+cx]>>4; + c[0]=screen_ram[cy*40+cx]&15; + c[1]=screen_ram[cy*40+cx]>>4; for(y=0; y<8; y++) { pixel=bitmap[cy*320+cx*8+y]; @@ -2094,7 +2097,7 @@ void Load_C64_hires(T_IO_Context *context, byte *bitmap, byte *colors) } } -void Load_C64_multi(T_IO_Context *context, byte *bitmap, byte *colors, byte *nybble, byte background) +void Load_C64_multi(T_IO_Context *context, byte *bitmap, byte *screen_ram, byte *color_ram, byte background) { int cx,cy,x,y,c[4],pixel,color; c[0]=background&15; @@ -2102,9 +2105,9 @@ void Load_C64_multi(T_IO_Context *context, byte *bitmap, byte *colors, byte *nyb { for(cx=0; cx<40; cx++) { - c[1]=colors[cy*40+cx]>>4; - c[2]=colors[cy*40+cx]&15; - c[3]=nybble[cy*40+cx]&15; + c[1]=screen_ram[cy*40+cx]>>4; + c[2]=screen_ram[cy*40+cx]&15; + c[3]=color_ram[cy*40+cx]&15; for(y=0; y<8; y++) { @@ -2120,16 +2123,113 @@ void Load_C64_multi(T_IO_Context *context, byte *bitmap, byte *colors, byte *nyb } } +void Load_C64_fli(T_IO_Context *context, byte *bitmap, byte *screen_ram, byte *color_ram, byte *background) +{ + // Thanks to MagerValp for complement of specifications. + // + // background : length: 200 (+ padding 56) + // These are the BG colors for lines 0-199 (top to bottom) + // Low nybble: the color. + // High nybble: garbage. ignore it. + // color_ram : length: 1000 (+ padding 24) + // Color RAM. Contains one color per 4x8 block. + // There are 40x25 such blocks, arranged from top left to bottom + // right, starting in right direction. For each block there is one byte. + // Low nybble: the color. + // High nybble: garbage. ignore it. + // screen_ram : length: 8192 + // Screen RAMs. The s is important. + // This is actually 8 blocks of 1000 bytes, each separated by a filler of + // 24 bytes. Each byte contains data for a 4x1 pixel group, and a complete + // block will contain 40x25 of them. 40 is from left to right, and 25 is from + // top to bottom, spacing them 8 lines apart. + // The second block start at y=1, the third block starts at y=2, etc... + // Each byte contains 2 colors that *can* be used by the 4x1 pixel group: + // Low nybble: Color 1 + // High nybble: Color 2 + // + // bitmap : length: 8000 + // This is the final structure that refers to all others. It describes + // 160x200 pixels linearly, from top left to bottom right, starting in + // right direction. For each pixel, two bits say which color is displayed + // (So 4 pixels are described by the same byte) + // 00 Use the BG color of the current line (background[y]) + // 01 Use the Color 2 from the current 4x8 block of Screen RAM + // ((screen_ram[y/8][x/4] & 0xF0) >> 8) + // 10 Use the Color 1 from the current 4x8 block of Screen RAM + // (screen_ram[y/8][x/4] & 0x0F) + // 11 Use the color from Color RAM + // (color_ram[y/8][x/4] & 0x0F) + // + + int cx,cy,x,y,c[4]; + + for(y=0; y<200; y++) + { + for(x=0; x<160; x++) + { + Set_pixel(context, x,y,background[y]); + } + } + + Set_layer(context, 1); + for(cy=0; cy<25; cy++) + { + for(cx=0; cx<40; cx++) + { + c[3]=color_ram[cy*40+cx]&15; + for(y=0; y<8; y++) + { + for(x=0; x<4; x++) + { + Set_pixel(context, cx*4+(3-x),cy*8+y,c[3]); + } + } + } + } + + Set_layer(context, 2); + for(cy=0; cy<25; cy++) + { + for(cx=0; cx<40; cx++) + { + c[3]=color_ram[cy*40+cx]&15; + for(y=0; y<8; y++) + { + int pixel=bitmap[cy*320+cx*8+y]; + + c[0]=background[cy*8+y]&15; + c[1]=screen_ram[y*1024+cy*40+cx]>>4; + c[2]=screen_ram[y*1024+cy*40+cx]&15; + for(x=0; x<4; x++) + { + int color=c[(pixel&3)]; + pixel>>=2; + Set_pixel(context, cx*4+(3-x),cy*8+y,color); + } + } + } + } + Set_layer(context, 3); + for(y=0; y<200; y++) + { + for(x=0; x<160; x++) + { + Set_pixel(context, x,y,16); + } + } +} + void Load_C64(T_IO_Context * context) { FILE* file; char filename[MAX_PATH_CHARACTERS]; long file_size; - int i; - byte background,hasLoadAddr=0; + byte hasLoadAddr=0; int loadFormat=0; - enum c64_format {F_hires,F_multi,F_bitmap,F_screen,F_color}; - const char *c64_format_names[]={"hires","multicolor","bitmap","screen","color"}; + enum c64_format {F_hires,F_multi,F_bitmap,F_fli}; + const char *c64_format_names[]={"Hires","Multicolor","Bitmap","FLI"}; + // Palette from http://www.pepto.de/projects/colorvic/ byte pal[48]={ @@ -2150,118 +2250,194 @@ void Load_C64(T_IO_Context * context) 0x6C, 0x5E, 0xB5, 0x95, 0x95, 0x95}; - byte bitmap[8000],colors[1000],nybble[1000]; + byte *file_buffer; + byte *bitmap, *screen_ram, *color_ram=NULL, *background=NULL; // Only pointers to existing data word width=320, height=200; + static byte dummy_screen[1000]; Get_full_filename(filename, context->File_name, context->File_directory); file = fopen(filename,"rb"); if (file) { - File_error=0; - file_size = File_length_file(file); + File_error=0; + file_size = File_length_file(file); - switch (file_size) + // Check for known file sizes + switch (file_size) + { + case 8000: // raw bitmap + case 8002: // raw bitmap with loadaddr + case 9000: // bitmap + ScreenRAM + case 9002: // bitmap + ScreenRAM + loadaddr + case 10001: // multicolor + case 10003: // multicolor + loadaddr + case 10277: // multicolor CDU-Paint + loadaddr + case 17472: // FLI (BlackMail) + case 17474: // FLI (BlackMail) + loadaddr + break; + + default: + File_error = 1; + fclose(file); + return; + } + // Load entire file in memory + file_buffer=(byte *)malloc(file_size); + if (!file_buffer) + { + File_error = 1; + fclose(file); + return; + } + if (!Read_bytes(file,file_buffer,file_size)) + { + File_error = 1; + free(file_buffer); + fclose(file); + return; + } + fclose(file); + + memset(dummy_screen,1,1000); + + switch (file_size) { - case 1000: // screen or color - hasLoadAddr=0; - loadFormat=F_screen; - break; - - case 1002: // (screen or color) + loadaddr - hasLoadAddr=1; - loadFormat=F_screen; - break; - case 8000: // raw bitmap hasLoadAddr=0; loadFormat=F_bitmap; + bitmap=file_buffer+0; // length: 8000 + screen_ram=dummy_screen; break; - + case 8002: // raw bitmap with loadaddr hasLoadAddr=1; loadFormat=F_bitmap; + bitmap=file_buffer+2; // length: 8000 + screen_ram=dummy_screen; break; - case 9000: // bitmap + screen + case 9000: // bitmap + ScreenRAM hasLoadAddr=0; loadFormat=F_hires; + bitmap=file_buffer+0; // length: 8000 + screen_ram=file_buffer+8000; // length: 1000 break; - case 9002: // bitmap + screen + loadaddr + case 9002: // bitmap + ScreenRAM + loadaddr hasLoadAddr=1; loadFormat=F_hires; + bitmap=file_buffer+2; // length: 8000 + screen_ram=file_buffer+8002; // length: 1000 break; case 10001: // multicolor hasLoadAddr=0; loadFormat=F_multi; + context->Ratio = PIXEL_WIDE; + bitmap=file_buffer+0; // length: 8000 + screen_ram=file_buffer+8000; // length: 1000 + color_ram=file_buffer+9000; // length: 1000 + background=file_buffer+10000; // only 1 break; case 10003: // multicolor + loadaddr hasLoadAddr=1; loadFormat=F_multi; + context->Ratio = PIXEL_WIDE; + bitmap=file_buffer+2; // length: 8000 + screen_ram=file_buffer+8002; // length: 1000 + color_ram=file_buffer+9002; // length: 1000 + background=file_buffer+10002; // only 1 break; - - default: // then we don't know what it is. - File_error = 1; + case 10277: // multicolor CDU-Paint + loadaddr + hasLoadAddr=1; + loadFormat=F_multi; + context->Ratio = PIXEL_WIDE; + // 273 bytes of display routine + bitmap=file_buffer+275; // length: 8000 + screen_ram=file_buffer+8275; // length: 1000 + color_ram=file_buffer+9275; // length: 1000 + background=file_buffer+10275; // only 1 + break; + + case 17472: // FLI (BlackMail) + hasLoadAddr=0; + loadFormat=F_fli; + context->Ratio = PIXEL_WIDE; + background=file_buffer+0; // length: 200 (+ padding 56) + color_ram=file_buffer+256; // length: 1000 (+ padding 24) + screen_ram=file_buffer+1280; // length: 8192 + bitmap=file_buffer+9472; // length: 8000 + break; + + case 17474: // FLI (BlackMail) + loadaddr + hasLoadAddr=1; + loadFormat=F_fli; + context->Ratio = PIXEL_WIDE; + background=file_buffer+2; // length: 200 (+ padding 56) + color_ram=file_buffer+258; // length: 1000 (+ padding 24) + screen_ram=file_buffer+1282; // length: 8192 + bitmap=file_buffer+9474; // length: 8000 + break; + + default: + File_error = 1; + free(file_buffer); + return; } + if (context->Ratio == PIXEL_WIDE) + width=160; + + // Write detailed format in comment + strcpy(context->Comment, c64_format_names[loadFormat]); + if (hasLoadAddr) + { + // get load address + word load_addr; + load_addr = file_buffer[0] | (file_buffer[1] << 8); + sprintf(context->Comment+strlen(context->Comment),", load at $%04.4X",load_addr); + } + else + { + sprintf(context->Comment+strlen(context->Comment),", no addr"); + } + + Pre_load(context, width, height, file_size, FORMAT_C64, context->Ratio,0); // Do this as soon as you can + memcpy(context->Palette,pal,48); // this set the software palette for grafx2 + // Transparent color "16" is a dark grey that is distinguishable + // from black, but darker than normal colors. + context->Palette[16].R=20; + context->Palette[16].G=20; + context->Palette[16].B=20; + Palette_loaded(context); // Always call it if you change the palette - if (file_size>9002) - width=160; - - if (hasLoadAddr) - { - // get load address - Read_byte(file,&background); - Read_byte(file,&background); - sprintf(filename,"load at $%02x00",background); - } - else - { - sprintf(filename,"no addr"); - } - - if(file_size>9002) - { - context->Ratio = PIXEL_WIDE; - } - sprintf(context->Comment,"C64 %s, %s", - c64_format_names[loadFormat],filename); - Pre_load(context, width, height, file_size, FORMAT_C64, context->Ratio,0); // Do this as soon as you can - context->Width = width ; context->Height = height; + context->Transparent_color=16; - Read_bytes(file,bitmap,8000); - - if (file_size>8002) - Read_bytes(file,colors,1000); - else + if(loadFormat==F_fli) { - for(i=0;i<1000;i++) - { - colors[i]=1; - } + Load_C64_fli(context,bitmap,screen_ram,color_ram,background); } - - if(width==160) + else + if(loadFormat==F_multi) { - Read_bytes(file,nybble,1000); - Read_byte(file,&background); - Load_C64_multi(context,bitmap,colors,nybble,background); + Load_C64_multi(context,bitmap,screen_ram,color_ram,*background); } else { - Load_C64_hires(context,bitmap,colors); + Load_C64_hires(context,bitmap,screen_ram); } File_error = 0; - fclose(file); + + free(file_buffer); + } else File_error = 1; @@ -2290,17 +2466,17 @@ int Save_C64_window(byte *saveWhat, byte *loadAddr) }; Open_window(200,120,"c64 settings"); - Window_set_normal_button(110,100,80,15,"Save",1,1,SDLK_RETURN); - Window_set_normal_button(10,100,80,15,"Cancel",1,1,SDLK_ESCAPE); + Window_set_normal_button(110,100,80,15,"Save",1,1,SDLK_RETURN); // 1 + Window_set_normal_button(10,100,80,15,"Cancel",1,1,SDLK_ESCAPE); // 2 Print_in_window(13,18,"Data:",MC_Dark,MC_Light); - what=Window_set_dropdown_button(10,28,90,15,70,what_label[*saveWhat],1, 0, 1, LEFT_SIDE,0); + what=Window_set_dropdown_button(10,28,90,15,70,what_label[*saveWhat],1, 0, 1, LEFT_SIDE,0); // 3 Window_dropdown_clear_items(what); for (i=0; iFile_name, context->File_directory); + /* if (numcolors>16) { Warning_message("Error: Max 16 colors"); File_error = 1; return; } + */ if (((context->Width!=320) && (context->Width!=160)) || context->Height!=200) { Warning_message("must be 320x200 or 160x200"); @@ -2574,7 +2801,7 @@ void Save_C64(T_IO_Context * context) if (context->Width==320) File_error = Save_C64_hires(context,filename,saveWhat,loadAddr); else - File_error = Save_C64_multi(context,filename,saveWhat,loadAddr); + File_error = Save_C64_fli(filename,saveWhat,loadAddr); } diff --git a/src/oldies.c b/src/oldies.c new file mode 100644 index 00000000..9be48122 --- /dev/null +++ b/src/oldies.c @@ -0,0 +1,411 @@ +/* vim:expandtab:ts=2 sw=2: +*/ +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Yves Rizoud + Copyright 2008 Franck Charlet + Copyright 2007 Adrien Destugues + Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) + + Grafx2 is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 + of the License. + + Grafx2 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grafx2; if not, see +*/ +#include +#include +#include +#include +#include +#include "struct.h" +#include "global.h" +#include "errors.h" +#include "misc.h" +#include "palette.h" + +void Pixel_in_layer(word x,word y, byte layer, byte color) +{ + *((y)*Main_image_width+(x)+Main_backups->Pages->Image[layer])=color; +} + +byte C64_FLI(byte *bitmap, byte *screen_ram, byte *color_ram, byte *background) +{ + word used_colors[200][40]; + word block_used_colors[25][40]; + word line_used_colors[200]; + byte used_colors_count[200][40]; + dword usage[16]; + word x,y,row,col; + int i; + byte line_color[200]; + byte block_color[25][40]; + word best_color_count; + byte best_color; + const byte no_color=16; + + // Prerequisites + if (Main_backups->Pages->Nb_layers < 3) + return 1; + if (Main_image_width != 160 || Main_image_height != 200) + return 2; + + memset(used_colors,0,200*40*sizeof(word)); + memset(block_used_colors,0,25*40*sizeof(word)); + memset(line_used_colors,0,200*sizeof(word)); + memset(used_colors_count,0,200*40*sizeof(byte)); + + // Initialize these as "unset" + memset(line_color,no_color,200*sizeof(byte)); + memset(block_color,no_color,25*40*sizeof(byte)); + + // Examine all 4-pixel blocks to fill used_colors[][] + for (row=0;row<200;row++) + { + for (col=0;col<40;col++) + { + for (x=0;x<4;x++) + { + byte c=*((row)*Main_image_width+(col*4+x)+Main_backups->Pages->Image[2]); + used_colors[row][col] |= 1<Pages->Image[0]); + if (c<16) + { + line_color[row]=c; + for (col=0;col<40;col++) + { + // Remove that color from the sets + used_colors[row][col] &= ~(1<Pages->Image[1]); + if (c<16) + { + block_color[row/8][col]=c; + // Remove that color from the sets + for (y=0; y<8;y++) + used_colors[row+y][col] &= ~(1<best_color_count) + { + best_color_count=usage[i]; + best_color=i; + } + } + line_color[row]=best_color; + + // Remove that color from the sets + for (col=0;col<40;col++) + { + if (used_colors[row][col] & (1<2) + { + filter &= used_colors[row+y][col]; + + for (i=0; i<16; i++) + { + if (used_colors[row+y][col] & (1<best_color_count) + { + best_color_count=usage[i]; + best_color=i; + } + } + } + } + block_color[row/8][col]=best_color; + + // Remove that color from the sets + for (y=0;y<8;y++) + { + if (used_colors[row+y][col] & (1<15) + c1=16; + if (c2>15) + c2=16; + + // Output Screen RAMs + if (screen_ram!=NULL) + screen_ram[y*1024+row*40+col] = (c1&15) | ((c2&15)<<4); + + // Output bitmap + if (bitmap!=NULL) + { + for(x=0; x<4; x++) + { + byte bits; + byte c=*((row*8+y)*Main_image_width+(col*4+x)+Main_backups->Pages->Image[2]); + + if (c==line_color[row*8+y]) + // BG color + bits=0; + else if (c==block_color[row][col]) + // block color + bits=3; + else if (c==c1) + // Color 1 + bits=2; + else if (c==c2) + // Color 2 + bits=1; + else // problem + bits=0; + // clear target bits + //bitmap[row*320+col*8+y] &= ~(3<<((3-x)*2)); + // set them + bitmap[row*320+col*8+y] |= bits<<((3-x)*2); + } + } + } + } + } + //memset(background,3,200); + //memset(color_ram,5,8000); + //memset(screen_ram,(9<<4) | 7,8192); + + return 0; + +} + +byte C64_FLI_enforcer(void) +{ + byte background[200]; + byte bitmap[8000]; + byte screen_ram[8192]; + byte color_ram[1000]; + + int row, col, x, y; + byte c[4]; + + // Checks + if (Main_image_width != 160) + return 1; + if (Main_image_height != 200) + return 1; + if (Main_backups->Pages->Nb_layers != 4) + return 2; + + Backup_layers(1<<3); + + memset(bitmap,0,8000); + memset(background,0,200); + memset(color_ram,0,1000); + memset(screen_ram,0,8192); + C64_FLI(bitmap, screen_ram, color_ram, background); + + for(row=0; row<25; row++) + { + for(col=0; col<40; col++) + { + c[3]=color_ram[row*40+col]&15; + for(y=0; y<8; y++) + { + int pixel=bitmap[row*320+col*8+y]; + + c[0]=background[row*8+y]&15; + c[1]=screen_ram[y*1024+row*40+col]>>4; + c[2]=screen_ram[y*1024+row*40+col]&15; + for(x=0; x<4; x++) + { + int color=c[(pixel&3)]; + pixel>>=2; + Pixel_in_layer(col*4+(3-x),row*8+y,3,color); + } + } + } + } + End_of_modification(); + + // Visible feedback: + + // If the "check" layer was visible, manually update the whole thing + if (Main_layers_visible & (1<<3)) + { + Hide_cursor(); + Redraw_layered_image(); + Display_all_screen(); + Display_layerbar(); + Display_cursor(); + } + else + // Otherwise, simply toggle the layer visiblity + Layer_activate(3,RIGHT_SIDE); + + + return 0; +} \ No newline at end of file diff --git a/src/oldies.h b/src/oldies.h new file mode 100644 index 00000000..8476775f --- /dev/null +++ b/src/oldies.h @@ -0,0 +1,24 @@ +/* vim:expandtab:ts=2 sw=2: +*/ +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Adrien Destugues + + Grafx2 is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 + of the License. + + Grafx2 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grafx2; if not, see +*/ + +byte C64_FLI(byte *bitmap, byte *screen_ram, byte *color_ram, byte *background); + +byte C64_FLI_enforcer(void); + diff --git a/src/pages.c b/src/pages.c index de7fccec..4b3c5ee0 100644 --- a/src/pages.c +++ b/src/pages.c @@ -178,25 +178,47 @@ void Redraw_layered_image(void) { #ifndef NOLAYERS // Re-construct the image with the visible layers - byte layer; + byte layer=0; // First layer - for (layer=0; layerPages->Nb_layers; layer++) + if (Main_layers_visible & (1<<4)) { - if ((1<Pages->Image[layer], - Main_image_width*Main_image_height); - - // Initialize the depth buffer - memset(Main_visible_image_depth_buffer.Image, - layer, - Main_image_width*Main_image_height); - - // skip all other layers - layer++; - break; + layer = *(Main_backups->Pages->Image[4]+i); + Main_visible_image.Image[i]=*(Main_backups->Pages->Image[layer]+i); + } + + // Copy it to the depth buffer + memcpy(Main_visible_image_depth_buffer.Image, + Main_backups->Pages->Image[4], + Main_image_width*Main_image_height); + + // Next + layer= (1<<4)+1; + } + else + { + for (layer=0; layerPages->Nb_layers; layer++) + { + if ((1<Pages->Image[layer], + Main_image_width*Main_image_height); + + // Initialize the depth buffer + memset(Main_visible_image_depth_buffer.Image, + layer, + Main_image_width*Main_image_height); + + // skip all other layers + layer++; + break; + } } } // subsequent layer(s) diff --git a/src/struct.h b/src/struct.h index 3e8fbde2..f46c2560 100644 --- a/src/struct.h +++ b/src/struct.h @@ -323,11 +323,11 @@ typedef struct byte Grid_XOR_color; ///< XOR value to apply for grid color. } T_Config; -// Structures utilisées pour les descriptions de pages et de liste de pages. -// Lorsqu'on gérera les animations, il faudra aussi des listes de listes de +// Structures utilisées pour les descriptions de pages et de liste de pages. +// Lorsqu'on gèrera les animations, il faudra aussi des listes de listes de // pages. -// Ces structures sont manipulées à travers des fonctions de gestion du +// Ces structures sont manipulées à travers des fonctions de gestion du // backup dans "graph.c". /// This is the data for one step of Undo/Redo, for one image. @@ -350,11 +350,7 @@ typedef struct T_Page byte Background_transparent; ///< Boolean, true if Layer 0 should have transparent pixels byte Transparent_color; ///< Index of transparent color. 0 to 255. byte Nb_layers; ///< Number of layers -#if __GNUC__ < 3 - byte * Image[0]; -#else byte * Image[]; ///< Pixel data for the (first layer of) image. -#endif // Define as Image[0] if you have an old gcc which is not C99. // No field after Image[] ! Dynamic layer allocation for Image[1], [2] etc. } T_Page; From eba26aaa962d1db2c3da60793402f1582163bca3 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Sun, 13 Feb 2011 21:49:31 +0000 Subject: [PATCH 3/9] Merge trunk to the cpcmode5 branch. This gets us a more recent grafx2 with the cpcmode5 drawing. Now to make this mode optional so users can still work in regular mode :) git-svn-id: svn://pulkomandy.tk/GrafX2/branches/cpcmode5@1719 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- src/Makefile | 121 +++-- src/Makefile.dep | 46 +- src/SFont.c | 55 +- src/SFont.h | 5 +- src/brush.c | 769 +++++++++++++-------------- src/brush.h | 15 +- src/brush_ops.c | 110 +++- src/buttons.c | 1067 +++++++++++++++++++++++++------------ src/buttons.h | 4 + src/buttons_effects.c | 66 ++- src/const.h | 67 ++- src/engine.c | 664 +++++++++++++++++------ src/engine.h | 21 +- src/factory.c | 1036 ++++++++++++++++++++++++++++-------- src/factory.h | 10 + src/fileformats.c | 548 +++++++++++++++---- src/filesel.c | 502 ++++++++++++++---- src/filesel.h | 12 +- src/global.h | 182 ++++--- src/graph.c | 124 +++-- src/help.c | 256 +++++---- src/help.h | 12 + src/helpfile.h | 155 +++++- src/hotkeys.c | 189 ++++++- src/hotkeys.h | 2 + src/init.c | 847 ++++++++++++++++++++---------- src/init.h | 6 +- src/input.c | 658 +++++++++++++++++------ src/input.h | 10 +- src/io.c | 49 +- src/io.h | 7 + src/keyboard.c | 108 +++- src/loadsave.c | 373 ++++++++----- src/loadsave.h | 30 +- src/main.c | 164 +++--- src/misc.c | 58 +- src/misc.h | 4 +- src/miscfileformats.c | 124 +++-- src/mountlist.c | 2 +- src/op_c.c | 46 ++ src/op_c.h | 1 + src/operatio.c | 197 +++++-- src/operatio.h | 5 + src/pages.c | 234 +++++++-- src/pages.h | 12 +- src/palette.c | 1167 ++++++++++++++++++++++++++++------------- src/palette.h | 16 + src/readini.c | 46 +- src/readline.c | 302 +++++++++-- src/readline.h | 13 +- src/realpath.c | 7 +- src/saveini.c | 169 +++--- src/sdlscreen.c | 64 ++- src/sdlscreen.h | 7 + src/setup.c | 40 +- src/setup.h | 103 +++- src/shade.c | 6 +- src/special.c | 3 + src/struct.h | 124 +++-- src/text.c | 245 ++++++--- src/text.h | 5 +- src/tiles.c | 114 ++++ src/transform.c | 5 +- src/windows.c | 540 ++++++++++++------- src/windows.h | 6 +- 65 files changed, 8669 insertions(+), 3286 deletions(-) create mode 100644 src/tiles.c diff --git a/src/Makefile b/src/Makefile index fb0c92d5..7846d638 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,5 +1,6 @@ # Grafx2 - The Ultimate 256-color bitmap paint program # +# Copyright 2011 Pawel Góralski # Copyright 2009 Per Olofsson # Copyright 2008 Peter Gordon # Copyright 2008-2010 Yves Rizoud @@ -25,6 +26,7 @@ bindir = $(exec_prefix)/bin datarootdir = $(prefix)/share datadir = $(datarootdir) + pixmapdir = $(datarootdir)/icons # Compile with OPTIM=0 to disable gcc optimizations, to enable debug. STRIP = strip @@ -42,8 +44,8 @@ ifdef COMSPEC RMDIR = rmdir CP = cp BIN = ../bin/grafx2.exe - COPT = -W -Wall -Wdeclaration-after-statement -O$(OPTIM) -g -ggdb `sdl-config --cflags` $(TTFCOPT) $(JOYCOPT) $(LUACOPT) $(LAYERCOPT) - LOPT = `sdl-config --libs` -lSDL_image $(TTFLOPT) -lpng $(LUALOPT) + COPT = -W -Wall -Wdeclaration-after-statement -O$(OPTIM) -g -ggdb `sdl-config --cflags` $(TTFCOPT) $(JOYCOPT) $(VKEYCOPT) $(LUACOPT) $(LAYERCOPT) + LOPT = `sdl-config --libs` -lSDL_image $(TTFLOPT) -lpng14 $(LUALOPT) LUALOPT = -llua CC = gcc OBJDIR = ../obj/win32 @@ -52,7 +54,7 @@ ifdef COMSPEC PLATFORMOBJ = $(OBJDIR)/winres.o PLATFORM = win32 #some misc files we have to add to the release archive under windows. - PLATFORMFILES = bin/SDL.dll bin/SDL_image.dll bin/libpng13.dll bin/zlib1.dll $(TTFLIBS) + PLATFORMFILES = bin/SDL.dll bin/SDL_image.dll bin/libpng14-14.dll bin/zlib1.dll $(TTFLIBS) ZIP = zip else @@ -88,7 +90,7 @@ else FWDIR = /Library/Frameworks SDLCOPT = -arch i386 -I$(FWDIR)/SDL.framework/Headers -I$(FWDIR)/SDL_image.framework/Headers -I$(FWDIR)/SDL_ttf.framework/Headers -D_THREAD_SAFE SDLLOPT = -arch i386 -L/usr/lib -framework SDL -framework SDL_image -framework SDL_ttf -framework Cocoa -framework Carbon -framework OpenGL - COPT = -D__macosx__ -D__linux__ -W -Wall -Wdeclaration-after-statement -O$(OPTIM) -std=c99 -c -g $(SDLCOPT) $(TTFCOPT) -I/usr/X11/include + COPT = -D_DARWIN_C_SOURCE -D__macosx__ -D__linux__ -W -Wall -Wdeclaration-after-statement -O$(OPTIM) -std=c99 -c -g $(SDLCOPT) $(TTFCOPT) -I/usr/X11/include LOPT = $(SDLLOPT) -L/usr/X11/lib -R/usr/X11/lib -lpng # Use gcc for compiling. Use ncc to build a callgraph and analyze the code. CC = gcc @@ -152,8 +154,15 @@ else RMDIR = rmdir CP = cp BIN = ../bin/grafx2 - COPT = -W -Wall -c -g `sdl-config --cflags` $(TTFCOPT) -I/boot/common/include - LOPT = `sdl-config --libs` -lSDL_image -lpng -ljpeg -lz $(TTFLOPT) + ifeq ($(NOLUA),1) + LUACOPT = + LUALOPT = + else + LUACOPT = -D__ENABLE_LUA__ + LUALOPT = -llua + endif + COPT = -W -Wall -c -g `sdl-config --cflags` $(TTFCOPT) -I/boot/common/include $(LUACOPT) + LOPT = `sdl-config --libs` -lSDL_image -lpng -ljpeg -lz $(TTFLOPT) -lfreetype -lbe $(LUALOPT) CC = gcc OBJDIR = ../obj/haiku ZIP = zip @@ -197,19 +206,15 @@ else CP = cp ZIP = zip PLATFORMFILES = gfx2.png + ifneq ($(ATARICROSS),1) ifeq ($(NOLUA),1) LUACOPT = LUALOPT = else - ifeq (`pkg-config --exists lua --print-errors`,"") - LUACOPT = `pkg-config lua --cflags` - LUALOPT = `pkg-config lua --libs` - else - LUACOPT = `pkg-config lua5.1 --cflags` - LUALOPT = `pkg-config lua5.1 --libs` - endif + LUACOPT = `pkg-config lua --cflags --silence-errors ||pkg-config lua5.1 --cflags --silence-errors ||pkg-config lua-5.1 --cflags` + LUALOPT = `pkg-config lua --libs --silence-errors ||pkg-config lua5.1 --libs --silence-errors ||pkg-config lua-5.1 --libs` + endif endif - # These can only be used under linux and maybe freebsd. They allow to compile for the gp2x or to create a windows binary ifdef WIN32CROSS #cross compile a Win32 executable @@ -225,18 +230,41 @@ else #cross compile an exec for the gp2x CC = /opt/open2x/gcc-4.1.1-glibc-2.3.6/arm-open2x-linux/bin/arm-open2x-linux-gcc BIN = ../bin/grafx2.gpe - COPT = -W -Wall -Wdeclaration-after-statement -pedantic -std=c99 -static -g -O$(OPTIM) -I/opt/open2x/gcc-4.1.1-glibc-2.3.6/include `/opt/open2x/gcc-4.1.1-glibc-2.3.6/bin/sdl-config --cflags` $(TTFCOPT) -D__GP2X__ $(TTFCOPT) $(JOYCOPT) $(LUACOPT) $(LAYERCOPT) + COPT = -W -Wall -Wdeclaration-after-statement -pedantic -std=c99 -static -g -O$(OPTIM) -I/opt/open2x/gcc-4.1.1-glibc-2.3.6/include `/opt/open2x/gcc-4.1.1-glibc-2.3.6/bin/sdl-config --cflags` $(TTFCOPT) -D__GP2X__ $(TTFCOPT) $(JOYCOPT) $(VKEYCOPT) $(LUACOPT) $(LAYERCOPT) LOPT = -static -lSDL_image `/opt/open2x/gcc-4.1.1-glibc-2.3.6/bin/sdl-config --static-libs` -ljpeg -lpng -lz -lm $(TTFLOPT) $(LUALOPT) OBJDIR = ../obj/gp2x NOTTF = 1 PLATFORM = gp2x STRIP = /opt/open2x/gcc-4.1.1-glibc-2.3.6/arm-open2x-linux/bin/arm-open2x-linux-strip JOYCOPT = -DUSE_JOYSTICK + + else ifdef AROS32CROSS + #cross compile an Aros 32 bit executable + BIN = ../bin/grafx2 + COPT = -Wall -g `i386-linux-aros-sdl-config --cflags` $(TTFCOPT) + LOPT = -lSDL_image `i386-linux-aros-sdl-config --libs` -lpng -ljpeg -lz $(TTFLOPT) -lfreetype2shared + CC = i386-aros-gcc + OBJDIR = ../obj/aros + STRIP = strip --strip-unneeded --remove-section .comment + PLATFORM = AROS + ZIP = lha + ZIPOPT = a + else ifdef ATARICROSS + #cross compile an exec for atari TOS/MiNT machine + CC = m68k-atari-mint-gcc + BIN = ../bin/grafx2.ttp + LUALOPT = -llua + OBJDIR = ../obj/m68k-atari-mint + PLATFORM = m68k-atari-mint + STRIP = m68k-atari-mint-strip -s + X11LOPT = + COPT = -W -Wall -m68020-60 -fomit-frame-pointer -pedantic -std=c99 -Wdeclaration-after-statement -D__MINT__ -DNO_INLINE_MATH -O$(OPTIM) -c -I$(prefix)/include `$(prefix)/bin/libpng12-config --cflags` `$(prefix)/bin/sdl-config --cflags` $() $(JOYCOPT) $(LAYERCOPT) $(LUACOPT) + LOPT = -static -m68020-60 -lSDL_image `$(prefix)/bin/sdl-config --libs` -L$(prefix)/lib -ltiff -ljpeg `$(prefix)/bin/libpng12-config --libs` -lz -lm $(TTFLOPT) -lfreetype $(LUALOPT) $(LAYERLOPT) else # Compiles a regular linux executable for the native platform BIN = ../bin/grafx2 - COPT = -W -Wall -Wdeclaration-after-statement -std=c99 -c -g `sdl-config --cflags` $(TTFCOPT) $(LUACOPT) + COPT = -W -Wall -Wdeclaration-after-statement -std=c99 -c -g `sdl-config --cflags` $(TTFCOPT) $(LUACOPT) $(JOYCOPT) $(VKEYCOPT) -O$(OPTIM) LOPT = `sdl-config --libs` -lSDL_image $(TTFLOPT) -lpng $(LUALOPT) -lm # Use gcc for compiling. Use ncc to build a callgraph and analyze the code. CC = gcc @@ -258,6 +286,7 @@ endif ### BUILD SETTINGS are set according to vars set in the platform selection, the "overridable defaults", and environment variables set before launching make #TrueType is optional: make NOTTF=1 to disable support and dependencies. +ifndef ($(ATARICROSS,1)) ifeq ($(NOTTF),1) TTFCOPT = -DNOTTF=1 TTFLOPT = @@ -265,10 +294,23 @@ ifeq ($(NOTTF),1) TTFLABEL = -nottf else TTFCOPT = - TTFLOPT = -L/usr/local/lib -lSDL_ttf $(X11LOPT) + TTFLOPT = -L$(prefix)/lib -lSDL_ttf $(X11LOPT) TTFLIBS = bin/libfreetype-6.dll bin/SDL_ttf.dll TTFLABEL = endif +else +ifeq ($(NOTTF),1) + TTFCOPT = -DNOTTF=1 + TTFLOPT = + TTFLIBS = + TTFLABEL = -nottf +else + TTFCOPT = + TTFLOPT = -L$(prefix)/lib -lSDL_ttf $(X11LOPT) + TTFLIBS = + TTFLABEL = +endif +endif #Lua scripting is optional too ifeq ($(NOLUA),1) @@ -289,6 +331,14 @@ ifeq ($(USE_JOYSTICK),1) JOYCOPT = -DUSE_JOYSTICK endif +#To enable virtual keyboard input (mouse-driven), make VIRT_KEY=1 +#This is automatically enabled on some platforms, but this +#switch allows you to test the virtual keyboard on any other platform. +ifeq ($(VIRT_KEY),1) + VKEYCOPT = -DVIRT_KEY +endif + + #To speed up rendering, can disable the layered editing # with NOLAYERS=1 ifeq ($(NOLAYERS),1) @@ -304,11 +354,16 @@ endif # This is the list of the objects we want to build. Dependancies are built by "make depend" automatically. OBJ = $(OBJDIR)/main.o $(OBJDIR)/init.o $(OBJDIR)/graph.o $(OBJDIR)/sdlscreen.o $(OBJDIR)/misc.o $(OBJDIR)/special.o $(OBJDIR)/buttons.o $(OBJDIR)/palette.o $(OBJDIR)/help.o $(OBJDIR)/operatio.o $(OBJDIR)/pages.o $(OBJDIR)/loadsave.o $(OBJDIR)/readline.o $(OBJDIR)/engine.o $(OBJDIR)/filesel.o $(OBJDIR)/op_c.o $(OBJDIR)/readini.o $(OBJDIR)/saveini.o $(OBJDIR)/shade.o $(OBJDIR)/keyboard.o $(OBJDIR)/io.o $(OBJDIR)/version.o $(OBJDIR)/text.o $(OBJDIR)/SFont.o $(OBJDIR)/setup.o $(OBJDIR)/pxsimple.o $(OBJDIR)/pxtall.o $(OBJDIR)/pxwide.o $(OBJDIR)/pxdouble.o $(OBJDIR)/pxtriple.o $(OBJDIR)/pxtall2.o $(OBJDIR)/pxwide2.o $(OBJDIR)/pxquad.o $(OBJDIR)/windows.o $(OBJDIR)/brush.o $(OBJDIR)/realpath.o $(OBJDIR)/mountlist.o $(OBJDIR)/input.o $(OBJDIR)/hotkeys.o $(OBJDIR)/transform.o $(OBJDIR)/pversion.o $(OBJDIR)/factory.o $(PLATFORMOBJ) $(OBJDIR)/fileformats.o $(OBJDIR)/miscfileformats.o $(OBJDIR)/libraw2crtc.o $(OBJDIR)/brush_ops.o $(OBJDIR)/buttons_effects.o $(OBJDIR)/layers.o $(OBJDIR)/oldies.o -SKIN_FILES = ../share/grafx2/skins/skin_classic.png ../share/grafx2/skins/skin_modern.png ../share/grafx2/skins/skin_DPaint.png ../share/grafx2/skins/font_Classic.png ../share/grafx2/skins/font_Fun.png ../share/grafx2/skins/font_Fairlight.png ../share/grafx2/skins/font_Melon.png ../share/grafx2/skins/font_DPaint.png ../share/grafx2/skins/skin_scenish.png ../share/grafx2/skins/font_Seen.png +SKIN_FILES = ../share/grafx2/skins/skin_classic.png ../share/grafx2/skins/skin_modern.png ../share/grafx2/skins/skin_DPaint.png ../share/grafx2/skins/font_Classic.png ../share/grafx2/skins/font_Fun.png ../share/grafx2/skins/font_Fairlight.png ../share/grafx2/skins/font_Melon.png ../share/grafx2/skins/font_DPaint.png ../share/grafx2/skins/skin_scenish.png ../share/grafx2/skins/font_Seen.png ../share/grafx2/skins/skin_Aurora.png ../share/grafx2/skins/skin_Clax3.gif ../share/grafx2/skins/skin_Clax2.gif ../share/grafx2/skins/skin_Clax4.gif SCRIPT_FILES1 = ../share/grafx2/scripts/bru_db_Amigaball.lua ../share/grafx2/scripts/bru_db_ColorSphere.lua ../share/grafx2/scripts/bru_db_FindAA.lua ../share/grafx2/scripts/bru_db_Fisheye.lua ../share/grafx2/scripts/bru_db_GrayscaleAvg.lua ../share/grafx2/scripts/bru_db_GrayscaleDesat.lua ../share/grafx2/scripts/bru_db_Halfsmooth.lua ../share/grafx2/scripts/bru_db_Mandelbrot.lua ../share/grafx2/scripts/bru_db_Waves.lua ../share/grafx2/scripts/pal_db_Desaturate.lua ../share/grafx2/scripts/pal_db_ExpandColors.lua ../share/grafx2/scripts/pal_db_FillColorCube.lua ../share/grafx2/scripts/pal_db_InvertedRGB.lua ../share/grafx2/scripts/pal_db_Set3bit.lua ../share/grafx2/scripts/pal_db_Set6bit.lua ../share/grafx2/scripts/pal_db_SetC64Palette.lua ../share/grafx2/scripts/pal_db_ShiftHue.lua ../share/grafx2/scripts/pic_db_Pic2isometric.lua ../share/grafx2/scripts/pic_db_Rainbow-Dark2Bright.lua ../share/grafx2/scripts/pic_db_SierpinskyCarpet.lua -SCRIPT_FILES2 = ../share/grafx2/scripts/pic_db_SierpinskyTriangle.lua ../share/grafx2/scripts/pic_ni_Colorspace12bit.lua ../share/grafx2/scripts/pic_ni_Colorspace15bit.lua ../share/grafx2/scripts/pic_ni_Colorspace18bit.lua ../share/grafx2/scripts/pic_ni_GlassGridFilter.lua ../share/grafx2/scripts/pic_ni_Grid8.lua ../share/grafx2/scripts/pic_ni_Grid8red.lua ../share/grafx2/scripts/pic_ni_GridIso.lua ../share/grafx2/scripts/pic_ni_PaletteX1.lua ../share/grafx2/scripts/pic_ni_PaletteX8.lua ../share/grafx2/scripts/scn_db_RemapImage2RGB.lua ../share/grafx2/scripts/scn_db_RemapImage2RGB_ed.lua ../share/grafx2/scripts/scn_db_RemapImageTo3bitPal.lua -SCRIPT_FILES1= SCRIPT_FILES1 SCRIPT_FILES2 +SCRIPT_FILES2 = ../share/grafx2/scripts/pic_db_SierpinskyTriangle.lua ../share/grafx2/scripts/pic_ni_GlassGridFilter.lua ../share/grafx2/scripts/scn_db_RemapImage2RGB.lua ../share/grafx2/scripts/scn_db_RemapImage2RGB_ed.lua ../share/grafx2/scripts/scn_db_RemapImageTo3bitPal.lua +SCRIPT_FILES= $(SCRIPT_FILES1) $(SCRIPT_FILES2) + +SCRIPTLIB_FILES = ../share/grafx2/scripts/libs/memory.lua + +FONT_FILES = ../share/grafx2/fonts/8pxfont.png ../share/grafx2/fonts/Tuffy.ttf ../share/grafx2/fonts/PF_Arma_5__.png ../share/grafx2/fonts/PF_Easta_7_.png ../share/grafx2/fonts/PF_Easta_7__.png ../share/grafx2/fonts/PF_Ronda_7__.png ../share/grafx2/fonts/PF_Tempesta_5.png ../share/grafx2/fonts/PF_Tempesta_5_.png ../share/grafx2/fonts/PF_Tempesta_5__.png ../share/grafx2/fonts/PF_Tempesta_5___.png ../share/grafx2/fonts/PF_Tempesta_7.png ../share/grafx2/fonts/PF_Tempesta_7_.png ../share/grafx2/fonts/PF_Tempesta_7__.png ../share/grafx2/fonts/PF_Tempesta_7___.png ../share/grafx2/fonts/PF_Westa_7_.png ../share/grafx2/fonts/PF_Westa_7__.png + ifeq ($(PLATFORM),Darwin) all : $(MACAPPEXE) @@ -316,11 +371,11 @@ $(MACAPPEXE) : $(BIN) rm -rf Grafx2.app mkdir -p Grafx2.app Grafx2.app/Contents Grafx2.app/Contents/Frameworks Grafx2.app/Contents/MacOS Grafx2.app/Contents/Resources echo 'APPL????' > Grafx2.app/Contents/PkgInfo - cp Info.plist Grafx2.app/Contents + cp ../Info.plist Grafx2.app/Contents cp -r English.lproj Grafx2.app/Contents/Resources - cp -r fonts Grafx2.app/Contents/Resources - cp -r skins Grafx2.app/Contents/Resources - cp -r gfx2def.ini Grafx2.app/Contents/Resources + cp -r ../share/grafx2/fonts Grafx2.app/Contents/Resources + cp -r ../share/grafx2/skins Grafx2.app/Contents/Resources + cp -r ../share/grafx2/gfx2def.ini Grafx2.app/Contents/Resources cp -Rp $(FWDIR)/SDL.framework Grafx2.app/Contents/Frameworks cp -Rp $(FWDIR)/SDL_image.framework Grafx2.app/Contents/Frameworks cp -Rp $(FWDIR)/SDL_ttf.framework Grafx2.app/Contents/Frameworks @@ -341,9 +396,9 @@ ziprelease: version $(BIN) release echo `sed "s/.*=\"\(.*\)\";/\1/" pversion.c`.`svnversion` | tr " :" "_-" | sed -e "s/\(wip\)\\./\1/I" > $(OBJDIR)/versiontag tar cvzf "../src-`cat $(OBJDIR)/versiontag`.tgz" --strip=1 ../src/*.c ../src/*.h ../src/Makefile ../src/Makefile.dep ../src/gfx2.ico - cd .. && $(ZIP) $(ZIPOPT) "grafx2-`cat $(OBJDIR:../%=%)/versiontag`$(TTFLABEL)-$(PLATFORM).$(ZIP)" $(BIN:../%=%) share/grafx2/gfx2def.ini $(SCRIPT_FILES:../%=%) $(SKIN_FILES:../%=%) share/grafx2/gfx2.gif share/icons/grafx2.svg doc/README.txt doc/COMPILING.txt doc/gpl-2.0.txt share/grafx2/fonts/8pxfont.png doc/README-zlib1.txt doc/README-SDL.txt doc/README-SDL_image.txt doc/README-SDL_ttf.txt doc/README-lua.txt share/grafx2/fonts/Tuffy.ttf src-`cat $(OBJDIR:../%=%)/versiontag`.tgz $(PLATFORMFILES:../%=%) + cd .. && $(ZIP) $(ZIPOPT) "grafx2-`cat $(OBJDIR:../%=%)/versiontag`$(TTFLABEL)-$(PLATFORM).$(ZIP)" $(BIN:../%=%) share/grafx2/gfx2def.ini $(SCRIPT_FILES:../%=%) $(SCRIPTLIB_FILES:../%=%) $(SKIN_FILES:../%=%) share/grafx2/gfx2.gif share/icons/grafx2.svg doc/README.txt doc/COMPILING.txt doc/gpl-2.0.txt doc/PF_fonts.txt $(FONT_FILES:../%=%) doc/README-zlib1.txt doc/README-SDL.txt doc/README-SDL_image.txt doc/README-SDL_ttf.txt doc/README-lua.txt src-`cat $(OBJDIR:../%=%)/versiontag`.tgz $(PLATFORMFILES:../%=%) $(DELCOMMAND) "../src-`cat $(OBJDIR)/versiontag`.tgz" - tar cvzf "../grafx2-`cat $(OBJDIR)/versiontag`$(TTFLABEL)-src.tgz" --strip=1 --transform 's,^,grafx2/,g' ../src/*.c ../src/*.h ../src/Makefile ../src/Makefile.dep ../share/grafx2/gfx2def.ini $(SCRIPT_FILES) $(SKIN_FILES) ../src/gfx2.ico ../share/grafx2/gfx2.gif ../share/icons/grafx2.svg ../doc/README.txt ../doc/COMPILING.txt ../doc/gpl-2.0.txt ../misc/unix/grafx2.1 ../misc/unix/grafx2.xpm ../misc/unix/grafx2.desktop ../share/grafx2/fonts/8pxfont.png ../share/grafx2/fonts/Tuffy.ttf + tar cvzf "../grafx2-`cat $(OBJDIR)/versiontag`$(TTFLABEL)-src.tgz" --strip=1 --transform 's,^,grafx2/,g' ../src/*.c ../src/*.h ../src/Makefile ../src/Makefile.dep ../share/grafx2/gfx2def.ini $(SCRIPT_FILES) $(SCRIPTLIB_FILES) $(SKIN_FILES) ../src/gfx2.ico ../share/grafx2/gfx2.gif ../share/icons/grafx2.svg ../doc/README.txt ../doc/COMPILING.txt ../doc/gpl-2.0.txt ../doc/PF_fonts.txt ../misc/unix/grafx2.1 ../misc/unix/grafx2.xpm ../misc/unix/grafx2.desktop $(FONT_FILES) $(DELCOMMAND) "$(OBJDIR)/versiontag" testsed : @@ -400,8 +455,9 @@ install : $(BIN) test -d $(DESTDIR)$(datadir)/grafx2/fonts || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/fonts test -d $(DESTDIR)$(datadir)/grafx2/skins || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/skins test -d $(DESTDIR)$(datadir)/grafx2/scripts || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/scripts + test -d $(DESTDIR)$(datadir)/grafx2/scripts/libs || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/scripts/libs test -d $(DESTDIR)$(datadir)/applications || $(MKDIR) $(DESTDIR)$(datadir)/applications - test -d $(DESTDIR)$(datadir)/icons || $(MKDIR) $(DESTDIR)$(datadir)/icons + test -d $(DESTDIR)$(pixmapdir) || $(MKDIR) $(DESTDIR)$(pixmapdir) # Copy files $(CP) $(BIN) $(DESTDIR)$(bindir) $(CP) ../share/grafx2/gfx2def.ini $(DESTDIR)$(datadir)/grafx2/ @@ -409,10 +465,11 @@ install : $(BIN) $(CP) ../share/grafx2/fonts/* $(DESTDIR)$(datadir)/grafx2/fonts/ $(CP) $(SKIN_FILES) $(DESTDIR)$(datadir)/grafx2/skins/ $(CP) $(SCRIPT_FILES) $(DESTDIR)$(datadir)/grafx2/scripts/ + $(CP) $(SCRIPTLIB_FILES) $(DESTDIR)$(datadir)/grafx2/scripts/libs/ # Icon and desktop file for debian $(CP) ../misc/unix/grafx2.desktop $(DESTDIR)$(datadir)/applications/ - $(CP) ../misc/unix/grafx2.xpm $(DESTDIR)$(datadir)/icons/ - $(CP) ../share/icons/grafx2.svg $(DESTDIR)$(datadir)/icons/ + $(CP) ../misc/unix/grafx2.xpm $(DESTDIR)$(pixmapdir) + $(CP) ../share/icons/grafx2.svg $(DESTDIR)$(pixmapdir) @echo Install complete # Linux uninstallation of the program @@ -424,13 +481,15 @@ uninstall : $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/fonts),,$(RMDIR) $(DESTDIR)$(datadir)/grafx2/fonts) $(DELCOMMAND) $(SKIN_FILES:../share%=$(DESTDIR)$(datadir)%) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/skins),,$(RMDIR) $(DESTDIR)$(datadir)/grafx2/skins) + $(DELCOMMAND) $(SCRIPTLIB_FILES:../share%=$(DESTDIR)$(datadir)%) + $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/scripts/libs),,$(RMDIR) $(DESTDIR)$(datadir)/grafx2/scripts/libs) $(DELCOMMAND) $(SCRIPT_FILES:../share%=$(DESTDIR)$(datadir)%) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/scripts),,$(RMDIR) $(DESTDIR)$(datadir)/grafx2/scripts) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2),,$(RMDIR) $(DESTDIR)$(datadir)/grafx2) # Icon and desktop file for debian $(DELCOMMAND) $(DESTDIR)$(datadir)/applications/grafx2.desktop - $(DELCOMMAND) $(DESTDIR)$(datadir)/icons/grafx2.xpm - $(DELCOMMAND) $(DESTDIR)$(datadir)/icons/grafx2.svg + $(DELCOMMAND) $(DESTDIR)$(pixmapdir)/grafx2.xpm + $(DELCOMMAND) $(DESTDIR)$(pixmapdir)/grafx2.svg @echo Uninstall complete endif diff --git a/src/Makefile.dep b/src/Makefile.dep index 73930c02..27c8461b 100644 --- a/src/Makefile.dep +++ b/src/Makefile.dep @@ -1,3 +1,4 @@ +$(OBJDIR)/SFont.o: SFont.c SFont.h $(OBJDIR)/brush.o: brush.c global.h struct.h const.h graph.h misc.h errors.h \ windows.h sdlscreen.h brush.h $(OBJDIR)/brush_ops.o: brush_ops.c brush.h struct.h const.h buttons.h engine.h \ @@ -5,12 +6,13 @@ $(OBJDIR)/brush_ops.o: brush_ops.c brush.h struct.h const.h buttons.h engine.h \ $(OBJDIR)/buttons.o: buttons.c const.h struct.h global.h misc.h graph.h engine.h \ readline.h filesel.h loadsave.h init.h buttons.h operatio.h pages.h \ palette.h errors.h readini.h saveini.h shade.h io.h help.h text.h \ - sdlscreen.h windows.h brush.h input.h special.h + sdlscreen.h windows.h brush.h input.h special.h setup.h $(OBJDIR)/buttons_effects.o: buttons_effects.c buttons.h struct.h const.h engine.h \ - global.h graph.h help.h input.h misc.h readline.h sdlscreen.h windows.h + global.h graph.h help.h input.h misc.h readline.h sdlscreen.h windows.h \ + brush.h $(OBJDIR)/engine.o: engine.c const.h struct.h global.h graph.h misc.h special.h \ buttons.h operatio.h shade.h errors.h sdlscreen.h windows.h brush.h \ - input.h engine.h pages.h layers.h + input.h engine.h pages.h layers.h factory.h loadsave.h io.h $(OBJDIR)/factory.o: factory.c brush.h struct.h const.h buttons.h engine.h errors.h \ filesel.h loadsave.h global.h graph.h io.h misc.h pages.h readline.h \ sdlscreen.h windows.h palette.h input.h help.h @@ -21,7 +23,8 @@ $(OBJDIR)/filesel.o: filesel.c const.h struct.h global.h misc.h errors.h io.h \ help.h filesel.h $(OBJDIR)/graph.o: graph.c global.h struct.h const.h engine.h buttons.h pages.h \ errors.h sdlscreen.h graph.h misc.h pxsimple.h pxtall.h pxwide.h \ - pxdouble.h pxtriple.h pxwide2.h pxtall2.h pxquad.h windows.h input.h + pxdouble.h pxtriple.h pxwide2.h pxtall2.h pxquad.h windows.h input.h \ + brush.h $(OBJDIR)/help.o: help.c const.h struct.h global.h misc.h engine.h helpfile.h \ help.h sdlscreen.h text.h keyboard.h windows.h input.h hotkeys.h \ errors.h pages.h @@ -29,9 +32,9 @@ $(OBJDIR)/hotkeys.o: hotkeys.c struct.h const.h global.h hotkeys.h $(OBJDIR)/init.o: init.c buttons.h struct.h const.h errors.h global.h graph.h \ init.h io.h factory.h help.h hotkeys.h keyboard.h loadsave.h misc.h \ mountlist.h operatio.h palette.h sdlscreen.h setup.h transform.h \ - windows.h layers.h + windows.h layers.h special.h $(OBJDIR)/input.o: input.c global.h struct.h const.h keyboard.h sdlscreen.h \ - windows.h errors.h misc.h input.h + windows.h errors.h misc.h buttons.h input.h loadsave.h $(OBJDIR)/io.o: io.c struct.h const.h io.h realpath.h $(OBJDIR)/keyboard.o: keyboard.c global.h struct.h const.h keyboard.h $(OBJDIR)/layers.o: layers.c const.h struct.h global.h windows.h engine.h pages.h \ @@ -39,18 +42,20 @@ $(OBJDIR)/layers.o: layers.c const.h struct.h global.h windows.h engine.h pages. $(OBJDIR)/libraw2crtc.o: libraw2crtc.c const.h global.h struct.h loadsave.h $(OBJDIR)/loadsave.o: loadsave.c buttons.h struct.h const.h errors.h global.h io.h \ loadsave.h misc.h graph.h op_c.h pages.h palette.h sdlscreen.h windows.h \ - engine.h + engine.h brush.h setup.h $(OBJDIR)/main.o: main.c const.h struct.h global.h graph.h misc.h init.h buttons.h \ engine.h pages.h loadsave.h sdlscreen.h errors.h readini.h saveini.h \ - io.h text.h setup.h windows.h brush.h palette.h realpath.h + io.h text.h setup.h windows.h brush.h palette.h realpath.h input.h $(OBJDIR)/misc.o: misc.c struct.h const.h sdlscreen.h global.h errors.h buttons.h \ engine.h misc.h keyboard.h windows.h palette.h input.h graph.h pages.h $(OBJDIR)/miscfileformats.o: miscfileformats.c engine.h struct.h const.h errors.h \ global.h io.h libraw2crtc.h loadsave.h misc.h sdlscreen.h windows.h -$(OBJDIR)/mountlist.o: mountlist.c mountlist.h -$(OBJDIR)/op_c.o: op_c.c op_c.h struct.h const.h errors.h +$(OBJDIR)/mountlist.o: mountlist.c +$(OBJDIR)/op_c.o: op_c.c op_c.h struct.h const.h errors.h global.h engine.h \ + windows.h $(OBJDIR)/operatio.o: operatio.c const.h struct.h global.h misc.h engine.h graph.h \ - operatio.h buttons.h pages.h errors.h sdlscreen.h brush.h windows.h + operatio.h buttons.h pages.h errors.h sdlscreen.h brush.h windows.h \ + input.h $(OBJDIR)/pages.o: pages.c global.h struct.h const.h pages.h errors.h loadsave.h \ misc.h windows.h $(OBJDIR)/palette.o: palette.c const.h struct.h global.h misc.h engine.h readline.h \ @@ -63,34 +68,35 @@ $(OBJDIR)/pxquad.o: pxquad.c global.h struct.h const.h sdlscreen.h misc.h graph. pxquad.h $(OBJDIR)/pxsimple.o: pxsimple.c global.h struct.h const.h sdlscreen.h misc.h \ graph.h pxsimple.h -$(OBJDIR)/pxtall2.o: pxtall2.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ - pxtall2.h $(OBJDIR)/pxtall.o: pxtall.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ pxtall.h pxsimple.h +$(OBJDIR)/pxtall2.o: pxtall2.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ + pxtall2.h $(OBJDIR)/pxtriple.o: pxtriple.c global.h struct.h const.h sdlscreen.h misc.h \ graph.h pxtriple.h -$(OBJDIR)/pxwide2.o: pxwide2.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ - pxwide2.h $(OBJDIR)/pxwide.o: pxwide.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ pxwide.h -$(OBJDIR)/readini.o: readini.c const.h errors.h global.h struct.h misc.h readini.h +$(OBJDIR)/pxwide2.o: pxwide2.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ + pxwide2.h +$(OBJDIR)/readini.o: readini.c const.h errors.h global.h struct.h misc.h readini.h \ + setup.h $(OBJDIR)/readline.o: readline.c const.h struct.h global.h misc.h errors.h \ sdlscreen.h readline.h windows.h input.h $(OBJDIR)/realpath.o: realpath.c $(OBJDIR)/saveini.o: saveini.c const.h global.h struct.h readini.h io.h errors.h \ - misc.h saveini.h + misc.h saveini.h setup.h $(OBJDIR)/sdlscreen.o: sdlscreen.c global.h struct.h const.h sdlscreen.h errors.h \ misc.h $(OBJDIR)/setup.o: setup.c struct.h const.h io.h setup.h -$(OBJDIR)/SFont.o: SFont.c SFont.h $(OBJDIR)/shade.o: shade.c global.h struct.h const.h graph.h engine.h errors.h \ misc.h readline.h help.h sdlscreen.h windows.h input.h shade.h $(OBJDIR)/special.o: special.c const.h struct.h global.h graph.h engine.h windows.h \ special.h pages.h misc.h buttons.h $(OBJDIR)/text.o: text.c SFont.h struct.h const.h global.h sdlscreen.h io.h \ - errors.h + errors.h windows.h misc.h setup.h +$(OBJDIR)/tiles.o: tiles.c $(OBJDIR)/transform.o: transform.c global.h struct.h const.h transform.h engine.h \ sdlscreen.h windows.h input.h help.h misc.h readline.h buttons.h pages.h $(OBJDIR)/version.o: version.c $(OBJDIR)/windows.o: windows.c windows.h struct.h const.h engine.h errors.h \ - global.h graph.h input.h misc.h readline.h sdlscreen.h + global.h graph.h input.h misc.h op_c.h readline.h sdlscreen.h palette.h diff --git a/src/SFont.c b/src/SFont.c index 0e9a8c95..fef5b17f 100644 --- a/src/SFont.c +++ b/src/SFont.c @@ -69,7 +69,7 @@ static Uint32 GetPixel(SDL_Surface *Surface, Sint32 X, Sint32 Y) SFont_Font* SFont_InitFont(SDL_Surface* Surface) { - int x = 0, i = 0; + int x = 0, i = 33; Uint32 pixel; SFont_Font* Font; Uint32 pink; @@ -78,21 +78,42 @@ SFont_Font* SFont_InitFont(SDL_Surface* Surface) return NULL; Font = (SFont_Font *) malloc(sizeof(SFont_Font)); + memset(Font, 0, sizeof(SFont_Font)); + Font->Surface = Surface; SDL_LockSurface(Surface); - pink = SDL_MapRGB(Surface->format, 255, 0, 255); + pink = GetPixel(Surface, 0, 0); while (x < Surface->w) { - if (GetPixel(Surface, x, 0) == pink) { - Font->CharPos[i++]=x; - while((x < Surface->w) && (GetPixel(Surface, x, 0)== pink)) + if (GetPixel(Surface, x, 0) != pink) { + Font->CharBegin[i]=x; + while((x < Surface->w) && (GetPixel(Surface, x, 0)!= pink)) x++; - Font->CharPos[i++]=x; + Font->CharWidth[i]=x-Font->CharBegin[i]; + i++; } x++; } - Font->MaxPos = x-1; + + // Create lowercase characters, if not present + for (i=0; i <26; i++) + { + if (Font->CharWidth['a'+i]==0) + { + Font->CharBegin['a'+i]=Font->CharBegin['A'+i]; + Font->CharWidth['a'+i]=Font->CharWidth['A'+i]; + } + } + + // Determine space width. + // This strange format doesn't allow font designer to write explicit + // space as a character. + // Rule: A space should be as large as the character " if available, + // or 'a' if it's not. + Font->Space = Font->CharWidth[(int)'"']; + if (Font->Space<2) + Font->Space = Font->CharWidth[(int)'a']; pixel = GetPixel(Surface, 0, Surface->h-1); SDL_UnlockSurface(Surface); @@ -111,7 +132,6 @@ void SFont_Write(SDL_Surface *Surface, const SFont_Font *Font, int x, int y, const char *text) { const char* c; - int charoffset; SDL_Rect srcrect, dstrect; if(text == NULL) @@ -123,42 +143,39 @@ void SFont_Write(SDL_Surface *Surface, const SFont_Font *Font, srcrect.h = dstrect.h = Font->Surface->h - 1; for(c = text; *c != '\0' && x <= Surface->w ; c++) { - charoffset = ((int) (*c - 33)) * 2 + 1; // skip spaces and nonprintable characters - if (*c == ' ' || charoffset < 0 || charoffset > Font->MaxPos) { - x += Font->CharPos[2]-Font->CharPos[1]; + if (*c == ' ' || Font->CharWidth[(int)*c]==0) { + x += Font->Space; continue; } - srcrect.w = Font->CharPos[charoffset+2] - Font->CharPos[charoffset]; + srcrect.w = Font->CharWidth[(int)*c]; dstrect.w = srcrect.w; - srcrect.x = Font->CharPos[charoffset]; + srcrect.x = Font->CharBegin[(int)*c]; dstrect.x = x; SDL_BlitSurface(Font->Surface, &srcrect, Surface, &dstrect); - x += Font->CharPos[charoffset+1] - Font->CharPos[charoffset]; + x += Font->CharWidth[(int)*c]; } } int SFont_TextWidth(const SFont_Font *Font, const char *text) { const char* c; - int charoffset=0; int width = 0; if(text == NULL) return 0; for(c = text; *c != '\0'; c++) { - charoffset = ((int) *c - 33) * 2 + 1; // skip spaces and nonprintable characters - if (*c == ' ' || charoffset < 0 || charoffset > Font->MaxPos) { - width += Font->CharPos[2]-Font->CharPos[1]; + if (*c == ' ' || Font->CharWidth[(int)*c]==0) { + width += Font->Space; continue; } - width += Font->CharPos[charoffset+1] - Font->CharPos[charoffset]; + width += Font->CharWidth[(int)*c]; } return width; diff --git a/src/SFont.h b/src/SFont.h index bca5fae2..27a54937 100644 --- a/src/SFont.h +++ b/src/SFont.h @@ -56,8 +56,9 @@ extern "C" { /// and call InitFont( YourFont ); typedef struct { SDL_Surface *Surface; - int CharPos[512]; - int MaxPos; + int CharBegin[256]; + int CharWidth[256]; + int Space; } SFont_Font; /// diff --git a/src/brush.c b/src/brush.c index de28b7fd..bf4c0d39 100644 --- a/src/brush.c +++ b/src/brush.c @@ -587,66 +587,97 @@ void Display_paintbrush(short x,short y,byte color,byte is_preview) } } -/// -/// Changes the Brush size, discarding its previous content. -/// @return 0 OK, 1 Failed -byte Realloc_brush(word new_brush_width, word new_brush_height) +/// @return 0 on success, non-zero on failure (memory?). +/// @param new_brush: Optionally, you can provide an already allocated new +/// brush - otherwise, this function performs the allocation. +/// @param old_brush: If the caller passes NULL, this function will free the old +/// pixel data. If the caller provides the address of a (free) byte +/// pointer, the function will make it point to the original pixel data, +/// in this case it will be the caller's responsibility to free() it +/// (after transferring pixels to Brush, usually). +byte Realloc_brush(word new_brush_width, word new_brush_height, byte *new_brush, byte **old_brush) { - byte return_code=0; + + byte *new_smear_brush; + byte *new_brush_remapped; + word new_smear_brush_width; + word new_smear_brush_height; + byte new_brush_is_provided; + new_brush_is_provided = (new_brush!=NULL); + + if (!new_brush_is_provided) + { + new_brush=(byte *)malloc(((long)new_brush_height)*new_brush_width); + if (new_brush == NULL) + { + Error(0); + if (old_brush) + *old_brush=NULL; + return 1; + } + } + + new_smear_brush_width=(new_brush_width>MAX_PAINTBRUSH_SIZE)?new_brush_width:MAX_PAINTBRUSH_SIZE; + new_smear_brush_height=(new_brush_height>MAX_PAINTBRUSH_SIZE)?new_brush_height:MAX_PAINTBRUSH_SIZE; + new_smear_brush=NULL; + if ( (((long)Smear_brush_height)*Smear_brush_width) != + (((long)new_smear_brush_width)*new_smear_brush_height) ) + { + new_smear_brush=(byte *)malloc(((long)new_smear_brush_height)*new_smear_brush_width); + if (new_smear_brush == NULL) + { + Error(0); + if (old_brush) + *old_brush=NULL; + if (!new_brush_is_provided) + free(new_brush); + return 2; + } + } + new_brush_remapped=NULL; if ( (((long)Brush_height)*Brush_width) != (((long)new_brush_height)*new_brush_width) ) { - free(Brush); - Brush=(byte *)malloc(((long)new_brush_height)*new_brush_width); - if (Brush == NULL) + new_brush_remapped=(byte *)malloc(((long)new_brush_height)*new_brush_width); + if (new_brush_remapped == NULL) { Error(0); - return_code=1; - - Brush=(byte *)malloc(1*1); - if(Brush == NULL) - { - Error(ERROR_MEMORY); - exit(ERROR_MEMORY); - } - new_brush_height=new_brush_width=1; - *Brush=Fore_color; + free(new_smear_brush); + if (old_brush) + *old_brush=NULL; + if (!new_brush_is_provided) + free(new_brush); + return 3; } } + + // All allocations successful: can replace globals Brush_width=new_brush_width; Brush_height=new_brush_height; + Brush_original_back_color=Back_color; - free(Smear_brush); - Smear_brush_width=(Brush_width>MAX_PAINTBRUSH_SIZE)?Brush_width:MAX_PAINTBRUSH_SIZE; - Smear_brush_height=(Brush_height>MAX_PAINTBRUSH_SIZE)?Brush_height:MAX_PAINTBRUSH_SIZE; - Smear_brush=(byte *)malloc(((long)Smear_brush_height)*Smear_brush_width); - - if (Smear_brush == NULL) // Failed to allocate the smear brush + if (new_smear_brush) { - Error(0); - return_code=1; - - free(Brush); - Brush=(byte *)malloc(1*1); - if(Brush == NULL) - { - Error(ERROR_MEMORY); - exit(ERROR_MEMORY); - } - Brush_height=1; - Brush_width=1; - - Smear_brush=(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE); - if(Smear_brush == NULL) - { - Error(ERROR_MEMORY); - exit(ERROR_MEMORY); - } - Smear_brush_height=MAX_PAINTBRUSH_SIZE; - Smear_brush_width=MAX_PAINTBRUSH_SIZE; + free(Smear_brush); + Smear_brush=new_smear_brush; } - return return_code; + Smear_brush_width=new_smear_brush_width; + Smear_brush_height=new_smear_brush_height; + + // Save or free the old brush pixels + if (old_brush) + *old_brush=Brush_original_pixels; + else + free(old_brush); + Brush_original_pixels=new_brush; + // Assign new brush + if (new_brush_remapped) + { + free(Brush); + Brush=new_brush_remapped; + } + return 0; } @@ -828,7 +859,7 @@ void Capture_brush(short start_x,short start_y,short end_x,short end_y,short cle if (start_y+new_brush_height>Main_image_height) new_brush_height=Main_image_height-start_y; - if (Realloc_brush(new_brush_width, new_brush_height) != 0) + if (Realloc_brush(new_brush_width, new_brush_height, NULL, NULL)) return; // Unable to allocate the new brush, keep the old one. Copy_image_to_brush(start_x,start_y,Brush_width,Brush_height,Main_image_width); @@ -843,6 +874,10 @@ void Capture_brush(short start_x,short start_y,short end_x,short end_y,short cle } Update_part_of_screen(start_x,start_y,Brush_width,Brush_height); } + // Grab palette + memcpy(Brush_original_palette, Main_palette,sizeof(T_Palette)); + // Remap (no change) + Remap_brush(); // On centre la prise sur la brosse Brush_offset_X=(Brush_width>>1); @@ -851,32 +886,25 @@ void Capture_brush(short start_x,short start_y,short end_x,short end_y,short cle } -void Rotate_90_deg() +void Rotate_90_deg(void) { - short temp; - byte * new_brush; - - new_brush=(byte *)malloc(((size_t)Brush_height)*Brush_width); - if (new_brush) + byte * old_brush; + + if (Realloc_brush(Brush_height, Brush_width, NULL, &old_brush)) { - Rotate_90_deg_lowlevel(Brush,new_brush,Brush_width,Brush_height); - free(Brush); - Brush=new_brush; - - temp=Brush_width; - Brush_width=Brush_height; - Brush_height=temp; - - temp=Smear_brush_width; - Smear_brush_width=Smear_brush_height; - Smear_brush_height=temp; - - // On centre la prise sur la brosse - Brush_offset_X=(Brush_width>>1); - Brush_offset_Y=(Brush_height>>1); - } - else Error(0); + return; + } + Rotate_90_deg_lowlevel(old_brush,Brush_original_pixels,Brush_height,Brush_width); + + free(old_brush); + + // Remap according to the last used remap table + Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); + + // On centre la prise sur la brosse + Brush_offset_X=(Brush_width>>1); + Brush_offset_Y=(Brush_height>>1); } @@ -884,34 +912,45 @@ void Remap_brush(void) { short x_pos; // Variable de balayage de la brosse short y_pos; // Variable de balayage de la brosse - byte used[256]; // Tableau de booléens "La couleur est utilisée" int color; // On commence par initialiser le tableau de booléens à faux for (color=0;color<=255;color++) - used[color]=0; + Brush_colormap[color]=0; // On calcule la table d'utilisation des couleurs for (y_pos=0;y_pos>1); - Brush_offset_Y=(Brush_height>>1); - - free(temp); // Libération de l'ancienne brosse - temp = NULL; - - // Réallocation d'un buffer de Smear - free(Smear_brush); - Smear_brush_width=(Brush_width>MAX_PAINTBRUSH_SIZE)?Brush_width:MAX_PAINTBRUSH_SIZE; - Smear_brush_height=(Brush_height>MAX_PAINTBRUSH_SIZE)?Brush_height:MAX_PAINTBRUSH_SIZE; - Smear_brush=(byte *)malloc(((long)Smear_brush_width)*Smear_brush_height); + // 2ème balayage (vertical) + for (x_pos=1; x_pos>1); + Brush_offset_Y=(Brush_height>>1); + + free(old_brush); // Libération de l'ancienne brosse + } @@ -1039,112 +1071,105 @@ void Nibble_brush(void) { long x_pos,y_pos; byte state; - byte * new_brush; - byte * temp; - word width; - word height; + byte * old_brush; + word old_width; + word old_height; + int i; if ( (Brush_width>2) && (Brush_height>2) ) { - width=Brush_width-2; - height=Brush_height-2; - new_brush=(byte *)malloc(((long)width)*height); - - if (new_brush) + old_width=Brush_width; + old_height=Brush_height; + + SWAP_PBYTES(Brush, Brush_original_pixels); + if (Realloc_brush(Brush_width-2, Brush_height-2, NULL, &old_brush)) { - // On copie la brosse courante dans la nouvelle - Copy_part_of_image_to_another(Brush, // source - 1, - 1, - width, - height, - Brush_width, - new_brush, // Destination - 0, - 0, - width); + Error(0); + SWAP_PBYTES(Brush, Brush_original_pixels); + return; + } + // On copie l'ancienne brosse dans la nouvelle + Copy_part_of_image_to_another(old_brush, // source + 1, + 1, + old_width-2, + old_height-2, + old_width, + Brush, // Destination + 0, + 0, + Brush_width); - // On intervertit la nouvelle et l'ancienne brosse: - temp=Brush; - Brush=new_brush; - Brush_width-=2; - Brush_height-=2; - width+=2; - height+=2; - - // 1er balayage (horizontal) - for (y_pos=0; y_pos0) - Pixel_in_brush(x_pos-1,y_pos,Back_color); - state=0; - } - } - else - { - if (state == 0) - { - Pixel_in_brush(x_pos,y_pos,Back_color); - state=1; - } - } - } - // Cas du dernier pixel à droite de la ligne - if (temp[((y_pos+1)*width)+x_pos+1]==Back_color) - Pixel_in_brush(x_pos-1,y_pos,Back_color); - } - - // 2ème balayage (vertical) + // 1er balayage (horizontal) + for (y_pos=0; y_pos0) - Pixel_in_brush(x_pos,y_pos-1,Back_color); - state=0; - } - } - else - { - if (state == 0) - { - Pixel_in_brush(x_pos,y_pos,Back_color); - state=1; - } + if (x_pos>0) + Pixel_in_brush(x_pos-1,y_pos,Back_color); + state=0; + } + } + else + { + if (state == 0) + { + Pixel_in_brush(x_pos,y_pos,Back_color); + state=1; } } - // Cas du dernier pixel en bas de la colonne - if (temp[((y_pos+1)*width)+x_pos+1]==Back_color) - Pixel_in_brush(x_pos,y_pos-1,Back_color); } - - // On recentre la prise sur la brosse - Brush_offset_X=(Brush_width>>1); - Brush_offset_Y=(Brush_height>>1); - - free(temp); // Libération de l'ancienne brosse - temp = NULL; - - // Réallocation d'un buffer de Smear - free(Smear_brush); - Smear_brush_width=(Brush_width>MAX_PAINTBRUSH_SIZE)?Brush_width:MAX_PAINTBRUSH_SIZE; - Smear_brush_height=(Brush_height>MAX_PAINTBRUSH_SIZE)?Brush_height:MAX_PAINTBRUSH_SIZE; - Smear_brush=(byte *)malloc(((long)Smear_brush_width)*Smear_brush_height); + // Cas du dernier pixel à droite de la ligne + if (old_brush[((y_pos+1)*old_width)+x_pos+1]==Back_color) + Pixel_in_brush(x_pos-1,y_pos,Back_color); } - else - Error(0); // Pas assez de mémoire! + + // 2ème balayage (vertical) + for (x_pos=0; x_pos0) + Pixel_in_brush(x_pos,y_pos-1,Back_color); + state=0; + } + } + else + { + if (state == 0) + { + Pixel_in_brush(x_pos,y_pos,Back_color); + state=1; + } + } + } + // Cas du dernier pixel en bas de la colonne + if (old_brush[((y_pos+1)*old_width)+x_pos+1]==Back_color) + Pixel_in_brush(x_pos,y_pos-1,Back_color); + } + + free(old_brush); + // Adopt the current palette. + memcpy(Brush_original_palette, Main_palette,sizeof(T_Palette)); + memcpy(Brush_original_pixels, Brush, (long)Brush_width*Brush_height); + for (i=0; i<256; i++) + Brush_colormap[i]=i; + //-- + + // On recentre la prise sur la brosse + Brush_offset_X=(Brush_width>>1); + Brush_offset_Y=(Brush_height>>1); + } } @@ -1162,7 +1187,6 @@ void Capture_brush_with_lasso(int vertices, short * points,short clear) word new_brush_width; word new_brush_height; - // On recherche les bornes de la brosse: for (temp=0; temp<2*vertices; temp+=2) { @@ -1204,46 +1228,15 @@ void Capture_brush_with_lasso(int vertices, short * points,short clear) new_brush_width=(end_x-start_x)+1; new_brush_height=(end_y-start_y)+1; - if ( (((long)Brush_height)*Brush_width) != - (((long)new_brush_height)*new_brush_width) ) - { - free(Brush); - Brush=(byte *)malloc(((long)new_brush_height)*new_brush_width); - if (!Brush) - { - Error(0); - - Brush=(byte *)malloc(1*1); - if(Brush==NULL) Error(ERROR_MEMORY); - new_brush_height=new_brush_width=1; - *Brush=Fore_color; - } - } - Brush_width=new_brush_width; - Brush_height=new_brush_height; - - free(Smear_brush); - Smear_brush_width=(Brush_width>MAX_PAINTBRUSH_SIZE)?Brush_width:MAX_PAINTBRUSH_SIZE; - Smear_brush_height=(Brush_height>MAX_PAINTBRUSH_SIZE)?Brush_height:MAX_PAINTBRUSH_SIZE; - Smear_brush=(byte *)malloc(((long)Smear_brush_height)*Smear_brush_width); - - if (!Smear_brush) // On ne peut même pas allouer la brosse du smear! + if (Realloc_brush(new_brush_width, new_brush_height, NULL, NULL)) { Error(0); - - free(Brush); - Brush=(byte *)malloc(1*1); - if(Brush==NULL) Error(ERROR_MEMORY); - Brush_height=1; - Brush_width=1; - - Smear_brush=(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE); - Smear_brush_height=MAX_PAINTBRUSH_SIZE; - Smear_brush_width=MAX_PAINTBRUSH_SIZE; + return; } Brush_offset_X=start_x; Brush_offset_Y=start_y; + Pixel_figure=Pixel_figure_in_brush; memset(Brush,Back_color,(long)Brush_width*Brush_height); @@ -1271,6 +1264,13 @@ void Capture_brush_with_lasso(int vertices, short * points,short clear) if (clear) Pixel_in_current_screen(x_pos,y_pos,Back_color,0); } + // Grab palette + memcpy(Brush_original_palette, Main_palette,sizeof(T_Palette)); + // Init colormap + for (temp=0; temp<256; temp++) + Brush_colormap[temp]=temp; + // Copy Brush to original + memcpy(Brush_original_pixels, Brush, (long)Brush_width*Brush_height); // On centre la prise sur la brosse Brush_offset_X=(Brush_width>>1); @@ -1304,50 +1304,27 @@ void Stretch_brush(short x1, short y1, short x2, short y2) } new_brush_height++; - // Free some memory - free(Smear_brush); - Smear_brush = NULL; - - if ((new_brush=((byte *)malloc(new_brush_width*new_brush_height)))) + new_brush=((byte *)malloc(new_brush_width*new_brush_height)); + if (!new_brush) { - Rescale(Brush, Brush_width, Brush_height, new_brush, new_brush_width, new_brush_height, x2MAX_PAINTBRUSH_SIZE)?Brush_width:MAX_PAINTBRUSH_SIZE; - Smear_brush_height=(Brush_height>MAX_PAINTBRUSH_SIZE)?Brush_height:MAX_PAINTBRUSH_SIZE; - Smear_brush=(byte *)malloc(((long)Smear_brush_height)*Smear_brush_width); - - if (!Smear_brush) // On ne peut même pas allouer la brosse du smear! - { - Error(0); - - free(Brush); - Brush=(byte *)malloc(1*1); - Brush_height=1; - Brush_width=1; - - Smear_brush=(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE); - Smear_brush_height=MAX_PAINTBRUSH_SIZE; - Smear_brush_width=MAX_PAINTBRUSH_SIZE; - } - - Brush_offset_X=(Brush_width>>1); - Brush_offset_Y=(Brush_height>>1); - } - else - { - // Ici la libération de mémoire n'a pas suffi donc on remet dans l'état - // où c'etait avant. On a juste à réallouer la Smear_brush car il y a - // normalement la place pour elle puisque rien d'autre n'a pu être alloué - // entre temps. - Smear_brush=(byte *)malloc(((long)Smear_brush_height)*Smear_brush_width); Error(0); + return; } + + Rescale(Brush_original_pixels, Brush_width, Brush_height, new_brush, new_brush_width, new_brush_height, x2>1); + Brush_offset_Y=(Brush_height>>1); + } @@ -1578,9 +1555,6 @@ void Distort_brush(short x1, short y1, short x2, short y2, short x3, short y3, s short min_x, max_x, min_y, max_y; short width, height; byte * new_brush; - byte * new_smear_brush; - short new_smear_brush_width; - short new_smear_brush_height; // Move all coordinates to start on (0,0) min_x=Min4(x1,x2,x3,x4); @@ -1601,24 +1575,11 @@ void Distort_brush(short x1, short y1, short x2, short y2, short x3, short y3, s width=Max(max_x-min_x, 1); height=Max(max_y-min_y, 1); - new_smear_brush_width=(width>MAX_PAINTBRUSH_SIZE)?width:MAX_PAINTBRUSH_SIZE; - new_smear_brush_height=(height>MAX_PAINTBRUSH_SIZE)?height:MAX_PAINTBRUSH_SIZE; - - new_smear_brush=(byte *)malloc(((long)new_smear_brush_height)*new_smear_brush_width); - if (! new_smear_brush) - { - // Out of memory while allocating new smear brush - Error(0); - return; - } - new_brush=((byte *)malloc((long)width*height)); if (!new_brush) { // Out of memory while allocating new brush Error(0); - free(new_smear_brush); - new_smear_brush = NULL; return; } @@ -1631,18 +1592,14 @@ void Distort_brush(short x1, short y1, short x2, short y2, short x3, short y3, s Distort_buffer_width=width; Draw_brush_linear_distort(0, 0, (Brush_width<<16), (Brush_height<<16), (x1<<16), (y1<<16), (x2<<16), (y2<<16), (x3<<16), (y3<<16), (x4<<16), (y4<<16)); - // Free old brushes - free(Smear_brush); - free(Brush); - - // Point to the new ones - Brush=new_brush; - Brush_width=width; - Brush_height=height; - - Smear_brush=new_smear_brush; - Smear_brush_width=new_smear_brush_width; - Smear_brush_height=new_smear_brush_height; + if (Realloc_brush(width, height, new_brush, NULL)) + { + free(new_brush); + Error(0); + return; + } + // Remap according to the last used remap table + Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); // Re-center brush handle Brush_offset_X=(Brush_width>>1); @@ -1867,7 +1824,7 @@ void Compute_quad_texture(int x1,int y1,int xt1,int yt1, xt=Round((float)(ScanY_Xt[0][y])+(temp*(ScanY_Xt[1][y]-ScanY_Xt[0][y]))); yt=Round((float)(ScanY_Yt[0][y])+(temp*(ScanY_Yt[1][y]-ScanY_Yt[0][y]))); if (xt>=0 && yt>=0) - buffer[x+(y*width)]=Read_pixel_from_brush(xt,yt); + buffer[x+(y*width)]=*(Brush_original_pixels + yt * Brush_width + xt); } for (; xMAX_PAINTBRUSH_SIZE)?Brush_width:MAX_PAINTBRUSH_SIZE; - Smear_brush_height=(Brush_height>MAX_PAINTBRUSH_SIZE)?Brush_height:MAX_PAINTBRUSH_SIZE; - Smear_brush=(byte *)malloc(((long)Smear_brush_height)*Smear_brush_width); - - if (!Smear_brush) // On ne peut même pas allouer la brosse du smear! - { - Error(0); - - free(Brush); - Brush=(byte *)malloc(1*1); - Brush_height=1; - Brush_width=1; - - Smear_brush=(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE); - Smear_brush_height=MAX_PAINTBRUSH_SIZE; - Smear_brush_width=MAX_PAINTBRUSH_SIZE; - } - - Brush_offset_X=(Brush_width>>1); - Brush_offset_Y=(Brush_height>>1); - } - else - { - // Ici la libération de mémoire n'a pas suffit donc on remet dans l'état - // où c'etait avant. On a juste à réallouer la Smear_brush car il y a - // normalement la place pour elle puisque rien d'autre n'a pu être alloué - // entre temps. - Smear_brush=(byte *)malloc(((long)Smear_brush_height)*Smear_brush_width); Error(0); + return; } + // Et maintenant on calcule la nouvelle brosse tournée. + Compute_quad_texture(x1,y1, 0, 0, + x2,y2,Brush_width-1, 0, + x3,y3, 0,Brush_height-1, + x4,y4,Brush_width-1,Brush_height-1, + new_brush,new_brush_width,new_brush_height); + + if (Realloc_brush(new_brush_width, new_brush_height, new_brush, NULL)) + { + free(new_brush); + return; + } + // Remap according to the last used remap table + Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); + + // Center offsets + Brush_offset_X=(Brush_width>>1); + Brush_offset_Y=(Brush_height>>1); + } @@ -2090,3 +2025,25 @@ void Rotate_brush_preview(float angle) end_y=Max(Max(y1,y2),Max(y3,y4)); Update_part_of_screen(start_x,start_y,end_x-start_x+1,end_y-start_y+1); } +/* +/// Sets brush's original palette and color mapping. +void Brush_set_palette(T_Palette *palette) +{ + int i; + byte need_remap; + + need_remap=0; + + memcpy(Brush_original_palette,palette,sizeof(T_Palette)); + for (i=0;i<256;i++) + { + if (Brush_original_palette[i].R!=Main_palette[i].R + || Brush_original_palette[i].G!=Main_palette[i].G + || Brush_original_palette[i].B!=Main_palette[i].B) + { + need_remap=1; + } + } + +} +*/ \ No newline at end of file diff --git a/src/brush.h b/src/brush.h index 7369cd6d..9682b1fe 100644 --- a/src/brush.h +++ b/src/brush.h @@ -111,10 +111,19 @@ void Capture_brush_with_lasso(int vertices, short * points,short clear); /// -/// Changes the Brush size, discarding its previous content. -/// @return 0 OK, 1 Failed -byte Realloc_brush(word new_brush_width, word new_brush_height); +/// Changes the Brush size. +/// @return 0 on success, non-zero on failure (memory?). +/// @param new_brush: Optionally, you can provide an already allocated new +/// brush - otherwise, this function performs the allocation. +/// @param old_brush: If the caller passes NULL, this function will free the old +/// pixel data. If the caller provides the address of a (free) byte +/// pointer, the function will make it point to the original pixel data, +/// in this case it will be the caller's responsibility to free() it +/// (after transferring pixels to Brush, usually). +byte Realloc_brush(word new_brush_width, word new_brush_height, byte *new_brush, byte **old_brush); +/// Sets brush's original palette and color mapping. +void Brush_set_palette(T_Palette *palette); #endif diff --git a/src/brush_ops.c b/src/brush_ops.c index 79ba4710..405ca753 100644 --- a/src/brush_ops.c +++ b/src/brush_ops.c @@ -38,7 +38,7 @@ #include "sdlscreen.h" #include "windows.h" -#if defined(__VBCC__)||defined(__GP2X__) +#if defined(__VBCC__) || defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) #define M_PI 3.141592653589793238462643 #endif @@ -251,6 +251,106 @@ void Colorpicker_0_1(void) Unselect_button(BUTTON_COLORPICKER); } +/////////////////////////////////////////////////////////// OPERATION_RMB_COLORPICK + + +byte Rightclick_colorpick(byte cursor_visible) +{ + // Check if the rightclick colorpick should take over: + if (!Config.Right_click_colorpick) + return 0; + if (Mouse_K!=RIGHT_SIDE) + return 0; + // In these modes, the Foreground color is ignored, + // so the RMB should act as normal. + if (Shade_mode||Quick_shade_mode||Tiling_mode) + return 0; + + Colorpicker_color=-1; + Colorpicker_X=-1; + Colorpicker_Y=-1; + + if (cursor_visible) + Hide_cursor(); + Start_operation_stack(OPERATION_RMB_COLORPICK); + + Init_start_operation(); + + // Just an indicator to go to next step + Operation_push(1); + Rightclick_colorpick_2_1(); + + if (cursor_visible) + Display_cursor(); + + return 1; +} + +void Rightclick_colorpick_2_1(void) +// +// Opération : OPERATION_RMB_COLORPICK +// Click Souris: 2 +// Taille_Pile : 1 +// +// Souris effacée: Non +// +{ + char str[4]; + + if ( (Colorpicker_X!=Paintbrush_X) + || (Colorpicker_Y!=Paintbrush_Y) ) + { + if ( (Paintbrush_X>=0) && (Paintbrush_Y>=0) + && (Paintbrush_X=Main_X_zoom) ) ) + Print_in_menu("X: Y: ",0); + + Print_coordinates(); + + Display_cursor(); +} ////////////////////////////////////////////////////// OPERATION_GRAB_BRUSH @@ -858,6 +958,10 @@ void Rotate_brush_1_5(void) Operation_pop(&old_y); Operation_pop(&old_x); + // On corrige les coordonnées de la ligne si la touche shift est appuyée... + if(SDL_GetModState() & KMOD_SHIFT) + Clamp_coordinates_regular_angle(Brush_rotation_center_X,Brush_rotation_center_Y,&Paintbrush_X,&Paintbrush_Y); + if ( (Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y) || (prev_state!=2) ) { if ( (Brush_rotation_center_X==Paintbrush_X) @@ -921,6 +1025,10 @@ void Rotate_brush_0_5(void) Operation_pop(&old_y); Operation_pop(&old_x); + // On corrige les coordonnées de la ligne si la touche shift est appuyée... + if(SDL_GetModState() & KMOD_SHIFT) + Clamp_coordinates_regular_angle(Brush_rotation_center_X,Brush_rotation_center_Y,&Paintbrush_X,&Paintbrush_Y); + if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y) || (prev_state!=3)) { if ( (Brush_rotation_center_X==Paintbrush_X) diff --git a/src/buttons.c b/src/buttons.c index 7e7ca04b..d483ea53 100644 --- a/src/buttons.c +++ b/src/buttons.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Yves Rizoud Copyright 2007-2010 Adrien Destugues (PulkoMandy) Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) @@ -72,11 +73,28 @@ #include "brush.h" #include "input.h" #include "special.h" +#include "setup.h" #ifdef __VBCC__ #define __attribute__(x) #endif +#if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) + #include + #include + #define isHidden(x) (0) +#elif defined(__MINT__) + #include + #include + #define isHidden(x) (0) +#elif defined(__WIN32__) + #include + #include + #define isHidden(x) (GetFileAttributesA((x)->d_name)&FILE_ATTRIBUTE_HIDDEN) +#else + #include + #define isHidden(x) ((x)->d_name[0]=='.') +#endif extern char Program_version[]; // generated in pversion.c @@ -162,7 +180,8 @@ void Button_Message_initial(void) Display_cursor(); - while(!Mouse_K && !Key) if(!Get_input()) SDL_Delay(20); + while(!Mouse_K && !Key) + Get_input(20); if (Mouse_K) Wait_end_of_click(); @@ -204,7 +223,7 @@ void Button_Undo(void) Display_all_screen(); Unselect_button(BUTTON_UNDO); - Draw_menu_button_frame(BUTTON_MAGNIFIER,Main_magnifier_mode); + Draw_menu_button(BUTTON_MAGNIFIER,Main_magnifier_mode); Display_menu(); Display_cursor(); } @@ -219,7 +238,7 @@ void Button_Redo(void) Display_all_screen(); Unselect_button(BUTTON_UNDO); - Draw_menu_button_frame(BUTTON_MAGNIFIER,Main_magnifier_mode); + Draw_menu_button(BUTTON_MAGNIFIER,Main_magnifier_mode); Display_menu(); Display_cursor(); } @@ -332,8 +351,7 @@ void Button_Select_forecolor(void) // Wait loop after initial click while(Mouse_K) { - if(!Get_input()) - SDL_Delay(20); + Get_input(20); if (Button_under_mouse()==BUTTON_CHOOSE_COL) { @@ -369,8 +387,7 @@ void Button_Select_backcolor(void) // Wait loop after initial click do { - if(!Get_input()) - SDL_Delay(20); + Get_input(20); if (Button_under_mouse()==BUTTON_CHOOSE_COL) break; // This will repeat this button's action @@ -759,6 +776,13 @@ const T_Lookup Lookup_MouseSpeed[] = { {NULL,-1}, }; +const T_Lookup Lookup_SwapButtons[] = { + {"None",0}, + {"Control",MOD_CTRL}, + {"Alt",MOD_ALT}, + {NULL,-1}, +}; + typedef struct { const char* Label; byte Type; // 0: label, 1+: setting (size in bytes) @@ -916,8 +940,7 @@ void Button_Settings(void) T_Setting setting[SETTING_PER_PAGE*SETTING_PAGES] = { - {" --- GUI ---",0,NULL,0,0,0,NULL}, - {"",0,NULL,0,0,0,NULL}, + {" --- GUI ---",0,NULL,0,0,0,NULL}, {"Opening message:",1,&(selected_config.Opening_message),0,1,0,Lookup_YesNo}, {"Menu ratio adapt:",1,&(selected_config.Ratio),0,1,0,Lookup_MenuRatio}, {"Draw limits:",1,&(selected_config.Display_image_limits),0,1,0,Lookup_YesNo}, @@ -925,11 +948,11 @@ void Button_Settings(void) {"Separate colors:",1,&(selected_config.Separate_colors),0,1,0,Lookup_YesNo}, {"Safety colors:",1,&(selected_config.Safety_colors),0,1,0,Lookup_YesNo}, {"Grid XOR color:",1,&(selected_config.Grid_XOR_color),0,255,3,NULL}, + {"Sync views:",1,&(selected_config.Sync_views),0,1,0,Lookup_YesNo}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, {" --- Input ---",0,NULL,0,0,0,NULL}, - {"",0,NULL,0,0,0,NULL}, {"Scrollbar speed",0,NULL,0,0,0,NULL}, {" on left click:",1,&(selected_config.Delay_left_click_on_slider),1,255,4,NULL}, {" on right click:",1,&(selected_config.Delay_right_click_on_slider),1,255,4,NULL}, @@ -939,9 +962,9 @@ void Button_Settings(void) {"Mouse speed (fullscreen)",0,NULL,0,0,0,NULL}, {" horizontally:",1,&(selected_config.Mouse_sensitivity_index_x),1,4,0,Lookup_MouseSpeed}, {" vertically:",1,&(selected_config.Mouse_sensitivity_index_y),1,4,0,Lookup_MouseSpeed}, + {"Key to swap buttons:",2,&(selected_config.Swap_buttons),0,0,0,Lookup_SwapButtons}, {" --- Editing ---",0,NULL,0,0,0,NULL}, - {"",0,NULL,0,0,0,NULL}, {"Adjust brush pick:",1,&(selected_config.Adjust_brush_pick),0,1,0,Lookup_YesNo}, {"Undo pages:",1,&(selected_config.Max_undo_pages),1,99,5,NULL}, {"Vertices per polygon:",4,&(selected_config.Nb_max_vertices_per_polygon),2,16384,5,NULL}, @@ -949,11 +972,11 @@ void Button_Settings(void) {"Clear with stencil:",1,&(selected_config.Clear_with_stencil),0,1,0,Lookup_YesNo}, {"Auto discontinuous:",1,&(selected_config.Auto_discontinuous),0,1,0,Lookup_YesNo}, {"Auto count colors:",1,&(selected_config.Auto_nb_used),0,1,0,Lookup_YesNo}, + {"Right click colorpick:",1,&(selected_config.Right_click_colorpick),0,1,0,Lookup_YesNo}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, {" --- File selector ---",0,NULL,0,0,0,NULL}, - {"",0,NULL,0,0,0,NULL}, {"Show in fileselector",0,NULL,0,0,0,NULL}, {" Hidden files:",4,&(selected_config.Show_hidden_files),0,1,0,Lookup_YesNo}, {" Hidden dirs:",4,&(selected_config.Show_hidden_directories),0,1,0,Lookup_YesNo}, @@ -963,9 +986,9 @@ void Button_Settings(void) {"Auto set resolution:",1,&(selected_config.Auto_set_res), 0,1,0,Lookup_YesNo}, {" According to:",1,&(selected_config.Set_resolution_according_to), 1,2,0,Lookup_AutoRes}, {"Backup:",1,&(selected_config.Backup), 0,1,0,Lookup_YesNo}, + {"",0,NULL,0,0,0,NULL}, {" --- Format options ---",0,NULL,0,0,0,NULL}, - {"",0,NULL,0,0,0,NULL}, {"Screen size in GIF:",1,&(selected_config.Screen_size_in_GIF),0,1,0,Lookup_YesNo}, {"Clear palette:",1,&(selected_config.Clear_palette),0,1,0,Lookup_YesNo}, {"",0,NULL,0,0,0,NULL}, @@ -975,6 +998,7 @@ void Button_Settings(void) {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, + {"",0,NULL,0,0,0,NULL}, }; @@ -982,7 +1006,7 @@ void Button_Settings(void) const char * help_section[SETTING_PAGES] = { "GUI", "INPUT", - "EDITING" + "EDITING", "FILE SELECTOR", "FILE FORMAT OPTIONS", }; @@ -1076,7 +1100,7 @@ void Button_Settings(void) str[0]='\0'; if (! (old_mouse_k & RIGHT_SIDE)) Num2str(value,str,item.Digits+1); - if (Readline(panel->Pos_X+3+176, panel->Pos_Y+num*SETTING_HEIGHT+(SETTING_HEIGHT-6)/2,str,item.Digits+1,1)) + if (Readline(panel->Pos_X+3+176, panel->Pos_Y+num*SETTING_HEIGHT+(SETTING_HEIGHT-6)/2,str,item.Digits+1,INPUT_TYPE_INTEGER)) { value=atoi(str); if (value=10 && fname[0]!='_' && !strncasecmp(fname, "skin_", 5) + if (namelength>=10 && fname[0]!='_' && !strncasecmp(fname, SKIN_PREFIX, strlen(SKIN_PREFIX)) && (!strcasecmp(fname + namelength - 4,".png") || !strcasecmp(fname + namelength - 4,".gif"))) { - Add_element_to_list(&Skin_files_list, name, 0); + Add_element_to_list(&Skin_files_list, fname, Format_filename(fname, 19, 0), 0, ICON_NONE); if (fname[0]=='\0') return; - - // Remove directory from full name - strcpy(Skin_files_list.First->Full_name, fname); - // Reformat the short name differently - strcpy(Skin_files_list.First->Short_name, - Format_filename(Skin_files_list.First->Full_name, 0) - ); } - else if (namelength>=10 && !strncasecmp(fname, "font_", 5) + else if (namelength>=10 && !strncasecmp(fname, FONT_PREFIX, strlen(FONT_PREFIX)) && (!strcasecmp(fname + namelength - 4, ".png"))) { - Add_element_to_list(&Font_files_list, name, 0); + Add_element_to_list(&Font_files_list, fname, Format_font_filename(fname), 0, ICON_NONE); if (fname[0]=='\0') return; - - // Remove directory from full name - strcpy(Font_files_list.First->Full_name, fname); - // Reformat the short name differently - strcpy(Font_files_list.First->Short_name, - Format_font_filename(Font_files_list.First->Full_name)); } } @@ -1253,7 +1264,9 @@ void Button_Skins(void) int selected_cursor = Config.Cursor; byte separatecolors = Config.Separate_colors; byte showlimits = Config.Display_image_limits; - + byte need_load=1; + int button; + word x, y, x_pos, offs_y; char * cursors[] = { "Solid", "Transparent", "Thin" }; @@ -1270,7 +1283,7 @@ void Button_Skins(void) Free_fileselector_list(&Font_files_list); // Browse the "skins" directory strcpy(skinsdir, Data_directory); - strcat(skinsdir, "skins"); + strcat(skinsdir, SKINS_SUBDIRECTORY); // Add each found file to the list For_each_file(skinsdir, Add_font_or_skin); // Sort it @@ -1341,6 +1354,68 @@ void Button_Skins(void) do { + if (need_load) + { + need_load=0; + + Hide_cursor(); + // (Re-)load GUI graphics from selected skins + strcpy(skinsdir, Get_item_by_index(&Skin_files_list, + skin_list->List_start + skin_list->Cursor_position)->Full_name); + + gfx = Load_graphics(skinsdir, NULL); + if (gfx == NULL) // Error + { + Display_cursor(); + Verbose_message("Error!", Gui_loading_error_message); + Hide_cursor(); + // Update preview + Window_rectangle(6, 14, 173, 16, MC_Light); + } + else + { + // Update preview + + // Display the bitmap according to its own color indices + for (y = 14, offs_y = 0; offs_y < 16; offs_y++, y++) + for (x = 6, x_pos = 0; x_pos<173; x_pos++, x++) + { + if (gfx->Preview[offs_y][x_pos] == gfx->Color[0]) + Pixel_in_window(x, y, MC_Black); + else if (gfx->Preview[offs_y][x_pos] == gfx->Color[1]) + Pixel_in_window(x, y, MC_Dark); + else if (gfx->Preview[offs_y][x_pos] == gfx->Color[3]) + Pixel_in_window(x, y, MC_White); + else if (gfx->Preview[offs_y][x_pos] == gfx->Color[2]) + Pixel_in_window(x, y, MC_Light); + } + // Actualize current screen according to preferred GUI colors + // Note this only updates onscreen colors + Set_color( + MC_Black, + gfx->Default_palette[gfx->Color[0]].R, + gfx->Default_palette[gfx->Color[0]].G, + gfx->Default_palette[gfx->Color[0]].B); + Set_color( + MC_Dark, + gfx->Default_palette[gfx->Color[1]].R, + gfx->Default_palette[gfx->Color[1]].G, + gfx->Default_palette[gfx->Color[1]].B); + Set_color( + MC_Light, + gfx->Default_palette[gfx->Color[2]].R, + gfx->Default_palette[gfx->Color[2]].G, + gfx->Default_palette[gfx->Color[2]].B); + Set_color( + MC_White, + gfx->Default_palette[gfx->Color[3]].R, + gfx->Default_palette[gfx->Color[3]].G, + gfx->Default_palette[gfx->Color[3]].B); + } + Update_window_area(6, 14, 173, 16); + Display_cursor(); + } + clicked_button=Window_clicked_button(); if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_SETTINGS, "SKINS"); @@ -1354,60 +1429,7 @@ void Button_Skins(void) case 3 : // doesn't happen break; case 4 : // a file is selected - - // (Re-)load GUI graphics from selected skins - strcpy(skinsdir, Get_item_by_index(&Skin_files_list, - skin_list->List_start + skin_list->Cursor_position)->Full_name); - - gfx = Load_graphics(skinsdir); - if (gfx == NULL) // Error - { - Verbose_message("Error!", Gui_loading_error_message); - // Update preview - Window_rectangle(6, 14, 173, 16, MC_Light); - } - else - { - // Update preview - - // Display the bitmap according to its own color indices - for (y = 14, offs_y = 0; offs_y < 16; offs_y++, y++) - for (x = 6, x_pos = 0; x_pos<173; x_pos++, x++) - { - if (gfx->Preview[offs_y][x_pos] == gfx->Color[0]) - Pixel_in_window(x, y, MC_Black); - else if (gfx->Preview[offs_y][x_pos] == gfx->Color[1]) - Pixel_in_window(x, y, MC_Dark); - else if (gfx->Preview[offs_y][x_pos] == gfx->Color[3]) - Pixel_in_window(x, y, MC_White); - else if (gfx->Preview[offs_y][x_pos] == gfx->Color[2]) - Pixel_in_window(x, y, MC_Light); - } - // Actualize current screen according to preferred GUI colors - // Note this only updates onscreen colors - Set_color( - MC_Black, - gfx->Default_palette[gfx->Color[0]].R, - gfx->Default_palette[gfx->Color[0]].G, - gfx->Default_palette[gfx->Color[0]].B); - Set_color( - MC_Dark, - gfx->Default_palette[gfx->Color[1]].R, - gfx->Default_palette[gfx->Color[1]].G, - gfx->Default_palette[gfx->Color[1]].B); - Set_color( - MC_Light, - gfx->Default_palette[gfx->Color[2]].R, - gfx->Default_palette[gfx->Color[2]].G, - gfx->Default_palette[gfx->Color[2]].B); - Set_color( - MC_White, - gfx->Default_palette[gfx->Color[3]].R, - gfx->Default_palette[gfx->Color[3]].G, - gfx->Default_palette[gfx->Color[3]].B); - } - Update_window_area(6, 14, 173, 16); - + need_load=1; break; case 5 : // Font dropdown selected_font = Window_attribute2; // Get the index of the chosen font. @@ -1450,7 +1472,7 @@ void Button_Skins(void) Menu_font = new_font; fname = Get_item_by_index(&Font_files_list,selected_font)->Full_name; free(Config.Font_file); - Config.Font_file = strdup(fname); + Config.Font_file = (char *)strdup(fname); } // Confirm the change of cursor shape Config.Cursor = selected_cursor; @@ -1471,6 +1493,22 @@ void Button_Skins(void) // Raffichage du menu pour que les inscriptions qui y figurent soient retracées avec la nouvelle fonte Display_menu(); + // Redraw all buttons, to ensure all specific sprites are in place. + // This is necessary for multi-state buttons, for example Freehand. + for (button=0; buttonOPERATION_FILLED_CONTOUR) Selected_freehand_mode=OPERATION_CONTINUOUS_DRAW; Hide_cursor(); - Display_sprite_in_menu(BUTTON_DRAW,Selected_freehand_mode); + switch(Selected_freehand_mode) + { + default: + case OPERATION_CONTINUOUS_DRAW: + icon=-1; + break; + case OPERATION_DISCONTINUOUS_DRAW: + icon=MENU_SPRITE_DISCONTINUOUS_DRAW; + break; + case OPERATION_POINT_DRAW: + icon=MENU_SPRITE_POINT_DRAW; + break; + case OPERATION_FILLED_CONTOUR: + icon=MENU_SPRITE_CONTOUR_DRAW; + break; + } + Display_sprite_in_menu(BUTTON_DRAW,icon); + Draw_menu_button(BUTTON_DRAW,BUTTON_PRESSED); Start_operation_stack(Selected_freehand_mode); Display_cursor(); /* NOUVEAU CODE AVEC POPUP (EN COURS DE TEST) *** @@ -2254,7 +2311,7 @@ void Button_Draw_switch_mode(void) while (Mouse_K); Close_popup(); - Display_sprite_in_menu(BUTTON_DRAW,Selected_freehand_mode); + //Display_sprite_in_menu(BUTTON_DRAW,Selected_freehand_mode+2); Start_operation_stack(Selected_freehand_mode); Display_cursor(); */ @@ -2373,17 +2430,19 @@ void Draw_button_gradient_style(short x_pos,short y_pos,int technique) void Load_gradient_data(int index) { - Gradient_lower_bound =Gradient_array[index].Start; - Gradient_upper_bound =Gradient_array[index].End; - Gradient_is_inverted =Gradient_array[index].Inverse; - Gradient_random_factor=Gradient_array[index].Mix+1; + if (Main_backups->Pages->Gradients->Range[index].Start>Main_backups->Pages->Gradients->Range[index].End) + Error(0); + Gradient_lower_bound =Main_backups->Pages->Gradients->Range[index].Start; + Gradient_upper_bound =Main_backups->Pages->Gradients->Range[index].End; + Gradient_is_inverted =Main_backups->Pages->Gradients->Range[index].Inverse; + Gradient_random_factor=Main_backups->Pages->Gradients->Range[index].Mix+1; Gradient_bounds_range=(Gradient_lower_boundPages->Gradients->Range[index].Technique) { case 0 : // Degradé de base Gradient_function=Gradient_basic; @@ -2422,10 +2481,12 @@ void Draw_gradient_preview(short start_x,short start_y,short width,short height, void Button_Gradients(void) { short clicked_button; - char str[3]; - T_Gradient_array backup_gradients[16]; + char str[4]; + T_Gradient_array backup_gradients; int old_current_gradient; T_Scroller_button * mix_scroller; + T_Scroller_button * speed_scroller; + T_Scroller_button * gradient_scroller; short old_mouse_x; short old_mouse_y; byte old_mouse_k; @@ -2434,44 +2495,57 @@ void Button_Gradients(void) byte last_color; byte color; byte click; + int changed_gradient_index; + byte cycling_mode=Cycling_mode; - + // Enable cycling while this window is open + Cycling_mode=1; + Gradient_pixel=Pixel; old_current_gradient=Current_gradient; - memcpy(backup_gradients,Gradient_array,sizeof(T_Gradient_array)*16); + changed_gradient_index=0; + memcpy(&backup_gradients,Main_backups->Pages->Gradients,sizeof(T_Gradient_array)); - Open_window(237,133,"Gradation menu"); + Open_window(235,146,"Gradation menu"); - Window_set_palette_button(48,21); // 1 - // Définition du scrolleur <=> indice du dégradé dans le tableau - Window_set_scroller_button(218,22,75,16,1,Current_gradient); // 2 - // Définition du scrolleur de mélange du dégradé - mix_scroller = Window_set_scroller_button(31,22,84,256,1, - Gradient_array[Current_gradient].Mix); // 3 - // Définition du bouton de sens - Window_set_normal_button(8,22,15,14, - (Gradient_array[Current_gradient].Inverse)?"\033":"\032",0,1,SDLK_TAB); // 4 - // Définition du bouton de technique - Window_set_normal_button(8,92,15,14,"",0,1,SDLK_TAB|MOD_SHIFT); // 5 - Draw_button_gradient_style(8,92,Gradient_array[Current_gradient].Technique); + Window_set_palette_button(48,19); // 1 + // Slider for gradient selection + gradient_scroller=Window_set_scroller_button(218,20,75,16,1,Current_gradient); // 2 + // Slider for mix + mix_scroller = Window_set_scroller_button(31,20,84,256,1, + Main_backups->Pages->Gradients->Range[Current_gradient].Mix); // 3 + // Direction + Window_set_normal_button(8,20,15,14, + (Main_backups->Pages->Gradients->Range[Current_gradient].Inverse)?"\033":"\032",0,1,SDLK_TAB); // 4 + // Technique + Window_set_normal_button(8,90,15,14,"",0,1,SDLK_TAB|MOD_SHIFT); // 5 + Draw_button_gradient_style(8,90,Main_backups->Pages->Gradients->Range[Current_gradient].Technique); - Window_set_normal_button(178,112,51,14,"OK",0,1,SDLK_RETURN); // 6 - Window_set_normal_button(123,112,51,14,"Cancel",0,1,KEY_ESC); // 7 - - Print_in_window(5,60,"MIX",MC_Dark,MC_Light); + Window_set_normal_button(178,128,51,14,"OK",0,1,SDLK_RETURN); // 6 + Window_set_normal_button(123,128,51,14,"Cancel",0,1,KEY_ESC); // 7 + // Scrolling speed + speed_scroller = Window_set_horizontal_scroller_button(99,111,130,106,1,Main_backups->Pages->Gradients->Range[Current_gradient].Speed); // 8 + Num2str(Main_backups->Pages->Gradients->Range[Current_gradient].Speed,str,3); + Print_in_window(73,113,str,MC_Black,MC_Light); + + Print_in_window(5,58,"MIX",MC_Dark,MC_Light); + // Cycling mode on/off + Window_set_normal_button(8,109,62,14,"",0,1,KEY_NONE); // 9 + Print_in_window(11,112,"Cycling",cycling_mode?MC_Black:MC_Dark,MC_Light); + // On tagge les couleurs qui vont avec - Tag_color_range(Gradient_array[Current_gradient].Start,Gradient_array[Current_gradient].End); + Tag_color_range(Main_backups->Pages->Gradients->Range[Current_gradient].Start,Main_backups->Pages->Gradients->Range[Current_gradient].End); Num2str(Current_gradient+1,str,2); Print_in_window(215,100,str,MC_Black,MC_Light); - // On affiche le cadre autour de la préview - Window_display_frame_in(7,111,110,16); - // On affiche la preview - Draw_gradient_preview(8,112,108,14,Current_gradient); + // On affiche le cadre autour de la préview + Window_display_frame_in(7,127,110,16); + // On affiche la preview + Draw_gradient_preview(8,128,108,14,Current_gradient); - first_color=last_color=(Gradient_array[Current_gradient].Inverse)?Gradient_array[Current_gradient].End:Gradient_array[Current_gradient].Start; + first_color=last_color=(Main_backups->Pages->Gradients->Range[Current_gradient].Inverse)?Main_backups->Pages->Gradients->Range[Current_gradient].End:Main_backups->Pages->Gradients->Range[Current_gradient].Start; Update_window_area(0,0,Window_width, Window_height); Display_cursor(); @@ -2481,8 +2555,53 @@ void Button_Gradients(void) old_mouse_x=Mouse_X; old_mouse_y=Mouse_Y; old_mouse_k=Mouse_K; + if (changed_gradient_index) + { + // User has changed which gradient (0-15) he's watching + changed_gradient_index=0; + + Hide_cursor(); + + // On affiche la valeur sous la jauge + Num2str(Current_gradient+1,str,2); + Print_in_window(215,100,str,MC_Black,MC_Light); + + // On tagge les couleurs qui vont avec + Tag_color_range(Main_backups->Pages->Gradients->Range[Current_gradient].Start,Main_backups->Pages->Gradients->Range[Current_gradient].End); + + // On affiche le sens qui va avec + Print_in_window(12,23,(Main_backups->Pages->Gradients->Range[Current_gradient].Inverse)?"\033":"\032",MC_Black,MC_Light); + + // On raffiche le mélange (jauge) qui va avec + mix_scroller->Position=Main_backups->Pages->Gradients->Range[Current_gradient].Mix; + Window_draw_slider(mix_scroller); + + // Update speed + speed_scroller->Position=Main_backups->Pages->Gradients->Range[Current_gradient].Speed; + Window_draw_slider(speed_scroller); + Num2str(Main_backups->Pages->Gradients->Range[Current_gradient].Speed,str,3); + Print_in_window(73,113,str,MC_Black,MC_Light); + + // Gradient # + gradient_scroller->Position=Current_gradient; + Window_draw_slider(gradient_scroller); + + // Technique (flat, dithered, very dithered) + Draw_button_gradient_style(8,90,Main_backups->Pages->Gradients->Range[Current_gradient].Technique); + + // Rectangular gradient preview + Draw_gradient_preview(8,128,108,14,Current_gradient); + + Display_cursor(); + } clicked_button=Window_clicked_button(); + if (Input_sticky_control!=8 || !Mouse_K) + { + Allow_colorcycling=0; + // Restore palette + Set_palette(Main_palette); + } switch(clicked_button) { @@ -2498,11 +2617,11 @@ void Button_Gradients(void) // On vient de clicker // On met à jour l'intervalle du dégradé - first_color=last_color=Gradient_array[Current_gradient].Start=Gradient_array[Current_gradient].End=temp_color; + first_color=last_color=Main_backups->Pages->Gradients->Range[Current_gradient].Start=Main_backups->Pages->Gradients->Range[Current_gradient].End=temp_color; // On tagge le bloc - Tag_color_range(Gradient_array[Current_gradient].Start,Gradient_array[Current_gradient].End); + Tag_color_range(Main_backups->Pages->Gradients->Range[Current_gradient].Start,Main_backups->Pages->Gradients->Range[Current_gradient].End); // Tracé de la preview: - Draw_gradient_preview(8,112,108,14,Current_gradient); + Draw_gradient_preview(8,128,108,14,Current_gradient); } else { @@ -2512,20 +2631,20 @@ void Button_Gradients(void) // On commence par ordonner la 1ère et dernière couleur du bloc if (first_colorPages->Gradients->Range[Current_gradient].Start=first_color; + Main_backups->Pages->Gradients->Range[Current_gradient].End =temp_color; } else if (first_color>temp_color) { - Gradient_array[Current_gradient].Start=temp_color; - Gradient_array[Current_gradient].End =first_color; + Main_backups->Pages->Gradients->Range[Current_gradient].Start=temp_color; + Main_backups->Pages->Gradients->Range[Current_gradient].End =first_color; } else - Gradient_array[Current_gradient].Start=Gradient_array[Current_gradient].End=first_color; + Main_backups->Pages->Gradients->Range[Current_gradient].Start=Main_backups->Pages->Gradients->Range[Current_gradient].End=first_color; // On tagge le bloc - Tag_color_range(Gradient_array[Current_gradient].Start,Gradient_array[Current_gradient].End); + Tag_color_range(Main_backups->Pages->Gradients->Range[Current_gradient].Start,Main_backups->Pages->Gradients->Range[Current_gradient].End); // Tracé de la preview: - Draw_gradient_preview(8,112,108,14,Current_gradient); + Draw_gradient_preview(8,128,108,14,Current_gradient); last_color=temp_color; } } @@ -2533,57 +2652,49 @@ void Button_Gradients(void) } break; case 2 : // Nouvel indice de dégradé - Hide_cursor(); // Nouvel indice dans Window_attribute2 Current_gradient=Window_attribute2; - - // On affiche la valeur sous la jauge - Num2str(Current_gradient+1,str,2); - Print_in_window(215,100,str,MC_Black,MC_Light); - - // On tagge les couleurs qui vont avec - Tag_color_range(Gradient_array[Current_gradient].Start,Gradient_array[Current_gradient].End); - - // On affiche le sens qui va avec - Print_in_window(12,25,(Gradient_array[Current_gradient].Inverse)?"\033":"\032",MC_Black,MC_Light); - - // On raffiche le mélange (jauge) qui va avec - mix_scroller->Position=Gradient_array[Current_gradient].Mix; - Window_draw_slider(mix_scroller); - - // On raffiche la technique qui va avec - Draw_button_gradient_style(8,92,Gradient_array[Current_gradient].Technique); - - // On affiche la nouvelle preview - Draw_gradient_preview(8,112,108,14,Current_gradient); - - Display_cursor(); + changed_gradient_index=1; break; case 3 : // Nouveau mélange de dégradé Hide_cursor(); // Nouvel mélange dans Window_attribute2 - Gradient_array[Current_gradient].Mix=Window_attribute2; + Main_backups->Pages->Gradients->Range[Current_gradient].Mix=Window_attribute2; // On affiche la nouvelle preview - Draw_gradient_preview(8,112,108,14,Current_gradient); + Draw_gradient_preview(8,128,108,14,Current_gradient); Display_cursor(); break; case 4 : // Changement de sens Hide_cursor(); // On inverse le sens (par un XOR de 1) - Gradient_array[Current_gradient].Inverse^=1; - Print_in_window(12,25,(Gradient_array[Current_gradient].Inverse)?"\033":"\032",MC_Black,MC_Light); + Main_backups->Pages->Gradients->Range[Current_gradient].Inverse^=1; + Print_in_window(12,23,(Main_backups->Pages->Gradients->Range[Current_gradient].Inverse)?"\033":"\032",MC_Black,MC_Light); // On affiche la nouvelle preview - Draw_gradient_preview(8,112,108,14,Current_gradient); + Draw_gradient_preview(8,128,108,14,Current_gradient); Display_cursor(); break; case 5 : // Changement de technique Hide_cursor(); // On change la technique par (+1)%3 - Gradient_array[Current_gradient].Technique=(Gradient_array[Current_gradient].Technique+1)%3; - Draw_button_gradient_style(8,92,Gradient_array[Current_gradient].Technique); + Main_backups->Pages->Gradients->Range[Current_gradient].Technique=(Main_backups->Pages->Gradients->Range[Current_gradient].Technique+1)%3; + Draw_button_gradient_style(8,90,Main_backups->Pages->Gradients->Range[Current_gradient].Technique); // On affiche la nouvelle preview - Draw_gradient_preview(8,112,108,14,Current_gradient); + Draw_gradient_preview(8,128,108,14,Current_gradient); Display_cursor(); + case 8 : // Speed + Main_backups->Pages->Gradients->Range[Current_gradient].Speed=Window_attribute2; + Num2str(Main_backups->Pages->Gradients->Range[Current_gradient].Speed,str,3); + Hide_cursor(); + Print_in_window(73,113,str,MC_Black,MC_Light); + Display_cursor(); + Allow_colorcycling=1; + break; + case 9: // Cycling on/off + cycling_mode = !cycling_mode; + Hide_cursor(); + Print_in_window(11,112,"Cycling",cycling_mode?MC_Black:MC_Dark,MC_Light); + Display_cursor(); + break; } if (!Mouse_K) @@ -2598,16 +2709,31 @@ void Button_Gradients(void) temp_color=color; // On met à jour l'intervalle du dégradé - first_color=last_color=Gradient_array[Current_gradient].Start=Gradient_array[Current_gradient].End=temp_color; + first_color=last_color=Main_backups->Pages->Gradients->Range[Current_gradient].Start=Main_backups->Pages->Gradients->Range[Current_gradient].End=temp_color; // On tagge le bloc - Tag_color_range(Gradient_array[Current_gradient].Start,Gradient_array[Current_gradient].End); + Tag_color_range(Main_backups->Pages->Gradients->Range[Current_gradient].Start,Main_backups->Pages->Gradients->Range[Current_gradient].End); // Tracé de la preview: - Draw_gradient_preview(8,112,108,14,Current_gradient); + Draw_gradient_preview(8,128,108,14,Current_gradient); Display_cursor(); Wait_end_of_click(); } Key=0; break; + case KEY_MOUSEWHEELUP: + if (Current_gradient>0) + { + Current_gradient--; + changed_gradient_index=1; + } + break; + case KEY_MOUSEWHEELDOWN: + if (Current_gradient<15) + { + Current_gradient++; + changed_gradient_index=1; + } + break; + default: if (Is_shortcut(Key,0x100+BUTTON_HELP)) { @@ -2615,11 +2741,19 @@ void Button_Gradients(void) Key=0; break; } - if (Is_shortcut(Key,0x200+BUTTON_GRADRECT)) + else if (Is_shortcut(Key,0x200+BUTTON_GRADRECT)) clicked_button=6; + else if (Is_shortcut(Key,SPECIAL_CYCLE_MODE)) + { + // Cycling on/off + cycling_mode = !cycling_mode; + Hide_cursor(); + Print_in_window(11,112,"Cycling",cycling_mode?MC_Black:MC_Dark,MC_Light); + Display_cursor(); + } } } - while (clicked_button<6); + while (clicked_button!=6 && clicked_button!=7); Close_window(); // The Grad rect operation uses the same button as Grad menu. @@ -2629,11 +2763,11 @@ void Button_Gradients(void) Display_cursor(); Gradient_pixel=Display_pixel; + Cycling_mode=cycling_mode; if (clicked_button==7) // Cancel { Current_gradient=old_current_gradient; - memcpy(Gradient_array,backup_gradients,sizeof(T_Gradient_array)*16); - Load_gradient_data(Current_gradient); + memcpy(Main_backups->Pages->Gradients,&backup_gradients,sizeof(T_Gradient_array)); } } @@ -2719,6 +2853,26 @@ void Button_Unselect_fill(void) //---------------------------- Menu des pinceaux ----------------------------- +/// Checks if the current brush is identical to a preset one. +byte Same_paintbrush(byte index) +{ + if (Paintbrush_shape!=Paintbrush[index].Shape || + Paintbrush_width!=Paintbrush[index].Width || + Paintbrush_height!=Paintbrush[index].Height) + return 0; + + if (Paintbrush_shape==PAINTBRUSH_SHAPE_MISC) + { + // Check all pixels + int x,y; + for(y=0;y(NB_PAINTBRUSH_SPRITES+1)) + if (clicked_button>=(NB_PAINTBRUSH_SPRITES+3)) { - index = clicked_button-NB_PAINTBRUSH_SPRITES-2; + index = clicked_button-NB_PAINTBRUSH_SPRITES-3; - if (Window_attribute1==RIGHT_SIDE) + if (Window_attribute2==1) // Set { // Store @@ -2771,41 +2946,82 @@ void Button_Paintbrush_menu(void) Hide_cursor(); Display_stored_brush_in_window(x_pos+2, y_pos+2, index); Display_cursor(); - } + } else { // Restore and exit if (Restore_brush(index)) { - Close_window(); + Close_window(); break; } } } - else if (clicked_button>1 && Window_attribute1==LEFT_SIDE) + else if (clicked_button>=3) // Standard paintbrushes - { - Close_window(); - index=clicked_button-2; - Paintbrush_shape=Gfx->Paintbrush_type[index]; - Paintbrush_width=Gfx->Preset_paintbrush_width[index]; - Paintbrush_height=Gfx->Preset_paintbrush_height[index]; - Paintbrush_offset_X=Gfx->Preset_paintbrush_offset_X[index]; - Paintbrush_offset_Y=Gfx->Preset_paintbrush_offset_Y[index]; - for (y_pos=0; y_posPaintbrush_sprite[index][y_pos][x_pos]; - Change_paintbrush_shape(Gfx->Paintbrush_type[index]); - - break; + { + if (Window_attribute2!=1) + { + // Select paintbrush + Close_window(); + Select_paintbrush(clicked_button-3); + break; + } + else if (Window_attribute2==1) + { + // Store current + index=clicked_button-3; + if (!Store_paintbrush(index)) + { + // Redraw + Hide_cursor(); + x_pos=13+(index%12)*24; + y_pos=27+(index/12)*25; + Window_rectangle(x_pos,y_pos,20,20,MC_White); + Display_paintbrush_in_window(x_pos+2,y_pos+2,index); + Display_cursor(); + } + } } else if (clicked_button==1 || Is_shortcut(Key,0x100+BUTTON_PAINTBRUSHES)) { Close_window(); break; } + else if (clicked_button==2) + { + int size; + // Pick a standard shape + Paintbrush_shape=Window_attribute2; + // Assign a reasonable size + size=Max(Paintbrush_width,Paintbrush_height); + if (size==1) + size=3; + + switch (Paintbrush_shape) + { + case PAINTBRUSH_SHAPE_HORIZONTAL_BAR: + Set_paintbrush_size(size, 1); + break; + case PAINTBRUSH_SHAPE_VERTICAL_BAR: + Set_paintbrush_size(1, size); + break; + case PAINTBRUSH_SHAPE_CROSS: + case PAINTBRUSH_SHAPE_PLUS: + case PAINTBRUSH_SHAPE_DIAMOND: + Set_paintbrush_size(size|1,size|1); + break; + default: + Set_paintbrush_size(size,size); + break; + + } + Close_window(); + Change_paintbrush_shape(Paintbrush_shape); + break; + } } while (1); @@ -2897,7 +3113,6 @@ void Load_picture(byte image) // Image=0 => On charge/sauve une brosse { byte confirm; - byte use_brush_palette = 0; byte old_cursor_shape; int new_mode; T_IO_Context context; @@ -2925,8 +3140,6 @@ void Load_picture(byte image) if (Main_image_is_modified) confirm=Confirmation_box("Discard unsaved changes?"); } - else - use_brush_palette=Confirmation_box("Use the palette of the brush?"); } // confirm is modified inside the first if, that's why we check it @@ -2948,24 +3161,14 @@ void Load_picture(byte image) if (!image) { - //if (!use_brush_palette) - // memcpy(Main_palette,initial_palette,sizeof(T_Palette)); - - if (File_error==3) // On ne peut pas allouer la brosse + if (File_error==3) // Memory allocation error when loading brush { - free(Brush); - Brush=(byte *)malloc(1*1); - Brush_height=1; - Brush_width=1; - *Brush=Fore_color; - - free(Smear_brush); - Smear_brush=(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE); - Smear_brush_height=MAX_PAINTBRUSH_SIZE; - Smear_brush_width=MAX_PAINTBRUSH_SIZE; + // Nothing to do here. + // Previous versions of Grafx2 would have damaged the Brush, + // and need reset it here, but now the loading is done in separate + // memory buffers. } - Tiling_offset_X=0; Tiling_offset_Y=0; @@ -3001,9 +3204,9 @@ void Load_picture(byte image) { if (Main_magnifier_mode) { - Draw_menu_button_frame(BUTTON_MAGNIFIER,0); Pixel_preview=Pixel_preview_normal; Main_magnifier_mode=0; + Draw_menu_button(BUTTON_MAGNIFIER,Main_magnifier_mode); } new_mode=Best_video_mode(); @@ -3104,9 +3307,9 @@ void Button_Reload(void) { if (Main_magnifier_mode) { - Draw_menu_button_frame(BUTTON_MAGNIFIER,0); Pixel_preview=Pixel_preview_normal; Main_magnifier_mode=0; + Draw_menu_button(BUTTON_MAGNIFIER,Main_magnifier_mode); } new_mode=Best_video_mode(); @@ -3341,18 +3544,34 @@ void Button_Lines(void) void Button_Lines_switch_mode(void) { + char icon; + if (Selected_line_mode==OPERATION_LINE) - Selected_line_mode=OPERATION_K_LIGNE; + Selected_line_mode=OPERATION_K_LINE; else { - if (Selected_line_mode==OPERATION_K_LIGNE) + if (Selected_line_mode==OPERATION_K_LINE) Selected_line_mode=OPERATION_CENTERED_LINES; else Selected_line_mode=OPERATION_LINE; } + switch(Selected_line_mode) + { + default: + case OPERATION_LINE: + icon=-1; + break; + case OPERATION_K_LINE: + icon=MENU_SPRITE_K_LINE; + break; + case OPERATION_CENTERED_LINES: + icon=MENU_SPRITE_CENTERED_LINES; + break; + } Hide_cursor(); - Display_sprite_in_menu(BUTTON_LINES,Selected_line_mode-OPERATION_LINE+7); + Display_sprite_in_menu(BUTTON_LINES,icon); + Draw_menu_button(BUTTON_LINES,BUTTON_PRESSED); Start_operation_stack(Selected_line_mode); Display_cursor(); } @@ -3446,6 +3665,7 @@ void Button_Colorpicker(void) void Button_Unselect_colorpicker(void) { + // Erase the color block which shows the picked color if (Operation_before_interrupt!=OPERATION_REPLACE) if ( (Mouse_Y=Main_X_zoom) ) ) @@ -3492,8 +3712,6 @@ void Button_Magnify(void) } else { - Old_main_offset_X=Main_offset_X; - Old_main_offset_Y=Main_offset_Y; Compute_magnifier_data(); if ((!Config.Fast_zoom) || (Mouse_Y>=Menu_Y) || Coming_from_zoom_factor_menu) { @@ -3586,24 +3804,20 @@ void Button_Unselect_magnifier(void) // On sort du mode loupe Main_magnifier_mode=0; - /* + // --> Recalculer le décalage de l'écran lorsqu'on sort de la loupe <-- // Centrage "brut" de lécran par rapport à la loupe Main_offset_X=Main_magnifier_offset_X-((Screen_width-Main_magnifier_width)>>1); Main_offset_Y=Main_magnifier_offset_Y-((Menu_Y-Main_magnifier_height)>>1); - */ + // Correction en cas de débordement de l'image - if (Old_main_offset_X+Screen_width>Main_image_width) + if (Main_offset_X+Screen_width>Main_image_width) Main_offset_X=Main_image_width-Screen_width; - else - Main_offset_X=Old_main_offset_X; if (Main_offset_X<0) Main_offset_X=0; - if (Old_main_offset_Y+Menu_Y>Main_image_height) + if (Main_offset_Y+Menu_Y>Main_image_height) Main_offset_Y=Main_image_height-Menu_Y; - else - Main_offset_Y=Old_main_offset_Y; if (Main_offset_Y<0) Main_offset_Y=0; @@ -3721,10 +3935,14 @@ void Button_Brush_FX(void) switch (clicked_button) { case 2 : // Flip X - Flip_X_lowlevel(Brush, Brush_width, Brush_height); + Flip_X_lowlevel(Brush_original_pixels, Brush_width, Brush_height); + // Remap according to the last used remap table + Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); break; case 3 : // Flip Y - Flip_Y_lowlevel(Brush, Brush_width, Brush_height); + Flip_Y_lowlevel(Brush_original_pixels, Brush_width, Brush_height); + // Remap according to the last used remap table + Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); break; case 4 : // 90° Rotation Rotate_90_deg(); @@ -3811,7 +4029,8 @@ void Button_Curves_switch_mode(void) Selected_curve_mode=OPERATION_4_POINTS_CURVE; Hide_cursor(); - Display_sprite_in_menu(BUTTON_CURVES,Selected_curve_mode-OPERATION_3_POINTS_CURVE+5); + Display_sprite_in_menu(BUTTON_CURVES,Selected_curve_mode==OPERATION_4_POINTS_CURVE?MENU_SPRITE_4_POINTS_CURVE:-1); + Draw_menu_button(BUTTON_CURVES,BUTTON_PRESSED); Start_operation_stack(Selected_curve_mode); Display_cursor(); } @@ -4053,7 +4272,7 @@ void Button_Airbrush_menu(void) case 11 : // Size Num2str(Airbrush_size,str,3); - Readline(188,25,str,3,1); + Readline(188,25,str,3,INPUT_TYPE_INTEGER); Airbrush_size=atoi(str); // On corrige les dimensions if (Airbrush_size>256) @@ -4073,7 +4292,7 @@ void Button_Airbrush_menu(void) case 12 : // Delay Num2str(Airbrush_delay,str,2); - Readline(196,39,str,2,1); + Readline(196,39,str,2,INPUT_TYPE_INTEGER); Airbrush_delay=atoi(str); // On corrige le delai if (Airbrush_delay>99) @@ -4087,7 +4306,7 @@ void Button_Airbrush_menu(void) case 13 : // Mono-Flow Num2str(Airbrush_mono_flow,str,2); - Readline(113,24,str,2,1); + Readline(113,24,str,2,INPUT_TYPE_INTEGER); Airbrush_mono_flow=atoi(str); // On corrige le flux if (!Airbrush_mono_flow) @@ -4101,7 +4320,7 @@ void Button_Airbrush_menu(void) case 14 : // Init Num2str(spray_init,str,2); - Readline(113,40,str,2,1); + Readline(113,40,str,2,INPUT_TYPE_INTEGER); spray_init=atoi(str); // On corrige la valeur if (spray_init>=50) @@ -4231,11 +4450,11 @@ void Display_effect_sprite(short sprite_number, short start_x, short start_y) { short x,y,x_pos,y_pos; - for (y=0,y_pos=start_y;yEffect_sprite[sprite_number][y][x]); - Update_rect(ToWinX(start_x),ToWinY(start_y),MENU_SPRITE_WIDTH*Menu_factor_X,MENU_SPRITE_HEIGHT*Menu_factor_Y); + Update_rect(ToWinX(start_x),ToWinY(start_y),EFFECT_SPRITE_WIDTH*Menu_factor_X,EFFECT_SPRITE_HEIGHT*Menu_factor_Y); } @@ -4551,7 +4770,7 @@ void Draw_one_font_name(word x, word y, word index, byte highlighted) Print_in_window(x,y,Font_label(index), MC_Black, (highlighted)?MC_Dark:MC_Light); } -void Button_Text() +void Button_Text(void) { static char str[256]=""; static int font_size=32; @@ -4563,11 +4782,12 @@ void Button_Text() static short is_italic=0; byte * new_brush=NULL; + T_Palette text_palette; int new_width; int new_height; int clicked_button; const int NB_FONTS=8; - char size_buffer[3]; + char size_buffer[4]; T_Special_button * input_size_button; T_Special_button * input_text_button; T_Special_button * preview_button; @@ -4642,23 +4862,86 @@ void Button_Text() if (preview_is_needed) { const char * preview_string = "AaBbCcDdEeFf012345"; + byte is_truetype; + if (str[0]) preview_string=str; - Window_rectangle(8, 106, 273, 50,Back_color); + is_truetype=TrueType_font(selected_font_index); + Window_rectangle(8, 106, 273, 50,(antialias&&is_truetype)?MC_Black:Back_color); free(new_brush); - new_brush = Render_text(preview_string, selected_font_index, font_size, antialias, is_bold, is_italic, &new_width, &new_height); + new_brush = Render_text(preview_string, selected_font_index, font_size, antialias, is_bold, is_italic, &new_width, &new_height, text_palette); if (new_brush) { - Display_brush( - new_brush, - Window_pos_X+preview_button->Pos_X*Menu_factor_X, - Window_pos_Y+preview_button->Pos_Y*Menu_factor_Y, - 0, - 0, - Min(preview_button->Width*Menu_factor_X, new_width), - Min(preview_button->Height*Menu_factor_Y, new_height), - Back_color, - new_width); + if (!is_truetype || (is_truetype&&antialias)) + { + // Display brush in remapped form. + byte *remapped_brush; + + remapped_brush=(byte *)malloc(new_width*new_height); + if (remapped_brush) + { + // This code is mostly copied from Remap_brush() + short x_pos; + short y_pos; + int color; + byte colmap[256]; + + for (color=0;color<=255;color++) + colmap[color]=0; + + for (y_pos=0;y_posPos_X*Menu_factor_X, + Window_pos_Y+preview_button->Pos_Y*Menu_factor_Y, + 0, + 0, + Min(preview_button->Width*Menu_factor_X, new_width), + Min(preview_button->Height*Menu_factor_Y, new_height), + Back_color, + new_width); + + free(remapped_brush); + } + + } + else + { + // Solid + Display_brush( + new_brush, + Window_pos_X+preview_button->Pos_X*Menu_factor_X, + Window_pos_Y+preview_button->Pos_Y*Menu_factor_Y, + 0, + 0, + Min(preview_button->Width*Menu_factor_X, new_width), + Min(preview_button->Height*Menu_factor_Y, new_height), + Back_color, + new_width); + } + } Update_rect( Window_pos_X+preview_button->Pos_X*Menu_factor_X, @@ -4684,7 +4967,7 @@ void Button_Text() switch(clicked_button) { case 1: // Texte saisi - Readline_ex(50,20,str,29,250,0,0); + Readline_ex(50,20,str,29,250,INPUT_TYPE_STRING,0); preview_is_needed=1; break; @@ -4724,7 +5007,7 @@ void Button_Text() break; case 7: // Taille du texte (nombre) - Readline(222,45,size_buffer,3,1); + Readline(222,45,size_buffer,3,INPUT_TYPE_INTEGER); font_size=atoi(size_buffer); // On corrige les dimensions if (font_size < 1) @@ -4774,14 +5057,22 @@ void Button_Text() Error(0); return; } - free(Brush); + if (Realloc_brush(new_width, new_height, new_brush, NULL)) + { + free(new_brush); + Close_window(); + Unselect_button(BUTTON_TEXT); + Display_cursor(); + Error(0); + } + // Grab palette + memcpy(Brush_original_palette, text_palette,sizeof(T_Palette)); + // Remap to image's palette + Remap_brush(); - Brush=new_brush; - Brush_width=new_width; - Brush_height=new_height; Brush_offset_X=Brush_width>>1; Brush_offset_Y=Brush_height>>1; - + // Fermeture Close_window(); Unselect_button(BUTTON_TEXT); @@ -4792,6 +5083,20 @@ void Button_Text() Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); else Change_paintbrush_shape(PAINTBRUSH_SHAPE_MONO_BRUSH); + // Activate alpha mode + if (antialias && TrueType_font(selected_font_index)) + { + Shade_mode=0; + Quick_shade_mode=0; + Smooth_mode=0; + Tiling_mode=0; + Smear_mode=0; + Colorize_mode=1; + Colorize_current_mode=3; + Effect_function=Effect_alpha_colorize; + + Draw_menu_button(BUTTON_EFFECTS,BUTTON_PRESSED); + } Select_button(BUTTON_DRAW,LEFT_SIDE); if (Config.Auto_discontinuous) @@ -4846,7 +5151,7 @@ void Display_stored_brush_in_window(word x_pos,word y_pos,int index) if (Brush_container[index].Paintbrush_shape <= PAINTBRUSH_SHAPE_MISC) color = Brush_container[index].Thumbnail[y][x]?MC_Black:MC_Light; else - color = Brush_container[index].Thumbnail[y][x]; + color = Brush_container[index].Colormap[Brush_container[index].Thumbnail[y][x]]; Pixel_in_window(x_pos+x+offset_x,y_pos+y+offset_y,color); } } @@ -4855,6 +5160,7 @@ void Display_stored_brush_in_window(word x_pos,word y_pos,int index) } } +/// Store the current brush in brush container void Store_brush(int index) { if (Brush_container[index].Paintbrush_shape < PAINTBRUSH_SHAPE_MAX) @@ -4887,29 +5193,51 @@ void Store_brush(int index) // Re-init the rest Brush_container[index].Transp_color=0; } - if (Paintbrush_shape == PAINTBRUSH_SHAPE_COLOR_BRUSH || + else if (Paintbrush_shape == PAINTBRUSH_SHAPE_MONO_BRUSH && + Brush_width <= BRUSH_CONTAINER_PREVIEW_WIDTH && + Brush_height <= BRUSH_CONTAINER_PREVIEW_HEIGHT) + { + // Color brush transformed into a real mono paintbrush + int x,y; + + Brush_container[index].Paintbrush_shape=PAINTBRUSH_SHAPE_MISC; + Brush_container[index].Width=Brush_width; + Brush_container[index].Height=Brush_height; + // Preview: pick center for big mono brush + for (y=0; yBRUSH_CONTAINER_PREVIEW_WIDTH || Brush_height>BRUSH_CONTAINER_PREVIEW_HEIGHT) { // Scale - Rescale(Brush, Brush_width, Brush_height, (byte *)(Brush_container[index].Thumbnail), BRUSH_CONTAINER_PREVIEW_WIDTH, BRUSH_CONTAINER_PREVIEW_HEIGHT, 0, 0); + Rescale(Brush_original_pixels, Brush_width, Brush_height, (byte *)(Brush_container[index].Thumbnail), BRUSH_CONTAINER_PREVIEW_WIDTH, BRUSH_CONTAINER_PREVIEW_HEIGHT, 0, 0); } else { // Direct copy - Copy_part_of_image_to_another(Brush, 0,0,Brush_width, Brush_height,Brush_width,(byte *)(Brush_container[index].Thumbnail),0,0,BRUSH_CONTAINER_PREVIEW_WIDTH); + Copy_part_of_image_to_another(Brush_original_pixels, 0,0,Brush_width, Brush_height,Brush_width,(byte *)(Brush_container[index].Thumbnail),0,0,BRUSH_CONTAINER_PREVIEW_WIDTH); } } else @@ -4919,6 +5247,81 @@ void Store_brush(int index) } } +/// Retrieve a normal paintbrush +void Select_paintbrush(int index) +{ + int x_pos,y_pos; + + Paintbrush_shape=Paintbrush[index].Shape; + + if (Paintbrush[index].Width<=PAINTBRUSH_WIDTH && + Paintbrush[index].Height<=PAINTBRUSH_HEIGHT) + { + Paintbrush_width=Paintbrush[index].Width; + Paintbrush_height=Paintbrush[index].Height; + Paintbrush_offset_X=Paintbrush[index].Offset_X; + Paintbrush_offset_Y=Paintbrush[index].Offset_Y; + + for (y_pos=0; y_posPAINTBRUSH_WIDTH) + x_off=(Paintbrush_width-PAINTBRUSH_WIDTH)/2; + if (Paintbrush_height>PAINTBRUSH_HEIGHT) + y_off=(Paintbrush_height-PAINTBRUSH_HEIGHT)/2; + + for (y_pos=0; y_pos>1; - Brush_offset_Y=Brush_height>>1; + if (!Realloc_brush(Brush_container[index].Width,Brush_container[index].Height,NULL,NULL)) + { + // Recover pixels + memcpy(Brush_original_pixels, Brush_container[index].Brush, (long)Brush_height*Brush_width); + // Grab palette + memcpy(Brush_original_palette, Brush_container[index].Palette, sizeof(T_Palette)); + // Recover colormap + memcpy(Brush_colormap, Brush_container[index].Colormap, 256); + // Remap using current colormap + Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); + + Brush_offset_X=Brush_width>>1; + Brush_offset_Y=Brush_height>>1; + } } Change_paintbrush_shape(shape); diff --git a/src/buttons.h b/src/buttons.h index 7ccd4728..eed881dc 100644 --- a/src/buttons.h +++ b/src/buttons.h @@ -670,5 +670,9 @@ void Button_Smear_mode(void); void Button_Brush_container(void); +byte Store_paintbrush(int index); + +void Select_paintbrush(int index); + #endif diff --git a/src/buttons_effects.c b/src/buttons_effects.c index c76d1190..d95e1514 100644 --- a/src/buttons_effects.c +++ b/src/buttons_effects.c @@ -40,6 +40,7 @@ #include "sdlscreen.h" #include "struct.h" #include "windows.h" +#include "brush.h" //---------- Menu dans lequel on tagge des couleurs (genre Stencil) ---------- void Menu_tag_colors(char * window_title, byte * table, byte * mode, byte can_cancel, const char *help_section, word close_shortcut) @@ -279,7 +280,7 @@ void Button_Grid_menu(void) { case 3 : Num2str(chosen_X,str,2); - Readline(39,26,str,2,1); + Readline(39,26,str,2,INPUT_TYPE_INTEGER); chosen_X=atoi(str); // On corrige les dimensions if ((!chosen_X) || (chosen_X>80)) @@ -301,7 +302,7 @@ void Button_Grid_menu(void) break; case 4 : Num2str(chosen_Y,str,2); - Readline(39,47,str,2,1); + Readline(39,47,str,2,INPUT_TYPE_INTEGER); chosen_Y=atoi(str); // On corrige les dimensions if ((!chosen_Y) || (chosen_Y>80)) @@ -323,7 +324,7 @@ void Button_Grid_menu(void) break; case 5 : Num2str(dx_selected,str,2); - Readline(97,26,str,2,1); + Readline(97,26,str,2,INPUT_TYPE_INTEGER); dx_selected=atoi(str); // On corrige les dimensions if (dx_selected>79) @@ -338,7 +339,7 @@ void Button_Grid_menu(void) break; case 6 : Num2str(dy_selected,str,2); - Readline(97,47,str,2,1); + Readline(97,47,str,2,INPUT_TYPE_INTEGER); dy_selected=atoi(str); // On corrige les dimensions if (dy_selected>79) @@ -479,7 +480,7 @@ void Button_Smooth_menu(void) Num2str(chosen_matrix[x][y],str,2); Readline(matrix_input[x][y]->Pos_X+2, matrix_input[x][y]->Pos_Y+2, - str,2,1); + str,2,INPUT_TYPE_INTEGER); chosen_matrix[x][y]=atoi(str); Display_cursor(); } @@ -553,6 +554,9 @@ void Button_Colorize_mode(void) break; case 2 : Effect_function=Effect_substractive_colorize; + break; + case 3 : + Effect_function=Effect_alpha_colorize; } Shade_mode=0; Quick_shade_mode=0; @@ -572,10 +576,12 @@ void Button_Colorize_display_selection(int mode) Print_in_window(4,37," ",MC_Black,MC_Light); Print_in_window(4,57," ",MC_Black,MC_Light); Print_in_window(4,74," ",MC_Black,MC_Light); + Print_in_window(4,91," ",MC_Black,MC_Light); // Partie droite Print_in_window(129,37," ",MC_Black,MC_Light); Print_in_window(129,57," ",MC_Black,MC_Light); Print_in_window(129,74," ",MC_Black,MC_Light); + Print_in_window(129,91," ",MC_Black,MC_Light); // Ensuite, on affiche la flèche là où il le faut: switch(mode) @@ -588,6 +594,9 @@ void Button_Colorize_display_selection(int mode) break; case 2 : // Méthode soustractive y_pos=74; + break; + case 3 : // Méthode alpha + y_pos=91; } Print_in_window(4,y_pos,"\020",MC_Black,MC_Light); Print_in_window(129,y_pos,"\021",MC_Black,MC_Light); @@ -600,7 +609,7 @@ void Button_Colorize_menu(void) short clicked_button; char str[4]; - Open_window(140,118,"Transparency"); + Open_window(140,135,"Transparency"); Print_in_window(16,23,"Opacity:",MC_Dark,MC_Light); Window_set_input_button(87,21,3); // 1 @@ -610,9 +619,10 @@ void Button_Colorize_menu(void) Window_set_normal_button(16,54,108,14,"Additive" ,2,1,SDLK_d); // 3 Window_set_normal_button(16,71,108,14,"Subtractive",1,1,SDLK_s); // 4 + Window_set_normal_button(16,88,108,14,"Alpha",1,1,SDLK_a); // 4 - Window_set_normal_button(16,94, 51,14,"Cancel" ,0,1,KEY_ESC); // 5 - Window_set_normal_button(73,94, 51,14,"OK" ,0,1,SDLK_RETURN); // 6 + Window_set_normal_button(16,111, 51,14,"Cancel" ,0,1,KEY_ESC); // 5 + Window_set_normal_button(73,111, 51,14,"OK" ,0,1,SDLK_RETURN); // 6 Num2str(Colorize_opacity,str,3); Window_input_content(Window_special_button_list,str); @@ -632,7 +642,7 @@ void Button_Colorize_menu(void) { case 1: // Zone de saisie de l'opacité Num2str(chosen_opacity,str,3); - Readline(89,23,str,3,1); + Readline(89,23,str,3,INPUT_TYPE_INTEGER); chosen_opacity=atoi(str); // On corrige le pourcentage if (chosen_opacity>100) @@ -643,9 +653,10 @@ void Button_Colorize_menu(void) } Display_cursor(); break; - case 2: // Méthode interpolée - case 3: // Méthode additive - case 4: // Méthode soustractive + case 2: // Interpolated method + case 3: // Additive method + case 4: // Substractive method + case 5: // Alpha method selected_mode=clicked_button-2; Hide_cursor(); Button_Colorize_display_selection(selected_mode); @@ -654,13 +665,13 @@ void Button_Colorize_menu(void) if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_EFFECTS, "TRANSPARENCY"); else if (Is_shortcut(Key,SPECIAL_COLORIZE_MENU)) - clicked_button=6; + clicked_button=7; } - while (clicked_button<5); + while (clicked_button<6); Close_window(); - if (clicked_button==6) // OK + if (clicked_button==7) // OK { Colorize_opacity =chosen_opacity; Colorize_current_mode=selected_mode; @@ -724,7 +735,7 @@ void Button_Tiling_menu(void) if (clicked_button==3) // Zone de saisie du décalage X { Num2str(chosen_offset_x,str,4); - Readline(93,23,str,4,1); + Readline(93,23,str,4,INPUT_TYPE_INTEGER); chosen_offset_x=atoi(str); // On corrige le décalage en X if (chosen_offset_x>=Brush_width) @@ -739,7 +750,7 @@ void Button_Tiling_menu(void) if (clicked_button==4) // Zone de saisie du décalage Y { Num2str(chosen_offset_y,str,4); - Readline(93,37,str,4,1); + Readline(93,37,str,4,INPUT_TYPE_INTEGER); chosen_offset_y=atoi(str); // On corrige le décalage en Y if (chosen_offset_y>=Brush_height) @@ -975,8 +986,8 @@ void Button_Sieve_menu(void) { clicked_button=Window_clicked_button(); - origin_x=Window_pos_X+(Menu_factor_X*Window_special_button_list->Pos_X); - origin_y=Window_pos_Y+(Menu_factor_Y*Window_special_button_list->Pos_Y); + origin_x=Window_pos_X+(Menu_factor_X*Window_special_button_list->Pos_X); + origin_y=Window_pos_Y+(Menu_factor_Y*Window_special_button_list->Pos_Y); switch (clicked_button) @@ -1063,15 +1074,22 @@ void Button_Sieve_menu(void) break; case 7 : // Transfer to brush - Brush_width=Sieve_width; - Brush_height=Sieve_height; - free(Brush); - Brush=(byte *)malloc(((long)Brush_height)*Brush_width); + + if (Realloc_brush(Sieve_width, Sieve_height, NULL, NULL)) + break; + for (y_pos=0; y_pos>1); Brush_offset_Y=(Brush_height>>1); + Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); break; diff --git a/src/const.h b/src/const.h index e4c60590..69c844ca 100644 --- a/src/const.h +++ b/src/const.h @@ -37,7 +37,6 @@ #define BETA1 98 ///< Version number for gfx2.cfg (3/4) #define BETA2 0 ///< Version number for gfx2.cfg (4/4) #define MAX_VIDEO_MODES 100 ///< Maximum number of video modes Grafx2 can propose. -#define NB_SHORTCUTS 183 ///< Number of actions that can have a key combination associated to it. #define NB_ZOOM_FACTORS 15 ///< Number of zoom levels available in the magnifier. #define MENU_WIDTH 254 ///< Width of the menu (not counting the palette) #define MENU_HEIGHT 44 ///< Height of the menu. @@ -45,9 +44,10 @@ #define CURSOR_SPRITE_WIDTH 15 ///< Width of a mouse cursor sprite. #define CURSOR_SPRITE_HEIGHT 15 ///< Height of a mouse cursor sprite. #define NB_EFFECTS_SPRITES 9 ///< Number of effect sprites. -#define NB_MENU_SPRITES 20 ///< Number of menu sprites. -#define MENU_SPRITE_WIDTH 14 ///< Width of a menu sprite in pixels -#define MENU_SPRITE_HEIGHT 14 ///< Height of a menu sprite in pixels +#define MENU_SPRITE_WIDTH 16 ///< Width of a menu sprite in pixels +#define MENU_SPRITE_HEIGHT 16 ///< Height of a menu sprite in pixels +#define EFFECT_SPRITE_WIDTH 14 ///< Width of an effect sprite in pixels +#define EFFECT_SPRITE_HEIGHT 14 ///< Height of an effect sprite in pixels #define LAYER_SPRITE_WIDTH 14 ///< Width of a layer button in pixels #define LAYER_SPRITE_HEIGHT 10 ///< Height of a layer button in pixels #define PAINTBRUSH_WIDTH 16 ///< Width of a preset paintbrush sprite @@ -120,6 +120,7 @@ enum FILE_FORMATS FORMAT_KCF, FORMAT_PAL, FORMAT_SCR, + FORMAT_XPM, FORMAT_MISC, ///< Must be last of enum: others formats recognized by SDL_image }; @@ -210,9 +211,17 @@ enum PAINTBRUSH_SHAPES PAINTBRUSH_SHAPE_DIAMOND, PAINTBRUSH_SHAPE_SIEVE_ROUND, PAINTBRUSH_SHAPE_SIEVE_SQUARE, + PAINTBRUSH_SHAPE_RESERVED1, ///< Reserved for future use + PAINTBRUSH_SHAPE_RESERVED2, ///< Reserved for future use + PAINTBRUSH_SHAPE_RESERVED3, ///< Reserved for future use + PAINTBRUSH_SHAPE_RESERVED4, ///< Reserved for future use + PAINTBRUSH_SHAPE_RESERVED5, ///< Reserved for future use + PAINTBRUSH_SHAPE_RESERVED6, ///< Reserved for future use + PAINTBRUSH_SHAPE_RESERVED7, ///< Reserved for future use + PAINTBRUSH_SHAPE_RESERVED8, ///< Reserved for future use PAINTBRUSH_SHAPE_MISC, ///< A raw monochrome bitmap, can't be resized. This must be the last of the preset paintbrush types. PAINTBRUSH_SHAPE_POINT, ///< Used to reduce the paintbrush to a single pixel, during operations like floodfill. - PAINTBRUSH_SHAPE_NONE, ///< Used to display no cursor at all (colorpicker) + PAINTBRUSH_SHAPE_NONE, ///< Used to display no cursor at all (colorpicker) PAINTBRUSH_SHAPE_COLOR_BRUSH, ///< User's brush, in color mode PAINTBRUSH_SHAPE_MONO_BRUSH, ///< User's brush, in mono mode PAINTBRUSH_SHAPE_MAX ///< Upper limit. @@ -222,6 +231,8 @@ enum PAINTBRUSH_SHAPES #define BUTTON_RELEASED 0 /// State of a menu button that is being pressed. #define BUTTON_PRESSED 1 +/// State of a button temporarily highligted +#define BUTTON_HIGHLIGHTED 2 /// The different modes of the Shade enum SHADE_MODES @@ -243,7 +254,9 @@ enum CHUNKS_CFG CHUNK_SMOOTH = 6, ///< Smooth effect settings CHUNK_EXCLUDE_COLORS = 7, ///< List of excluded colors CHUNK_QUICK_SHADE = 8, ///< QShade effect settings - CHUNK_GRID = 9, + CHUNK_GRID = 9, ///< Grid settings + CHUNK_BRUSH =10, ///< Paintbrushes + CHUNK_SCRIPTS =11, ///< Callable scripts CHUNK_MAX }; @@ -257,7 +270,8 @@ enum ICON_TYPES ICON_NETWORK, ///< "Network" drive ICON_STAR, ///< Star (favorite) ICON_DROPDOWN, ///< Dropdown arrow - NB_ICON_SPRITES ///< Number of 8x8 icons + NB_ICON_SPRITES, ///< Number of 8x8 icons + ICON_NONE ///< None of the above }; /// Identifiers for the buttons in the menu. @@ -316,6 +330,24 @@ enum BUTTON_NUMBERS NB_BUTTONS ///< Number of buttons in the menu bar. }; +enum MENU_SPRITE +{ + MENU_SPRITE_COLOR_BRUSH=0, + MENU_SPRITE_MONO_BRUSH, + MENU_SPRITE_DISCONTINUOUS_DRAW, + MENU_SPRITE_POINT_DRAW, + MENU_SPRITE_CONTOUR_DRAW, + MENU_SPRITE_4_POINTS_CURVE, + MENU_SPRITE_K_LINE, + MENU_SPRITE_CENTERED_LINES, + MENU_SPRITE_ELLIPSES, + MENU_SPRITE_POLYFORM, + MENU_SPRITE_REPLACE, + MENU_SPRITE_GRAD_ELLIPSE, + MENU_SPRITE_VERTICAL_PALETTE_SCROLL, + NB_MENU_SPRITES ///< Number of menu sprites. +}; + /// /// Identifiers of special actions that can have a keyboard shortcut. /// They are special in the sense that there's no button in the menu for them, @@ -364,6 +396,10 @@ enum SPECIAL_ACTIONS SPECIAL_GET_BRUSH_COLORS, SPECIAL_RECOLORIZE_BRUSH, SPECIAL_ROTATE_ANY_ANGLE, + SPECIAL_BRUSH_DOUBLE, + SPECIAL_BRUSH_DOUBLE_WIDTH, + SPECIAL_BRUSH_DOUBLE_HEIGHT, + SPECIAL_BRUSH_HALVE, SPECIAL_LOAD_BRUSH, SPECIAL_SAVE_BRUSH, SPECIAL_INVERT_SIEVE, @@ -435,8 +471,22 @@ enum SPECIAL_ACTIONS SPECIAL_LAYER7_TOGGLE, SPECIAL_LAYER8_SELECT, SPECIAL_LAYER8_TOGGLE, + SPECIAL_REPEAT_SCRIPT, + SPECIAL_RUN_SCRIPT_1, + SPECIAL_RUN_SCRIPT_2, + SPECIAL_RUN_SCRIPT_3, + SPECIAL_RUN_SCRIPT_4, + SPECIAL_RUN_SCRIPT_5, + SPECIAL_RUN_SCRIPT_6, + SPECIAL_RUN_SCRIPT_7, + SPECIAL_RUN_SCRIPT_8, + SPECIAL_RUN_SCRIPT_9, + SPECIAL_RUN_SCRIPT_10, + SPECIAL_CYCLE_MODE, + SPECIAL_FORMAT_CHECKER, SPECIAL_FORMAT_CHECKER_MENU, + NB_SPECIAL_SHORTCUTS ///< Number of special shortcuts }; @@ -448,7 +498,7 @@ enum OPERATIONS OPERATION_POINT_DRAW, ///< Freehand point-by-point draw OPERATION_FILLED_CONTOUR, ///< Filled contour OPERATION_LINE, ///< Lines - OPERATION_K_LIGNE, ///< Linked lines + OPERATION_K_LINE, ///< Linked lines OPERATION_CENTERED_LINES, ///< Centered lines OPERATION_EMPTY_RECTANGLE, ///< Empty rectangle OPERATION_FILLED_RECTANGLE, ///< Filled rectangle @@ -476,6 +526,7 @@ enum OPERATIONS OPERATION_STRETCH_BRUSH, ///< Stretch brush OPERATION_DISTORT_BRUSH, ///< Distort brush OPERATION_GRAD_RECTANGLE, ///< Gradient-filled rectangle + OPERATION_RMB_COLORPICK, ///< Colorpick on right mouse button NB_OPERATIONS ///< Number of operations handled by the engine }; diff --git a/src/engine.c b/src/engine.c index 514d4ea8..3c71c13a 100644 --- a/src/engine.c +++ b/src/engine.c @@ -40,6 +40,10 @@ #include "engine.h" #include "pages.h" #include "layers.h" +#include "factory.h" +#include "loadsave.h" +#include "io.h" + // we need this as global @@ -210,19 +214,20 @@ int Button_under_mouse(void) } -///Draw the frame for a menu button -void Draw_menu_button_frame(byte btn_number,byte pressed) +///Draw a menu button, selected or not +void Draw_menu_button(byte btn_number,byte pressed) { - byte color_top_left; - byte color_bottom_right; - byte color_diagonal; word start_x; word start_y; - word end_x; - word end_y; + word width; + word height; + byte * bitmap; + word bitmap_width; word x_pos; word y_pos; byte current_menu; + byte color; + char icon; // Find in which menu the button is for (current_menu = 0; current_menu < MENUBAR_COUNT; current_menu++) @@ -235,22 +240,114 @@ void Draw_menu_button_frame(byte btn_number,byte pressed) } } - start_x=Buttons_Pool[btn_number].X_offset; - start_y=Buttons_Pool[btn_number].Y_offset; - end_x =start_x+Buttons_Pool[btn_number].Width; - end_y =start_y+Buttons_Pool[btn_number].Height; + start_x = Buttons_Pool[btn_number].X_offset; + start_y = Buttons_Pool[btn_number].Y_offset; + width = Buttons_Pool[btn_number].Width+1; + height = Buttons_Pool[btn_number].Height+1; + icon = Buttons_Pool[btn_number].Icon; - if (!pressed) + if (icon==-1) { - color_top_left=MC_White; - color_bottom_right=MC_Dark; - color_diagonal=MC_Light; + // Standard button + bitmap_width = Menu_bars[current_menu].Skin_width; + bitmap=&(Menu_bars[current_menu].Skin[pressed][start_y*Menu_bars[current_menu].Skin_width+start_x]); } else { + // From Menu_buttons + bitmap_width = MENU_SPRITE_WIDTH; + bitmap=Gfx->Menu_sprite[pressed][(byte)icon][0]; + // For bottom right: offset +1,+1 + if (Buttons_Pool[btn_number].Shape==BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT) + bitmap += MENU_SPRITE_WIDTH+1; + } + + switch(Buttons_Pool[btn_number].Shape) + { + case BUTTON_SHAPE_NO_FRAME : + break; + case BUTTON_SHAPE_RECTANGLE : + for (y_pos=0;y_posPages); + + flimit = Find_last_slash(Drop_file_name); + *(flimit++) = '\0'; + + Hide_cursor(); + old_cursor_shape=Cursor_shape; + Cursor_shape=CURSOR_SHAPE_HOURGLASS; + Display_cursor(); + + Init_context_layered_image(&context, flimit, Drop_file_name); + Load_image(&context); + if (File_error!=1) + { + Compute_limits(); + Compute_paintbrush_coordinates(); + Redraw_layered_image(); + End_of_modification(); + Display_all_screen(); + Main_image_is_modified=0; + } + Destroy_context(&context); + + Compute_optimal_menu_colors(Main_palette); + Display_menu(); + if (Config.Display_image_limits) + Display_image_limits(); + + Hide_cursor(); + Cursor_shape=old_cursor_shape; + Display_all_screen(); + Display_cursor(); + } + free(Drop_file_name); + Drop_file_name=NULL; + } - if(Get_input()) + if(Get_input(0)) { action = 0; @@ -732,13 +894,17 @@ void Main_handler(void) break; case SPECIAL_FLIP_X : // Flip X Hide_cursor(); - Flip_X_lowlevel(Brush, Brush_width, Brush_height); + Flip_X_lowlevel(Brush_original_pixels, Brush_width, Brush_height); + // Remap according to the last used remap table + Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); Display_cursor(); action++; break; case SPECIAL_FLIP_Y : // Flip Y Hide_cursor(); - Flip_Y_lowlevel(Brush, Brush_width, Brush_height); + Flip_Y_lowlevel(Brush_original_pixels, Brush_width, Brush_height); + // Remap according to the last used remap table + Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); Display_cursor(); action++; break; @@ -751,6 +917,8 @@ void Main_handler(void) case SPECIAL_ROTATE_180 : // 180° brush rotation Hide_cursor(); Rotate_180_deg_lowlevel(Brush, Brush_width, Brush_height); + // Remap according to the last used remap table + Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); Brush_offset_X=(Brush_width>>1); Brush_offset_Y=(Brush_height>>1); Display_cursor(); @@ -774,6 +942,46 @@ void Main_handler(void) Display_cursor(); action++; break; + case SPECIAL_BRUSH_DOUBLE: + if (Paintbrush_shape==PAINTBRUSH_SHAPE_COLOR_BRUSH + || Paintbrush_shape==PAINTBRUSH_SHAPE_MONO_BRUSH) + { + Hide_cursor(); + Stretch_brush(1,1,Brush_width*2,Brush_height*2); + Display_cursor(); + } + action++; + break; + case SPECIAL_BRUSH_DOUBLE_WIDTH: + if (Paintbrush_shape==PAINTBRUSH_SHAPE_COLOR_BRUSH + || Paintbrush_shape==PAINTBRUSH_SHAPE_MONO_BRUSH) + { + Hide_cursor(); + Stretch_brush(1,1,Brush_width*2,Brush_height); + Display_cursor(); + } + action++; + break; + case SPECIAL_BRUSH_DOUBLE_HEIGHT: + if (Paintbrush_shape==PAINTBRUSH_SHAPE_COLOR_BRUSH + || Paintbrush_shape==PAINTBRUSH_SHAPE_MONO_BRUSH) + { + Hide_cursor(); + Stretch_brush(1,1,Brush_width,Brush_height*2); + Display_cursor(); + } + action++; + break; + case SPECIAL_BRUSH_HALVE: + if (Paintbrush_shape==PAINTBRUSH_SHAPE_COLOR_BRUSH + || Paintbrush_shape==PAINTBRUSH_SHAPE_MONO_BRUSH) + { + Hide_cursor(); + Stretch_brush(1,1,Brush_width/2,Brush_height/2); + Display_cursor(); + } + action++; + break; case SPECIAL_OUTLINE : // Outline brush Hide_cursor(); Outline_brush(); @@ -1088,6 +1296,36 @@ void Main_handler(void) C64_FLI_enforcer(); action++; break; + + case SPECIAL_REPEAT_SCRIPT: +#ifdef __ENABLE_LUA__ + Repeat_script(); + action++; +#endif + break; + case SPECIAL_RUN_SCRIPT_1: + case SPECIAL_RUN_SCRIPT_2: + case SPECIAL_RUN_SCRIPT_3: + case SPECIAL_RUN_SCRIPT_4: + case SPECIAL_RUN_SCRIPT_5: + case SPECIAL_RUN_SCRIPT_6: + case SPECIAL_RUN_SCRIPT_7: + case SPECIAL_RUN_SCRIPT_8: + case SPECIAL_RUN_SCRIPT_9: + case SPECIAL_RUN_SCRIPT_10: +#ifdef __ENABLE_LUA__ + Run_numbered_script(key_index-SPECIAL_RUN_SCRIPT_1); + action++; +#endif + break; + case SPECIAL_CYCLE_MODE: + Cycling_mode= !Cycling_mode; + // Restore palette + if (!Cycling_mode) + Set_palette(Main_palette); + action++; + break; + } } } // End of special keys @@ -1122,7 +1360,7 @@ void Main_handler(void) if (effect_modified) { Hide_cursor(); - Draw_menu_button_frame(BUTTON_EFFECTS, + Draw_menu_button(BUTTON_EFFECTS, (Shade_mode||Quick_shade_mode||Colorize_mode||Smooth_mode||Tiling_mode||Smear_mode||Stencil_mode||Mask_mode||Sieve_mode||Snap_mode)); Display_cursor(); } @@ -1132,21 +1370,8 @@ void Main_handler(void) } else { - // No event : we go asleep for a while, but we try to get waked up at constant intervals of time - // no matter the machine speed or system load. The time is fixed to 10ms (that should be about a cpu slice on most systems) - // This allows nice smooth mouse movement. - const int delay = 10; - - Uint32 debut; - debut = SDL_GetTicks(); - // Première attente : le complément de "delay" millisecondes - SDL_Delay(delay - (debut % delay)); - // Si ça ne suffit pas, on complète par des attentes successives de "1ms". - // (Remarque, Windows arrondit généralement aux 10ms supérieures) - while ( SDL_GetTicks()/delay <= debut/delay) - { - SDL_Delay(1); - } + // Removed all SDL_Delay() timing here: relying on Get_input() + SDL_Delay(10); } // Gestion de la souris @@ -1175,6 +1400,11 @@ void Main_handler(void) { // On nettoie les coordonnées Hide_cursor(); + + /*if (Gfx->Hover_effect && prev_button_number > -1 && !Buttons_Pool[prev_button_number].Pressed) + Draw_menu_button(prev_button_number, BUTTON_RELEASED); + */ + Block(18*Menu_factor_X,Menu_status_Y,192*Menu_factor_X,Menu_factor_Y<<3,MC_Light); Update_rect(18*Menu_factor_X,Menu_status_Y,192*Menu_factor_X,Menu_factor_Y<<3); Display_cursor(); @@ -1190,7 +1420,17 @@ void Main_handler(void) if (button_index!=BUTTON_CHOOSE_COL) { Hide_cursor(); + + /*if (Gfx->Hover_effect && prev_button_number > -1 && !Buttons_Pool[prev_button_number].Pressed) + Draw_menu_button(prev_button_number, BUTTON_RELEASED); + */ + Print_in_menu(Menu_tooltip[button_index],0); + + /*if (Gfx->Hover_effect && !Buttons_Pool[button_index].Pressed) + Draw_menu_button(button_index, BUTTON_HIGHLIGHTED); + */ + Display_cursor(); } else @@ -1245,21 +1485,27 @@ void Main_handler(void) // Le curseur se trouve dans l'image if ( (!Cursor_in_menu) && (Menu_is_visible) && (Old_MY != Mouse_Y || Old_MX != Mouse_X || Key || Mouse_K)) // On ne met les coordonnées à jour que si l'utilisateur a fait un truc { - if ( (Current_operation!=OPERATION_COLORPICK) && (Current_operation!=OPERATION_REPLACE) ) - { - if(Cursor_in_menu_previous) - { - Print_in_menu("X: Y: ",0); - } - } - else - { - if(Cursor_in_menu_previous) - { - Print_in_menu("X: Y: ( )",0); - } - } - Cursor_in_menu_previous = 0; + if(Cursor_in_menu_previous) + { + Hide_cursor(); + + /*if (Gfx->Hover_effect && prev_button_number > -1 && !Buttons_Pool[prev_button_number].Pressed) + Draw_menu_button(prev_button_number, BUTTON_RELEASED); + */ + + if ( (Current_operation!=OPERATION_COLORPICK) && (Current_operation!=OPERATION_REPLACE) ) + { + Print_in_menu("X: Y: ",0); + } + else + { + Print_in_menu("X: Y: ( )",0); + } + + Display_cursor(); + + Cursor_in_menu_previous = 0; + } } if(Cursor_in_menu) @@ -1300,7 +1546,17 @@ void Open_window(word width,word height, const char * title) size_t title_length; Hide_cursor(); - + + /*if (Windows_open == 0 && Gfx->Hover_effect) + { + if (Cursor_in_menu) + { + int button_index=Button_under_mouse(); + if (button_index > -1 && !Buttons_Pool[button_index].Pressed) + Draw_menu_button(button_index, BUTTON_RELEASED); + } + }*/ + Windows_open++; Window_width=width; @@ -1310,12 +1566,14 @@ void Open_window(word width,word height, const char * title) Window_pos_X=(Screen_width-(width*Menu_factor_X))>>1; Window_pos_Y=(Screen_height-(height*Menu_factor_Y))>>1; + + Window_draggable=1; // Sauvegarde de ce que la fenêtre remplace Save_background(&(Window_background[Windows_open-1]), Window_pos_X, Window_pos_Y, width, height); // Fenêtre grise - Block(Window_pos_X+(Menu_factor_X<<1),Window_pos_Y+(Menu_factor_Y<<1),(width-4)*Menu_factor_X,(height-4)*Menu_factor_Y,MC_Light); + Block(Window_pos_X+(Menu_factor_X<<1),Window_pos_Y+(Menu_factor_Y<<1),(width-4)*Menu_factor_X,(height-4)*Menu_factor_Y,MC_Window); // -- Frame de la fenêtre ----- --- -- - - @@ -1342,6 +1600,13 @@ void Open_window(word width,word height, const char * title) Cursor_shape=CURSOR_SHAPE_ARROW; Paintbrush_hidden_before_window=Paintbrush_hidden; Paintbrush_hidden=1; + if (Allow_colorcycling) + { + Allow_colorcycling=0; + // Restore palette + Set_palette(Main_palette); + } + Allow_drag_and_drop(0); } // Initialisation des listes de boutons de la fenêtre @@ -1431,6 +1696,8 @@ void Close_window(void) Display_all_screen(); Display_menu(); + Allow_colorcycling=1; + Allow_drag_and_drop(1); } Key=0; @@ -1445,7 +1712,7 @@ void Close_window(void) //---------------- Dessiner un bouton normal dans une fenêtre ---------------- void Window_draw_normal_bouton(word x_pos,word y_pos,word width,word height, - char * title,byte undersc_letter,byte clickable) + const char * title,byte undersc_letter,byte clickable) { byte title_color; word text_x_pos,text_y_pos; @@ -1532,14 +1799,14 @@ void Tag_color_range(byte start,byte end) // On efface les anciens TAGs for (index=0;index<=start;index++) - Block(Window_pos_X+(Window_palette_button_list->Pos_X+3+((index>>4)*10))*Menu_factor_X, - Window_pos_Y+(Window_palette_button_list->Pos_Y+3+((index&15)* 5))*Menu_factor_Y, - Menu_factor_X*3,Menu_factor_Y*5,MC_Light); + Window_rectangle(Window_palette_button_list->Pos_X+3+((index>>4)*10), + Window_palette_button_list->Pos_Y+3+((index&15)* 5), + 3,5,MC_Light); for (index=end;index<256;index++) - Block(Window_pos_X+(Window_palette_button_list->Pos_X+3+((index>>4)*10))*Menu_factor_X, - Window_pos_Y+(Window_palette_button_list->Pos_Y+3+((index&15)* 5))*Menu_factor_Y, - Menu_factor_X*3,Menu_factor_Y*5,MC_Light); + Window_rectangle(Window_palette_button_list->Pos_X+3+((index>>4)*10), + Window_palette_button_list->Pos_Y+3+((index&15)* 5), + 3,5,MC_Light); // On affiche le 1er TAG origin_x=(Window_palette_button_list->Pos_X+3)+(start>>4)*10; @@ -1567,9 +1834,9 @@ void Tag_color_range(byte start,byte end) // On TAG toutes les couleurs intermédiaires for (index=start+1;indexPos_X+3+((index>>4)*10))*Menu_factor_X, - Window_pos_Y+(Window_palette_button_list->Pos_Y+3+((index&15)* 5))*Menu_factor_Y, - Menu_factor_X*2,Menu_factor_Y*5,MC_Black); + Window_rectangle(Window_palette_button_list->Pos_X+3+((index>>4)*10), + Window_palette_button_list->Pos_Y+3+((index&15)* 5), + 2,5,MC_Black); // On efface l'éventuelle pointe d'une ancienne extrémité de l'intervalle Pixel_in_window(Window_palette_button_list->Pos_X+5+((index>>4)*10), Window_palette_button_list->Pos_Y+5+((index&15)* 5), @@ -1579,24 +1846,24 @@ void Tag_color_range(byte start,byte end) } - Update_rect(ToWinX(Window_palette_button_list->Pos_X+3),ToWinY(Window_palette_button_list->Pos_Y+3),ToWinL(12*16),ToWinH(5*16)); + Update_window_area(Window_palette_button_list->Pos_X+3,Window_palette_button_list->Pos_Y+3,12*16,5*16); } //------------------ Dessiner un scroller dans une fenêtre ------------------- -void Compute_slider_cursor_height(T_Scroller_button * button) +void Compute_slider_cursor_length(T_Scroller_button * button) { if (button->Nb_elements>button->Nb_visibles) { - button->Cursor_height=(button->Nb_visibles*(button->Height-24))/button->Nb_elements; - if (!(button->Cursor_height)) - button->Cursor_height=1; + button->Cursor_length=(button->Nb_visibles*(button->Length-24))/button->Nb_elements; + if (!(button->Cursor_length)) + button->Cursor_length=1; } else { - button->Cursor_height=button->Height-24; + button->Cursor_length=button->Length-24; } } @@ -1604,32 +1871,70 @@ void Window_draw_slider(T_Scroller_button * button) { word slider_position; - slider_position=button->Pos_Y+12; - - Block(Window_pos_X+(button->Pos_X*Menu_factor_X), - Window_pos_Y+(slider_position*Menu_factor_Y), - 11*Menu_factor_X,(button->Height-24)*Menu_factor_Y,MC_Black/*MC_Dark*/); - - if (button->Nb_elements>button->Nb_visibles) - slider_position+=Round_div(button->Position*(button->Height-24-button->Cursor_height),button->Nb_elements-button->Nb_visibles); - - Block(Window_pos_X+(button->Pos_X*Menu_factor_X), - Window_pos_Y+(slider_position*Menu_factor_Y), - 11*Menu_factor_X,button->Cursor_height*Menu_factor_Y,MC_Dark/*MC_White*/); - - Update_rect(Window_pos_X+(button->Pos_X*Menu_factor_X), - Window_pos_Y+button->Pos_Y*Menu_factor_Y, - 11*Menu_factor_X,(button->Height)*Menu_factor_Y); + if (button->Is_horizontal) + { + slider_position=button->Pos_X+12; + + Window_rectangle(slider_position, + button->Pos_Y, + button->Length-24,11,MC_Black/*MC_Dark*/); + + if (button->Nb_elements>button->Nb_visibles) + slider_position+= + ((button->Length-24-button->Cursor_length)*(button->Position)+(button->Nb_elements-button->Nb_visibles)/2)/(button->Nb_elements-button->Nb_visibles); + + Window_rectangle(slider_position, + button->Pos_Y, + button->Cursor_length,11,MC_OnBlack/*MC_White*/); + + Update_window_area(button->Pos_X, + button->Pos_Y, + button->Length,11); + } + else + { + slider_position=button->Pos_Y+12; + + Window_rectangle(button->Pos_X, + slider_position, + 11,button->Length-24,MC_Black/*MC_Dark*/); + + if (button->Nb_elements>button->Nb_visibles) + slider_position+= + ((button->Length-24-button->Cursor_length)*(button->Position)+(button->Nb_elements-button->Nb_visibles)/2)/(button->Nb_elements-button->Nb_visibles); + // + //(button->Position*) / (button->Nb_elements-button->Nb_visibles)); + + Window_rectangle(button->Pos_X, + slider_position, + 11,button->Cursor_length,MC_OnBlack/*MC_White*/); + + Update_window_area(button->Pos_X, + button->Pos_Y, + 11,button->Length); + } } -void Window_draw_scroller_bouton(T_Scroller_button * button) +void Window_draw_scroller_button(T_Scroller_button * button) { - Window_display_frame_generic(button->Pos_X-1,button->Pos_Y-1,13,button->Height+2,MC_Black,MC_Black,MC_Dark,MC_Dark,MC_Dark); - Window_display_frame_mono(button->Pos_X-1,button->Pos_Y+11,13,button->Height-22,MC_Black); - Window_display_frame_out(button->Pos_X,button->Pos_Y,11,11); - Window_display_frame_out(button->Pos_X,button->Pos_Y+button->Height-11,11,11); - Print_in_window(button->Pos_X+2,button->Pos_Y+2,"\030",MC_Black,MC_Light); - Print_in_window(button->Pos_X+2,button->Pos_Y+button->Height-9,"\031",MC_Black,MC_Light); + if (button->Is_horizontal) + { + Window_display_frame_generic(button->Pos_X-1,button->Pos_Y-1,button->Length+2,13,MC_Black,MC_Black,MC_Dark,MC_Dark,MC_Dark); + Window_display_frame_mono(button->Pos_X+11,button->Pos_Y-1,button->Length-22,13,MC_Black); + Window_display_frame_out(button->Pos_X,button->Pos_Y,11,11); + Window_display_frame_out(button->Pos_X+button->Length-11,button->Pos_Y,11,11); + Print_in_window(button->Pos_X+2,button->Pos_Y+2,"\033",MC_Black,MC_Light); + Print_in_window(button->Pos_X+button->Length-9,button->Pos_Y+2,"\032",MC_Black,MC_Light); + } + else + { + Window_display_frame_generic(button->Pos_X-1,button->Pos_Y-1,13,button->Length+2,MC_Black,MC_Black,MC_Dark,MC_Dark,MC_Dark); + Window_display_frame_mono(button->Pos_X-1,button->Pos_Y+11,13,button->Length-22,MC_Black); + Window_display_frame_out(button->Pos_X,button->Pos_Y,11,11); + Window_display_frame_out(button->Pos_X,button->Pos_Y+button->Length-11,11,11); + Print_in_window(button->Pos_X+2,button->Pos_Y+2,"\030",MC_Black,MC_Light); + Print_in_window(button->Pos_X+2,button->Pos_Y+button->Length-9,"\031",MC_Black,MC_Light); + } Window_draw_slider(button); } @@ -1662,7 +1967,7 @@ void Window_clear_input_button(T_Special_button * button) T_Normal_button * Window_set_normal_button(word x_pos, word y_pos, word width, word height, - char * title, byte undersc_letter, + const char * title, byte undersc_letter, byte clickable, word shortcut) { T_Normal_button * temp=NULL; @@ -1692,7 +1997,7 @@ T_Normal_button * Window_set_normal_button(word x_pos, word y_pos, T_Normal_button * Window_set_repeatable_button(word x_pos, word y_pos, word width, word height, - char * title, byte undersc_letter, + const char * title, byte undersc_letter, byte clickable, word shortcut) { T_Normal_button * temp=NULL; @@ -1745,21 +2050,47 @@ T_Scroller_button * Window_set_scroller_button(word x_pos, word y_pos, temp=(T_Scroller_button *)malloc(sizeof(T_Scroller_button)); temp->Number =++Window_nb_buttons; + temp->Is_horizontal =0; temp->Pos_X =x_pos; temp->Pos_Y =y_pos; - temp->Height =height; + temp->Length =height; temp->Nb_elements =nb_elements; temp->Nb_visibles =nb_elements_visible; temp->Position =initial_position; - Compute_slider_cursor_height(temp); + Compute_slider_cursor_length(temp); temp->Next=Window_scroller_button_list; Window_scroller_button_list=temp; - Window_draw_scroller_bouton(temp); + Window_draw_scroller_button(temp); return temp; } +T_Scroller_button * Window_set_horizontal_scroller_button(word x_pos, word y_pos, + word width, + word nb_elements, + word nb_elements_visible, + word initial_position) +{ + T_Scroller_button * temp; + + temp=(T_Scroller_button *)malloc(sizeof(T_Scroller_button)); + temp->Number =++Window_nb_buttons; + temp->Is_horizontal =1; + temp->Pos_X =x_pos; + temp->Pos_Y =y_pos; + temp->Length =width; + temp->Nb_elements =nb_elements; + temp->Nb_visibles =nb_elements_visible; + temp->Position =initial_position; + Compute_slider_cursor_length(temp); + + temp->Next=Window_scroller_button_list; + Window_scroller_button_list=temp; + + Window_draw_scroller_button(temp); + return temp; +} T_Special_button * Window_set_special_button(word x_pos,word y_pos,word width,word height) { @@ -1888,6 +2219,15 @@ void Window_redraw_list(T_List_button * list) list->List_start + i, i == list->Cursor_position); } + // Remaining rectangle under list + i=list->Scroller->Nb_visibles-list->Scroller->Nb_elements; + if (i>0) + Window_rectangle( + list->Entry_button->Pos_X, + list->Entry_button->Pos_Y+list->Scroller->Nb_elements*8, + list->Entry_button->Width, + i*8, + MC_Light); } //----------------------- Ouverture d'un pop-up ----------------------- @@ -1908,6 +2248,7 @@ void Open_popup(word x_pos, word y_pos, word width,word height) Window_height=height; Window_pos_X=x_pos; Window_pos_Y=y_pos; + Window_draggable=0; // Sauvegarde de ce que la fenêtre remplace Save_background(&(Window_background[Windows_open-1]), Window_pos_X, Window_pos_Y, width, height); @@ -2074,7 +2415,8 @@ short Wait_click_in_palette(T_Palette_button * button) for (;;) { - while(!Get_input())SDL_Delay(20); + while (Get_input(20)) + ; if (Mouse_K==LEFT_SIDE) { @@ -2155,7 +2497,7 @@ void Get_color_behind_window(byte * color, byte * click) do { - if(!Get_input())SDL_Delay(20); + Get_input(20); if ((Mouse_X!=old_x) || (Mouse_Y!=old_y)) { @@ -2242,7 +2584,10 @@ void Move_window(short dx, short dy) old_x=new_x; old_y=new_y; - while(!Get_input() && new_x==Mouse_X-dx && new_y==Mouse_Y-dy) SDL_Delay(20); + do + { + Get_input(20); + } while(Mouse_K && new_x==Mouse_X-dx && new_y==Mouse_Y-dy); new_x=Mouse_X-dx; @@ -2444,7 +2789,7 @@ T_Dropdown_choice * Dropdown_activate(T_Dropdown_button *button, short off_x, sh do { // Attente - if(!Get_input()) SDL_Delay(20); + Get_input(20); // Mise à jour du survol selected_index=Window_click_in_rectangle(2,2,button->Dropdown_width-2,box_height-1)? (((Mouse_Y-Window_pos_Y)/Menu_factor_Y-2)>>3) : -1; @@ -2515,7 +2860,7 @@ short Window_normal_button_onclick(word x_pos, word y_pos, word width, word heig Display_cursor(); while (Window_click_in_rectangle(x_pos,y_pos,x_pos+width-1,y_pos+height-1)) { - if(!Get_input()) SDL_Delay(20); + Get_input(20); if (!Mouse_K) { Hide_cursor(); @@ -2529,7 +2874,7 @@ short Window_normal_button_onclick(word x_pos, word y_pos, word width, word heig Display_cursor(); while (!(Window_click_in_rectangle(x_pos,y_pos,x_pos+width-1,y_pos+height-1))) { - if(!Get_input()) SDL_Delay(20); + Get_input(20); if (!Mouse_K) return 0; } @@ -2545,8 +2890,6 @@ short Window_get_clicked_button(void) T_Special_button * temp4; T_Dropdown_button * temp5; - long max_slider_height; - Window_attribute1=Mouse_K; // Test click on normal buttons @@ -2561,7 +2904,7 @@ short Window_get_clicked_button(void) Hide_cursor(); Window_select_normal_button(temp1->Pos_X,temp1->Pos_Y,temp1->Width,temp1->Height); Display_cursor(); - Slider_timer((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider); + Delay_with_active_mouse((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider); Hide_cursor(); Window_unselect_normal_button(temp1->Pos_X,temp1->Pos_Y,temp1->Width,temp1->Height); Display_cursor(); @@ -2585,7 +2928,7 @@ short Window_get_clicked_button(void) } } - // Test click oin slider/scroller bars + // Test click on slider/scroller bars for (temp3=Window_scroller_button_list; temp3; temp3=temp3->Next) { // Button Up arrow @@ -2608,7 +2951,7 @@ short Window_get_clicked_button(void) Display_cursor(); - Slider_timer((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider); + Delay_with_active_mouse((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider); Hide_cursor(); Window_unselect_normal_button(temp3->Pos_X,temp3->Pos_Y,11,11); @@ -2619,12 +2962,16 @@ short Window_get_clicked_button(void) // Button Down arrow if ((Input_sticky_control == 0 || Input_sticky_control == (temp3->Number|2048)) - && Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y+temp3->Height-11,temp3->Pos_X+10,temp3->Pos_Y+temp3->Height-1)) + && ((temp3->Is_horizontal && Window_click_in_rectangle(temp3->Pos_X+temp3->Length-11,temp3->Pos_Y,temp3->Pos_X+temp3->Length-1,temp3->Pos_Y+10)) + || (!temp3->Is_horizontal && Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y+temp3->Length-11,temp3->Pos_X+10,temp3->Pos_Y+temp3->Length-1)))) { Input_sticky_control = temp3->Number | 2048; Hide_cursor(); - Window_select_normal_button(temp3->Pos_X,temp3->Pos_Y+temp3->Height-11,11,11); - + if (temp3->Is_horizontal) + Window_select_normal_button(temp3->Pos_X+temp3->Length-11,temp3->Pos_Y,11,11); + else + Window_select_normal_button(temp3->Pos_X,temp3->Pos_Y+temp3->Length-11,11,11); + if (temp3->Position+temp3->Nb_visiblesNb_elements) { temp3->Position++; @@ -2637,38 +2984,50 @@ short Window_get_clicked_button(void) Display_cursor(); - Slider_timer((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider); + Delay_with_active_mouse((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider); Hide_cursor(); - Window_unselect_normal_button(temp3->Pos_X,temp3->Pos_Y+temp3->Height-11,11,11); + if (temp3->Is_horizontal) + Window_unselect_normal_button(temp3->Pos_X+temp3->Length-11,temp3->Pos_Y,11,11); + else + Window_unselect_normal_button(temp3->Pos_X,temp3->Pos_Y+temp3->Length-11,11,11); Display_cursor(); return (Window_attribute1)? temp3->Number : 0; } // Middle slider if ((Input_sticky_control == temp3->Number) || (Input_sticky_control==0 && - Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y+12,temp3->Pos_X+10,temp3->Pos_Y+temp3->Height-13))) + ((!temp3->Is_horizontal && Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y+12,temp3->Pos_X+10,temp3->Pos_Y+temp3->Length-13)) + ||(temp3->Is_horizontal && Window_click_in_rectangle(temp3->Pos_X+12,temp3->Pos_Y,temp3->Pos_X+temp3->Length-13,temp3->Pos_Y+10))))) { Input_sticky_control = temp3->Number; if (temp3->Nb_elements>temp3->Nb_visibles) { // If there is enough room to make the cursor move: - - max_slider_height=(temp3->Height-24); + long mouse_pos; + long origin; // Window_attribute2 receives the position of the cursor. - Window_attribute2 =(Mouse_Y-Window_pos_Y) / Menu_factor_Y; - Window_attribute2-=(temp3->Pos_Y+12+((temp3->Cursor_height-1)>>1)); - Window_attribute2*=(temp3->Nb_elements-temp3->Nb_visibles); + if (temp3->Is_horizontal) + mouse_pos =(Mouse_X-Window_pos_X) / Menu_factor_X - (temp3->Pos_X+12); + else + mouse_pos =(Mouse_Y-Window_pos_Y) / Menu_factor_Y - (temp3->Pos_Y+12); + // The following formula is wicked. The issue is that you want two + // different behaviors: + // *) If the range is bigger than the pixel precision, the last pixel + // should map to max value, exactly. + // *) Otherwise, the possible cursor positions are separated by + // at least one full pixel, so we should find the valid position + // closest to the center of the mouse cursor position pixel. + + origin = (temp3->Nb_visibles-1)*(temp3->Length-24)/temp3->Nb_elements/2; + Window_attribute2 = (mouse_pos - origin) * (temp3->Nb_elements-(temp3->Cursor_length>1?0:1)) / (temp3->Length-24-1); + if (Window_attribute2<0) Window_attribute2=0; - else - { - Window_attribute2 =Round_div(Window_attribute2,max_slider_height-temp3->Cursor_height); - if (Window_attribute2+temp3->Nb_visibles>temp3->Nb_elements) - Window_attribute2=temp3->Nb_elements-temp3->Nb_visibles; - } + else if (Window_attribute2+temp3->Nb_visibles>temp3->Nb_elements) + Window_attribute2=temp3->Nb_elements-temp3->Nb_visibles; // If the cursor moved @@ -2743,7 +3102,7 @@ short Window_get_button_shortcut(void) Window_select_normal_button(temp->Pos_X,temp->Pos_Y,temp->Width,temp->Height); Display_cursor(); - Slider_timer(Config.Delay_right_click_on_slider); + Delay_with_active_mouse(Config.Delay_right_click_on_slider); Hide_cursor(); Window_unselect_normal_button(temp->Pos_X,temp->Pos_Y,temp->Width,temp->Height); @@ -2793,7 +3152,7 @@ short Window_clicked_button(void) { short Button; - if(!Get_input())SDL_Delay(20); + Get_input(20); // Handle clicks if (Mouse_K) @@ -2813,7 +3172,7 @@ short Window_clicked_button(void) } } - if (!Input_sticky_control && Mouse_Y < Window_pos_Y+(12*Menu_factor_Y)) + if (!Input_sticky_control && Window_draggable && Mouse_Y < Window_pos_Y+(12*Menu_factor_Y)) { Move_window(Mouse_X-Window_pos_X,Mouse_Y-Window_pos_Y); } @@ -3084,17 +3443,17 @@ void Remap_window_backgrounds(byte * conversion_table, int Min_Y, int Max_Y) EDI = Window_background[window_index]; // Pour chaque ligne - for(dx=0; dxMax_Y) + if (dx+Window_stack[window_index].Pos_Y>Max_Y) return; - if (dx+Window_stack_pos_Y[window_index]0;cx--) + for(cx=Window_stack[window_index].Width*Menu_factor_X*Pixel_width;cx>0;cx--) { *EDI = conversion_table[*EDI]; EDI ++; @@ -3102,3 +3461,16 @@ void Remap_window_backgrounds(byte * conversion_table, int Min_Y, int Max_Y) } } } + +void Delay_with_active_mouse(int speed) +{ + Uint32 end; + byte original_mouse_k = Mouse_K; + + end = SDL_GetTicks()+speed*10; + + do + { + Get_input(20); + } while (Mouse_K == original_mouse_k && SDL_GetTicks() @@ -50,11 +53,14 @@ #include #include // for DBL_MAX #include // chdir() +#include //for INT_MIN /// /// Number of characters for name in fileselector. /// Window is adjusted according to it. #define NAME_WIDTH 34 +/// Number of characters for the description block +#define DESC_WIDTH ((NAME_WIDTH+2)*8/6) /// Position of fileselector top, in window space #define FILESEL_Y 18 @@ -64,6 +70,8 @@ static word Brush_backup_width; static word Brush_backup_height; static byte Palette_has_changed; static byte Brush_was_altered; +static byte Original_fore_color; +static byte Original_back_color; /// Helper function to clamp a double to 0-255 range static inline byte clamp_byte(double value) @@ -109,6 +117,18 @@ do { \ dest = lua_tostring(L, (index)); \ } while (0) +/// +/// This macro checks that a Lua argument is a function. +/// If argument is invalid, it will break the caller and raise a verbose message. +/// This macro uses 2 existing symbols: L for the context, and nb_args=lua_gettop(L) +/// @param index Index of the argument to check, starting at 1. +/// @param func_name The name of the lua callback, to display a message in case of error. +#define LUA_ARG_FUNCTION(index, func_name) \ +do { \ + if (nb_args < (index)) return luaL_error(L, "%s: Argument %d is missing.", func_name, index); \ + if (!lua_isfunction(L, (index))) return luaL_error(L, "%s: Argument %d is not a function.", func_name, index); \ +} while (0) + /// Check if 'num' arguments were provided exactly #define LUA_ARG_LIMIT(num, func_name) \ do { \ @@ -116,7 +136,17 @@ do { \ return luaL_error(L, "%s: Expected %d arguments, but found %d.", func_name, (num), nb_args); \ } while(0) - +// Updates the screen colors after a running screen has modified the palette. +void Update_colors_during_script(void) +{ + if (Palette_has_changed) + { + Set_palette(Main_palette); + Compute_optimal_menu_colors(Main_palette); + Display_menu(); + Palette_has_changed=0; + } +} // Wrapper functions to call C from Lua @@ -131,13 +161,18 @@ int L_SetBrushSize(lua_State* L) LUA_ARG_NUMBER(1, "setbrushsize", w, 1, 10000); LUA_ARG_NUMBER(2, "setbrushsize", h, 1, 10000); - if (Realloc_brush(w, h)) + if (Realloc_brush(w, h, NULL, NULL)) { return luaL_error(L, "setbrushsize: Resize failed"); } Brush_was_altered=1; // Fill with Back_color - memset(Brush,Back_color,(long)Brush_width*Brush_height); + memset(Brush_original_pixels,Back_color,(long)Brush_width*Brush_height); + // Grab palette + memcpy(Brush_original_palette, Main_palette,sizeof(T_Palette)); + // Remap (no change) + Remap_brush(); + // Center the handle Brush_offset_X=(Brush_width>>1); Brush_offset_Y=(Brush_height>>1); @@ -169,7 +204,19 @@ int L_PutBrushPixel(lua_State* L) LUA_ARG_NUMBER(2, "putbrushpixel", y, INT_MIN, INT_MAX); LUA_ARG_NUMBER(3, "putbrushpixel", c, INT_MIN, INT_MAX); - Brush_was_altered=1; + if (!Brush_was_altered) + { + int i; + + // First time writing in brush: + // Adopt the current palette. + memcpy(Brush_original_palette, Main_palette,sizeof(T_Palette)); + memcpy(Brush_original_pixels, Brush, Brush_width*Brush_height); + for (i=0; i<256; i++) + Brush_colormap[i]=i; + //-- + Brush_was_altered=1; + } if (x<0 || y<0 || x>=Brush_width || y>=Brush_height) ; @@ -232,12 +279,23 @@ int L_SetPictureSize(lua_State* L) int w; int h; int nb_args=lua_gettop(L); + int i; LUA_ARG_LIMIT (2, "setpicturesize"); LUA_ARG_NUMBER(1, "setpicturesize", w, 1, 9999); LUA_ARG_NUMBER(2, "setpicturesize", h, 1, 9999); - Resize_image(w, h); // TODO: a return value to catch runtime errors + Backup_in_place(w, h); + // part of Resize_image() : the pixel copy part. + for (i=0; iPages->Nb_layers; i++) + { + Copy_part_of_image_to_another( + Main_backups->Pages->Next->Image[i],0,0,Min(Main_backups->Pages->Next->Width,Main_image_width), + Min(Main_backups->Pages->Next->Height,Main_image_height),Main_backups->Pages->Next->Width, + Main_backups->Pages->Image[i],0,0,Main_image_width); + } + Redraw_layered_image(); + return 0; } @@ -319,13 +377,16 @@ int L_GetBackupPixel(lua_State* L) LUA_ARG_NUMBER(2, "getbackuppixel", y, INT_MIN, INT_MAX); // Bound check - if (x<0 || y<0 || x>=Main_image_width || y>=Main_image_height) + if (x<0 || y<0 || x>=Main_backups->Pages->Next->Width || y>=Main_backups->Pages->Next->Height) { // Silently return the image's transparent color - lua_pushinteger(L, Main_backups->Pages->Transparent_color); + lua_pushinteger(L, Main_backups->Pages->Next->Transparent_color); return 1; } - lua_pushinteger(L, Read_pixel_from_backup_screen(x,y)); + // Can't use Read_pixel_from_backup_screen(), because in a Lua script + // the "backup" can use a different screen dimension. + lua_pushinteger(L, *(Screen_backup + x + Main_backups->Pages->Next->Width * y)); + return 1; } @@ -506,6 +567,33 @@ int L_GetTransColor(lua_State* L) return 1; } +int L_SetForeColor(lua_State* L) +{ + byte c; + int nb_args=lua_gettop(L); + + LUA_ARG_LIMIT (1, "setforecolor"); + LUA_ARG_NUMBER(1, "setforecolor", c, -DBL_MAX, DBL_MAX); + + Fore_color = c; + + return 0; +} + +int L_SetBackColor(lua_State* L) +{ + byte c; + int nb_args=lua_gettop(L); + + LUA_ARG_LIMIT (1, "setbackcolor"); + LUA_ARG_NUMBER(1, "setbackcolor", c, -DBL_MAX, DBL_MAX); + + Back_color = c; + + return 0; +} + + int L_InputBox(lua_State* L) { const int max_settings = 9; @@ -577,7 +665,7 @@ int L_InputBox(lua_State* L) LUA_ARG_NUMBER(setting*args_per_setting+6, "inputbox", decimal_places[setting], -15.0, 15.0); if (decimal_places[setting]>15) decimal_places[setting]=15; - if (min_value[setting]!=0 || min_value[setting]!=1) + if (min_value[setting]!=0 || max_value[setting]!=1) if (decimal_places[setting]<0) decimal_places[setting]=0; // Keep current value in range @@ -593,6 +681,7 @@ int L_InputBox(lua_State* L) if (max_label_length>25) max_label_length=25; + Update_colors_during_script(); Open_window(115+max_label_length*8,44+nb_settings*17,window_caption); // Normally this index is unused, but this initialization avoids @@ -675,7 +764,7 @@ int L_InputBox(lua_State* L) case CONTROL_INPUT: Sprint_double(str,current_value[setting],decimal_places[setting],0); - Readline_ex(12+max_label_length*8+23, 22+setting*17,str,7,40,3,decimal_places[setting]); + Readline_ex(12+max_label_length*8+23, 22+setting*17,str,7,40,INPUT_TYPE_DECIMAL,decimal_places[setting]); current_value[setting]=atof(str); if (current_value[setting] < min_value[setting]) @@ -769,6 +858,88 @@ int L_InputBox(lua_State* L) return 1 + nb_settings; } +int L_SelectBox(lua_State* L) +{ + const int max_settings = 10; + const char * label[max_settings]; + + const char * window_caption; + unsigned int caption_length; + int nb_args; + + unsigned int max_label_length; + int button; + int nb_buttons; + short clicked_button; + //char str[40]; + //short close_window = 0; + + nb_args = lua_gettop (L); + + if (nb_args < 2) + { + return luaL_error(L, "selectbox: Less than 2 arguments"); + } + if ((nb_args - 1) % 2) + { + return luaL_error(L, "selectbox: Wrong number of arguments"); + } + + + nb_buttons=(nb_args-1) /2; + + max_label_length=4; // Minimum size + + // First argument is window caption + LUA_ARG_STRING(1, "selectbox", window_caption); + caption_length = strlen(window_caption); + if ( caption_length > max_label_length) + max_label_length = caption_length; + + for (button=0; button max_label_length) + max_label_length = strlen(label[button]); + LUA_ARG_FUNCTION(button*2+3, "selectbox"); + } + // Max is 25 to keep window under 320 pixel wide + if (max_label_length>25) + max_label_length=25; + + Update_colors_during_script(); + Open_window(28+max_label_length*8,26+nb_buttons*17,window_caption); + + for (button=0; buttonFull_name, NAME_WIDTH, MC_Black, - (highlighted)?MC_Dark:MC_Light); - name_size=strlen(current_item->Full_name); - // Clear remaining area on the right - if (name_sizeType==1) // Directories + { + fg=(highlighted)?MC_Black:MC_Dark; + bg=(highlighted)?MC_Dark:MC_Light; + } + else // Files + { + fg=MC_Black; + bg=(highlighted)?MC_Dark:MC_Light; + } + + Print_in_window(x, y, current_item->Short_name, fg,bg); Update_window_area(x,y,NAME_WIDTH*8,8); } @@ -826,11 +1148,12 @@ void Draw_script_information(T_Fileselector_item * script_item) { FILE *script_file; char full_name[MAX_PATH_CHARACTERS]; - char text_block[3][NAME_WIDTH+3]; + char text_block[3][DESC_WIDTH+1]; int x, y; + int i; // Blank the target area - Window_rectangle(7, FILESEL_Y + 89, (NAME_WIDTH+2)*8+2, 3*8, MC_Black); + Window_rectangle(7, FILESEL_Y + 89, DESC_WIDTH*6+2, 4*8, MC_Black); if (script_item && script_item->Full_name && script_item->Full_name[0]!='\0') { @@ -865,7 +1188,7 @@ void Draw_script_information(T_Fileselector_item * script_item) } else { - if (x < NAME_WIDTH+4) + if (x < DESC_WIDTH+2) { // Adding character text_block[y][x-2] = (c<32 || c>255) ? ' ' : c; @@ -879,250 +1202,525 @@ void Draw_script_information(T_Fileselector_item * script_item) fclose(script_file); } - Print_in_window(7, FILESEL_Y + 89 , text_block[0], MC_Light, MC_Black); - Print_in_window(7, FILESEL_Y + 89+ 8, text_block[1], MC_Light, MC_Black); - Print_in_window(7, FILESEL_Y + 89+16, text_block[2], MC_Light, MC_Black); + Print_help(8, FILESEL_Y + 89 , text_block[0], 'N', 0, 0); + Print_help(8, FILESEL_Y + 89+ 8, text_block[1], 'N', 0, 0); + Print_help(8, FILESEL_Y + 89+16, text_block[2], 'N', 0, 0); + // Display a line with the keyboard shortcut + Print_help(8, FILESEL_Y + 89+24, "Key:", 'N', 0, 0); + for (i=0; i<10; i++) + if (Bound_script[i]!=NULL && !strcmp(Bound_script[i], script_item->Full_name)) + break; + + if (i<10) + { + const char *shortcut; + shortcut=Keyboard_shortcut_value(SPECIAL_RUN_SCRIPT_1+i); + Print_help(8+4*6, FILESEL_Y + 89+24, shortcut, 'K', 0, strlen(shortcut)); + } + else + { + Print_help(8+4*6, FILESEL_Y + 89+24, "None", 'K', 0, 4); + } } - Update_window_area(7, FILESEL_Y + 89, (NAME_WIDTH+2)*8+2, 3*8); + + + + Update_window_area(8, FILESEL_Y + 89, DESC_WIDTH*6+2, 4*8); } // Add a script to the list -void Add_script(const char *name) +void Add_script(const char *name, byte is_file, byte is_directory, byte is_hidden) { - Add_element_to_list(&Scripts_list, Find_last_slash(name)+1, 0); + const char * file_name; + int len; + + file_name=Find_last_slash(name)+1; + + if (is_file) + { + // Only files ending in ".lua" + len=strlen(file_name); + if (len<=4 || strcasecmp(file_name+len-4, ".lua")) + return; + // Hidden + //if (is_hidden && !Config.Show_hidden_files) + // return; + + Add_element_to_list(&Scripts_selector, file_name, Format_filename(file_name, NAME_WIDTH+1, 0), 0, ICON_NONE); + } + else if (is_directory) + { + // Ignore current directory + if ( !strcmp(file_name, ".")) + return; + // Hidden + //if (is_hidden && !Config.Show_hidden_directories) + // return; + + Add_element_to_list(&Scripts_selector, file_name, Format_filename(file_name, NAME_WIDTH+1, 1), 1, ICON_NONE); + } } -void Highlight_script(T_Fileselector *selector, T_List_button *list, const char *selected_script) +void Highlight_script(T_Fileselector *selector, T_List_button *list, const char *selected_file) { short index; - index=Find_file_in_fileselector(selector, selected_script); + index=Find_file_in_fileselector(selector, selected_file); + Locate_list_item(list, selector, index); +} - if ((list->Scroller->Nb_elements<=list->Scroller->Nb_visibles) || (indexScroller->Nb_visibles/2)) +static char Last_run_script[MAX_PATH_CHARACTERS]=""; + +// Before: Cursor hidden +// After: Cursor shown +void Run_script(const char *script_subdirectory, const char *script_filename) +{ + lua_State* L; + const char* message; + byte old_cursor_shape=Cursor_shape; + char scriptdir[MAX_PATH_CHARACTERS]; + + strcpy(scriptdir, Data_directory); + strcat(scriptdir, "scripts/"); + + // Some scripts are slow + Cursor_shape=CURSOR_SHAPE_HOURGLASS; + Display_cursor(); + Flush_update(); + + chdir(scriptdir); + + if (script_subdirectory && script_subdirectory[0]!='\0') { - list->List_start=0; - list->Cursor_position=index; + sprintf(Last_run_script, "%s%s%s", script_subdirectory, PATH_SEPARATOR, script_filename); } else { - if (index>=list->Scroller->Nb_elements-list->Scroller->Nb_visibles/2) + strcpy(Last_run_script, script_filename); + } + + + L = lua_open(); + putenv("LUA_PATH=libs\\?.lua"); + + lua_register(L,"putbrushpixel",L_PutBrushPixel); + lua_register(L,"getbrushpixel",L_GetBrushPixel); + lua_register(L,"getbrushbackuppixel",L_GetBrushBackupPixel); + lua_register(L,"putpicturepixel",L_PutPicturePixel); + lua_register(L,"getpicturepixel",L_GetPicturePixel); + lua_register(L,"getlayerpixel",L_GetLayerPixel); + lua_register(L,"getbackuppixel",L_GetBackupPixel); + lua_register(L,"setbrushsize",L_SetBrushSize); + lua_register(L,"setpicturesize",L_SetPictureSize); + lua_register(L,"getbrushsize",L_GetBrushSize); + lua_register(L,"getpicturesize",L_GetPictureSize); + lua_register(L,"setcolor",L_SetColor); + lua_register(L,"getcolor",L_GetColor); + lua_register(L,"getbackupcolor",L_GetBackupColor); + lua_register(L,"matchcolor",L_MatchColor); + lua_register(L,"getbrushtransparentcolor",L_GetBrushTransparentColor); + lua_register(L,"inputbox",L_InputBox); + lua_register(L,"messagebox",L_MessageBox); + lua_register(L,"statusmessage",L_StatusMessage); + lua_register(L,"selectbox",L_SelectBox); + lua_register(L,"getforecolor",L_GetForeColor); + lua_register(L,"getbackcolor",L_GetBackColor); + lua_register(L,"setforecolor",L_SetForeColor); + lua_register(L,"setbackcolor",L_SetBackColor); + lua_register(L,"gettranscolor",L_GetTransColor); + lua_register(L,"getsparepicturesize",L_GetSparePictureSize); + lua_register(L,"getsparelayerpixel",L_GetSpareLayerPixel); + lua_register(L,"getsparepicturepixel",L_GetSparePicturePixel); + lua_register(L,"getsparecolor",L_GetSpareColor); + lua_register(L,"getsparetranscolor",L_GetSpareTransColor); + lua_register(L,"clearpicture",L_ClearPicture); + lua_register(L,"wait",L_Wait); + lua_register(L,"waitbreak",L_WaitBreak); + lua_register(L,"waitinput",L_WaitInput); + lua_register(L,"updatescreen",L_UpdateScreen); + lua_register(L,"finalizepicture",L_FinalizePicture); + + // Load all standard libraries + luaL_openlibs(L); + + /* + luaopen_base(L); + //luaopen_package(L); // crashes on Windows, for unknown reason + luaopen_table(L); + //luaopen_io(L); // crashes on Windows, for unknown reason + //luaopen_os(L); + luaopen_string(L); + luaopen_math(L); + //luaopen_debug(L); + */ + + // TODO The script may modify the picture, so we do a backup here. + // If the script is only touching the brush, this isn't needed... + // The backup also allows the script to read from it to make something + // like a feedback off effect (convolution matrix comes to mind). + Backup(); + + Palette_has_changed=0; + Brush_was_altered=0; + Original_back_color=Back_color; + Original_fore_color=Fore_color; + + // Backup the brush + Brush_backup=(byte *)malloc(((long)Brush_height)*Brush_width); + Brush_backup_width = Brush_width; + Brush_backup_height = Brush_height; + + if (Brush_backup == NULL) + { + Verbose_message("Error!", "Out of memory!"); + } + else + { + memcpy(Brush_backup, Brush, ((long)Brush_height)*Brush_width); + + if (luaL_loadfile(L,Last_run_script) != 0) { - list->List_start=list->Scroller->Nb_elements-list->Scroller->Nb_visibles; - list->Cursor_position=index-list->List_start; + int stack_size; + stack_size= lua_gettop(L); + if (stack_size>0 && (message = lua_tostring(L, stack_size))!=NULL) + Verbose_message("Error!", message); + else + Warning_message("Unknown error loading script!"); + } + else if (lua_pcall(L, 0, 0, 0) != 0) + { + int stack_size; + stack_size= lua_gettop(L); + + Update_colors_during_script(); + + if (stack_size>0 && (message = lua_tostring(L, stack_size))!=NULL) + Verbose_message("Error running script", message); + else + Warning_message("Unknown error running script!"); + } + } + // Cleanup + free(Brush_backup); + Brush_backup=NULL; + Update_colors_during_script(); + End_of_modification(); + + lua_close(L); + + if (Brush_was_altered) + { + // Copy Brush to original + memcpy(Brush_original_pixels, Brush, (long)Brush_width*Brush_height); + Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); + } + + Hide_cursor(); + Display_all_screen(); + // Update changed pen colors. + if (Back_color!=Original_back_color || Fore_color!=Original_fore_color) + { + // This is done at end of script, in case somebody would use the + // functions in a custom window. + if (Back_color!=Original_back_color) + { + byte new_color = Back_color; + Back_color = Original_back_color; + Set_back_color(new_color); + } + if (Fore_color!=Original_fore_color) + { + byte new_color = Fore_color; + Fore_color = Original_fore_color; + Set_fore_color(new_color); + } + + } + Cursor_shape=old_cursor_shape; + Display_cursor(); +} + +void Run_numbered_script(byte index) +{ + + if (index>=10) + return; + if (Bound_script[index]==NULL) + return; + + Hide_cursor(); + Run_script(NULL, Bound_script[index]); +} + +void Repeat_script(void) +{ + + if (Last_run_script==NULL || Last_run_script[0]=='\0') + { + Warning_message("No script to repeat."); + return; + } + + Hide_cursor(); + Run_script(NULL, Last_run_script); +} + +void Set_script_shortcut(T_Fileselector_item * script_item) +{ + int i; + char full_name[MAX_PATH_CHARACTERS]; + + if (script_item && script_item->Full_name && script_item->Full_name[0]!='\0') + { + strcpy(full_name, Data_directory); + strcat(full_name, "scripts/"); + strcat(full_name, script_item->Full_name); + + // Find if it already has a shortcut + for (i=0; i<10; i++) + if (Bound_script[i]!=NULL && !strcmp(Bound_script[i], script_item->Full_name)) + break; + if (i<10) + { + // Existing shortcut } else { - list->List_start=index-(list->Scroller->Nb_visibles-1)/2; - list->Cursor_position=(list->Scroller->Nb_visibles-1)/2; + // Try to find a "free" one. + for (i=0; i<10; i++) + if (Bound_script[i]==NULL + || !Has_shortcut(SPECIAL_RUN_SCRIPT_1+i) + || !File_exists(full_name)) + break; + if (i<10) + { + free(Bound_script[i]); + Bound_script[i]=strdup(script_item->Full_name); + } + else + { + Warning_message("Already 10 scripts have shortcuts."); + return; + } } + Window_set_shortcut(SPECIAL_RUN_SCRIPT_1+i); + if (!Has_shortcut(SPECIAL_RUN_SCRIPT_1+i)) + { + // User cancelled or deleted all shortcuts + free(Bound_script[i]); + Bound_script[i]=NULL; + } + // Refresh display + Hide_cursor(); + Draw_script_information(script_item); + Display_cursor(); } } void Button_Brush_Factory(void) { + static char selected_file[MAX_PATH_CHARACTERS]=""; + static char sub_directory[MAX_PATH_CHARACTERS]=""; + short clicked_button; T_List_button* scriptlist; T_Scroller_button* scriptscroll; + T_Special_button* scriptarea; char scriptdir[MAX_PATH_CHARACTERS]; - static char selected_script[MAX_PATH_CHARACTERS]=""; - - Open_window(33+8*NAME_WIDTH, 162, "Brush Factory"); - - // Here we use the same data container as the fileselectors. + T_Fileselector_item *item; + // Reinitialize the list - Free_fileselector_list(&Scripts_list); + Free_fileselector_list(&Scripts_selector); strcpy(scriptdir, Data_directory); strcat(scriptdir, "scripts/"); + strcat(scriptdir, sub_directory); // Add each found file to the list - For_each_file(scriptdir, Add_script); + For_each_directory_entry(scriptdir, Add_script); // Sort it - Sort_list_of_files(&Scripts_list); + Sort_list_of_files(&Scripts_selector); + // - Window_set_normal_button(85, 141, 67, 14, "Cancel", 0, 1, KEY_ESC); // 1 + Open_window(33+8*NAME_WIDTH, 180, "Brush Factory"); + + Window_set_normal_button(85, 149, 67, 14, "Cancel", 0, 1, KEY_ESC); // 1 Window_display_frame_in(6, FILESEL_Y - 2, NAME_WIDTH*8+4, 84); // File selector - scriptlist = Window_set_list_button( - // Fileselector - Window_set_special_button(8, FILESEL_Y + 1, NAME_WIDTH*8, 80), // 2 - // Scroller for the fileselector - (scriptscroll = Window_set_scroller_button(NAME_WIDTH*8+14, FILESEL_Y - 1, 82, - Scripts_list.Nb_elements,10, 0)), // 3 - Draw_script_name); // 4 + // Fileselector + scriptarea=Window_set_special_button(8, FILESEL_Y + 1, NAME_WIDTH*8, 80); // 2 + // Scroller for the fileselector + scriptscroll = Window_set_scroller_button(NAME_WIDTH*8+14, FILESEL_Y - 1, 82, + Scripts_selector.Nb_elements,10, 0); // 3 + scriptlist = Window_set_list_button(scriptarea,scriptscroll,Draw_script_name); // 4 - Window_set_normal_button(10, 141, 67, 14, "Run", 0, Scripts_list.Nb_elements!=0, SDLK_RETURN); // 5 + Window_set_normal_button(10, 149, 67, 14, "Run", 0, 1, SDLK_RETURN); // 5 - Window_display_frame_in(6, FILESEL_Y + 88, (NAME_WIDTH+2)*8+4, 3*8+2); // Descr. + Window_display_frame_in(6, FILESEL_Y + 88, DESC_WIDTH*6+4, 4*8+2); // Descr. + Window_set_special_button(7, FILESEL_Y + 89+24,DESC_WIDTH*6,8); // 6 - // Update position - Highlight_script(&Scripts_list, scriptlist, selected_script); - // Update the scroller position - scriptscroll->Position=scriptlist->List_start; - if (scriptscroll->Position) - Window_draw_slider(scriptscroll); - - Window_redraw_list(scriptlist); - Draw_script_information(Get_item_by_index(&Scripts_list, - scriptlist->List_start + scriptlist->Cursor_position)); - - Update_window_area(0, 0, Window_width, Window_height); - Display_cursor(); - - do + while (1) { - clicked_button = Window_clicked_button(); - if (Is_shortcut(Key,0x100+BUTTON_HELP)) - Window_help(BUTTON_BRUSH_EFFECTS, "BRUSH FACTORY"); - - switch (clicked_button) - { - case 4: - Hide_cursor(); - Draw_script_information(Get_item_by_index(&Scripts_list, - scriptlist->List_start + scriptlist->Cursor_position)); - Display_cursor(); - break; - - - default: - break; - } + // Locate selected file in view + Highlight_script(&Scripts_selector, scriptlist, selected_file); + // Update the scroller position + scriptscroll->Position=scriptlist->List_start; + Window_draw_slider(scriptscroll); - } while (clicked_button != 1 && clicked_button != 5); - - if (Scripts_list.Nb_elements == 0) - selected_script[0]='\0'; - else - strcpy(selected_script, Get_item_by_index(&Scripts_list, - scriptlist->List_start + scriptlist->Cursor_position)-> Full_name); + Window_redraw_list(scriptlist); + Draw_script_information(Get_item_by_index(&Scripts_selector, + scriptlist->List_start + scriptlist->Cursor_position)); + + Update_window_area(0, 0, Window_width, Window_height); + Display_cursor(); + + Reset_quicksearch(); + + do + { + clicked_button = Window_clicked_button(); + if (Key==SDLK_BACKSPACE && sub_directory[0]!='\0') + { + // Make it select first entry (parent directory) + scriptlist->List_start=0; + scriptlist->Cursor_position=0; + clicked_button=5; + } + if (Is_shortcut(Key,0x100+BUTTON_HELP)) + Window_help(BUTTON_BRUSH_EFFECTS, "BRUSH FACTORY"); + else if (Is_shortcut(Key,0x200+BUTTON_BRUSH_EFFECTS)) + clicked_button=1; // Cancel + // Quicksearch + if (clicked_button==4) + Reset_quicksearch(); + else if (clicked_button==0 && Key_ANSI) + clicked_button=Quicksearch_list(scriptlist, &Scripts_selector); + + switch (clicked_button) + { + case 4: + Hide_cursor(); + Draw_script_information(Get_item_by_index(&Scripts_selector, + scriptlist->List_start + scriptlist->Cursor_position)); + Display_cursor(); + { + // Test double-click + static long time_click = 0; + static int last_selected_item=-1; + static long time_previous; + time_previous = time_click; + time_click = SDL_GetTicks(); + if (scriptlist->List_start + scriptlist->Cursor_position == last_selected_item) + { + if (time_click - time_previous < Config.Double_click_speed) + clicked_button=5; + } + else + { + last_selected_item=scriptlist->List_start + scriptlist->Cursor_position; + } + } + break; + + case 6: + Set_script_shortcut(Get_item_by_index(&Scripts_selector, + scriptlist->List_start + scriptlist->Cursor_position)); + break; + + default: + break; + } + + } while (clicked_button != 1 && clicked_button != 5); + + // Cancel + if (clicked_button==1) + break; + + // OK + if (Scripts_selector.Nb_elements == 0) + { + // No items : same as Cancel + clicked_button=1; + break; + } + + // Examine selected file + item = Get_item_by_index(&Scripts_selector, + scriptlist->List_start + scriptlist->Cursor_position); + + if (item->Type==0) // File + { + strcpy(selected_file, sub_directory); + strcat(selected_file, item->Full_name); + break; + } + else if (item->Type==1) // Directory + { + if (!strcmp(item->Full_name,PARENT_DIR)) + { + // Going up one directory + long len; + char * slash_pos; + + // Remove trailing slash + len=strlen(sub_directory); + if (len && !strcmp(sub_directory+len-1,PATH_SEPARATOR)) + sub_directory[len-1]='\0'; + + slash_pos=Find_last_slash(sub_directory); + if (slash_pos) + { + strcpy(selected_file, slash_pos+1); + *slash_pos='\0'; + } + else + { + strcpy(selected_file, sub_directory); + sub_directory[0]='\0'; + } + } + else + { + // Going down one directory + strcpy(selected_file, PARENT_DIR); + + strcat(sub_directory, item->Full_name); + strcat(sub_directory, PATH_SEPARATOR); + } + + // No break: going back up to beginning of loop + + // Reinitialize the list + Free_fileselector_list(&Scripts_selector); + strcpy(scriptdir, Data_directory); + strcat(scriptdir, "scripts/"); + strcat(scriptdir, sub_directory); + // Add each found file to the list + For_each_directory_entry(scriptdir, Add_script); + // Sort it + Sort_list_of_files(&Scripts_selector); + // + + scriptlist->Scroller->Nb_elements=Scripts_selector.Nb_elements; + Compute_slider_cursor_length(scriptlist->Scroller); + + Hide_cursor(); + } + } + + Close_window(); + Unselect_button(BUTTON_BRUSH_EFFECTS); + if (clicked_button == 5) // Run the script { - lua_State* L; - const char* message; - - // Some scripts are slow - Hide_cursor(); - Cursor_shape=CURSOR_SHAPE_HOURGLASS; - Display_cursor(); - Flush_update(); - - chdir(scriptdir); - - L = lua_open(); - - lua_register(L,"putbrushpixel",L_PutBrushPixel); - lua_register(L,"getbrushpixel",L_GetBrushPixel); - lua_register(L,"getbrushbackuppixel",L_GetBrushBackupPixel); - lua_register(L,"putpicturepixel",L_PutPicturePixel); - lua_register(L,"getpicturepixel",L_GetPicturePixel); - lua_register(L,"getlayerpixel",L_GetLayerPixel); - lua_register(L,"getbackuppixel",L_GetBackupPixel); - lua_register(L,"setbrushsize",L_SetBrushSize); - lua_register(L,"setpicturesize",L_SetPictureSize); - lua_register(L,"getbrushsize",L_GetBrushSize); - lua_register(L,"getpicturesize",L_GetPictureSize); - lua_register(L,"setcolor",L_SetColor); - lua_register(L,"getcolor",L_GetColor); - lua_register(L,"getbackupcolor",L_GetBackupColor); - lua_register(L,"matchcolor",L_MatchColor); - lua_register(L,"getbrushtransparentcolor",L_GetBrushTransparentColor); - lua_register(L,"inputbox",L_InputBox); - lua_register(L,"messagebox",L_MessageBox); - lua_register(L,"getforecolor",L_GetForeColor); - lua_register(L,"getbackcolor",L_GetBackColor); - lua_register(L,"gettranscolor",L_GetTransColor); - lua_register(L,"getsparepicturesize ",L_GetSparePictureSize); - lua_register(L,"getsparelayerpixel ",L_GetSpareLayerPixel); - lua_register(L,"getsparepicturepixel",L_GetSparePicturePixel); - lua_register(L,"getsparecolor",L_GetSpareColor); - lua_register(L,"getsparetranscolor",L_GetSpareTransColor); - lua_register(L,"clearpicture",L_ClearPicture); - - - // For debug only - // luaL_openlibs(L); - - luaopen_base(L); - //luaopen_package(L); // crashes on Windows, for unknown reason - luaopen_table(L); - //luaopen_io(L); // crashes on Windows, for unknown reason - //luaopen_os(L); - //luaopen_string(L); - luaopen_math(L); - //luaopen_debug(L); - - strcat(scriptdir, selected_script); - - // TODO The script may modify the picture, so we do a backup here. - // If the script is only touching the brush, this isn't needed... - // The backup also allows the script to read from it to make something - // like a feedback off effect (convolution matrix comes to mind). - Backup(); - - Palette_has_changed=0; - Brush_was_altered=0; - - // Backup the brush - Brush_backup=(byte *)malloc(((long)Brush_height)*Brush_width); - Brush_backup_width = Brush_width; - Brush_backup_height = Brush_height; - - if (Brush_backup == NULL) - { - Verbose_message("Error!", "Out of memory!"); - } - else - { - memcpy(Brush_backup, Brush, ((long)Brush_height)*Brush_width); - - if (luaL_loadfile(L,scriptdir) != 0) - { - int stack_size; - stack_size= lua_gettop(L); - if (stack_size>0 && (message = lua_tostring(L, stack_size))!=NULL) - Verbose_message("Error!", message); - else - Warning_message("Unknown error loading script!"); - } - else if (lua_pcall(L, 0, 0, 0) != 0) - { - int stack_size; - stack_size= lua_gettop(L); - if (stack_size>0 && (message = lua_tostring(L, stack_size))!=NULL) - Verbose_message("Error running script", message); - else - Warning_message("Unknown error running script!"); - } - } - // Cleanup - free(Brush_backup); - Brush_backup=NULL; - if (Palette_has_changed) - { - Set_palette(Main_palette); - Compute_optimal_menu_colors(Main_palette); - } - End_of_modification(); - - lua_close(L); + Run_script("", selected_file); + } + else + { + Display_cursor(); } - - Close_window(); - if (Brush_was_altered) - Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); - Unselect_button(BUTTON_BRUSH_EFFECTS); - // If the image has been resized, Compute_limits() has been called and it - // has computed wrong values because a window was open : In this - // context, Menu_Y and Menu_is_visible are artificially set to "menu hidden". - // This whole "_before_window" looks like it's completely useless anyway, - // but we're too close to release to scrap it and re-test everything. - // So: call Compute_limits() one more time, and be done with it. - Compute_limits(); - - Display_all_screen(); - Display_cursor(); } #else // NOLUA diff --git a/src/factory.h b/src/factory.h index ff12d081..3a1a54f5 100644 --- a/src/factory.h +++ b/src/factory.h @@ -1,3 +1,13 @@ /* vim:expandtab:ts=2 sw=2: */ void Button_Brush_Factory(void); +void Repeat_script(void); + +/// Lua scripts bound to shortcut keys. +extern char * Bound_script[10]; + +/// +/// Run a lua script linked to a shortcut, 0-9. +/// Before: Cursor hidden +/// After: Cursor shown +void Run_numbered_script(byte index); diff --git a/src/fileformats.c b/src/fileformats.c index 433935f1..21d281e2 100644 --- a/src/fileformats.c +++ b/src/fileformats.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2009 Petter Lindquist Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet @@ -27,6 +28,19 @@ #ifndef __no_pnglib__ #include +#if (PNG_LIBPNG_VER_MAJOR <= 1) && (PNG_LIBPNG_VER_MINOR < 4) + // Compatibility layer to allow us to use libng 1.4 or any older one. + + // This function is renamed in 1.4 + #define png_set_expand_gray_1_2_4_to_8(x) png_set_gray_1_2_4_to_8(x) + + // Wrappers that are mandatory in 1.4. Older version allowed direct access. + #define png_get_rowbytes(png_ptr,info_ptr) ((info_ptr)->rowbytes) + #define png_get_image_width(png_ptr,info_ptr) ((info_ptr)->width) + #define png_get_image_height(png_ptr,info_ptr) ((info_ptr)->height) + #define png_get_bit_depth(png_ptr,info_ptr) ((info_ptr)->bit_depth) + #define png_get_color_type(png_ptr,info_ptr) ((info_ptr)->color_type) +#endif #endif #include @@ -59,11 +73,11 @@ void Test_IMG(T_IO_Context * context) if ((file=fopen(filename, "rb"))) { // Lecture et vérification de la signature - if (Read_bytes(file,IMG_header.Filler1,sizeof(IMG_header.Filler1)) + if (Read_bytes(file,IMG_header.Filler1,6) && Read_word_le(file,&(IMG_header.Width)) && Read_word_le(file,&(IMG_header.Height)) - && Read_bytes(file,IMG_header.Filler2,sizeof(IMG_header.Filler2)) - && Read_bytes(file,IMG_header.Palette,sizeof(IMG_header.Palette)) + && Read_bytes(file,IMG_header.Filler2,118) + && Read_bytes(file,IMG_header.Palette,sizeof(T_Palette)) ) { if ( (!memcmp(IMG_header.Filler1,signature,6)) @@ -94,11 +108,11 @@ void Load_IMG(T_IO_Context * context) { file_size=File_length_file(file); - if (Read_bytes(file,IMG_header.Filler1,sizeof(IMG_header.Filler1)) + if (Read_bytes(file,IMG_header.Filler1,6) && Read_word_le(file,&(IMG_header.Width)) && Read_word_le(file,&(IMG_header.Height)) - && Read_bytes(file,IMG_header.Filler2,sizeof(IMG_header.Filler2)) - && Read_bytes(file,IMG_header.Palette,sizeof(IMG_header.Palette)) + && Read_bytes(file,IMG_header.Filler2,118) + && Read_bytes(file,IMG_header.Palette,sizeof(T_Palette)) ) { @@ -167,11 +181,11 @@ void Save_IMG(T_IO_Context * context) memcpy(IMG_header.Palette,context->Palette,sizeof(T_Palette)); - if (Write_bytes(file,IMG_header.Filler1,sizeof(IMG_header.Filler1)) + if (Write_bytes(file,IMG_header.Filler1,6) && Write_word_le(file,IMG_header.Width) && Write_word_le(file,IMG_header.Height) - && Write_bytes(file,IMG_header.Filler2,sizeof(IMG_header.Filler2)) - && Write_bytes(file,IMG_header.Palette,sizeof(IMG_header.Palette)) + && Write_bytes(file,IMG_header.Filler2,118) + && Write_bytes(file,IMG_header.Palette,sizeof(T_Palette)) ) { @@ -204,7 +218,6 @@ void Save_IMG(T_IO_Context * context) //////////////////////////////////// LBM //////////////////////////////////// -#pragma pack(1) typedef struct { word Width; @@ -221,7 +234,6 @@ typedef struct word X_screen; word Y_screen; } T_LBM_Header; -#pragma pack() byte * LBM_buffer; FILE *LBM_file; @@ -375,28 +387,42 @@ void Test_LBM(T_IO_Context * context) } } - // ------------------------- Attendre une section ------------------------- - byte Wait_for(byte * expected_section) - { - // Valeur retournée: 1=Section trouvée, 0=Section non trouvée (erreur) - dword Taille_section; - byte section_read[4]; +// Inspired by Allegro: storing a 4-character identifier as a 32bit litteral +#define ID4(a,b,c,d) ((((a)&255)<<24) | (((b)&255)<<16) | (((c)&255)<<8) | (((d)&255))) +/// Skips the current section in an ILBM file. +/// This function should be called while the file pointer is right +/// after the 4-character code that identifies the section. +int LBM_Skip_section(void) +{ + dword size; + + if (!Read_dword_be(LBM_file,&size)) + return 0; + if (size&1) + size++; + if (fseek(LBM_file,size,SEEK_CUR)) + return 0; + return 1; +} + +// ------------------------- Attendre une section ------------------------- +byte LBM_Wait_for(byte * expected_section) +{ + // Valeur retournée: 1=Section trouvée, 0=Section non trouvée (erreur) + byte section_read[4]; + + if (! Read_bytes(LBM_file,section_read,4)) + return 0; + while (memcmp(section_read,expected_section,4)) // Sect. pas encore trouvée + { + if (!LBM_Skip_section()) + return 0; if (! Read_bytes(LBM_file,section_read,4)) return 0; - while (memcmp(section_read,expected_section,4)) // Sect. pas encore trouvée - { - if (!Read_dword_be(LBM_file,&Taille_section)) - return 0; - if (Taille_section&1) - Taille_section++; - if (fseek(LBM_file,Taille_section,SEEK_CUR)) - return 0; - if (! Read_bytes(LBM_file,section_read,4)) - return 0; - } - return 1; } + return 1; +} // Les images ILBM sont stockés en bitplanes donc on doit trifouiller les bits pour // en faire du chunky @@ -509,7 +535,7 @@ void Load_LBM(T_IO_Context * context) byte temp_byte; short b256; dword nb_colors; - dword image_size; + dword section_size; short x_pos; short y_pos; short counter; @@ -531,7 +557,7 @@ void Load_LBM(T_IO_Context * context) Read_bytes(LBM_file,section,4); Read_dword_be(LBM_file,&dummy); Read_bytes(LBM_file,format,4); - if (!Wait_for((byte *)"BMHD")) + if (!LBM_Wait_for((byte *)"BMHD")) File_error=1; Read_dword_be(LBM_file,&dummy); @@ -551,7 +577,7 @@ void Load_LBM(T_IO_Context * context) && (Read_word_be(LBM_file,&header.Y_screen)) && header.Width && header.Height) { - if ( (header.BitPlanes) && (Wait_for((byte *)"CMAP")) ) + if ( (header.BitPlanes) && (LBM_Wait_for((byte *)"CMAP")) ) { Read_dword_be(LBM_file,&nb_colors); nb_colors/=3; @@ -604,16 +630,73 @@ void Load_LBM(T_IO_Context * context) if (Read_byte(LBM_file,&temp_byte)) File_error=2; - if ( (Wait_for((byte *)"BODY")) && (!File_error) ) + // Keep reading sections until we find the body + while (1) { - Read_dword_be(LBM_file,&image_size); - //swab((char *)&header.Width ,(char *)&context->Width,2); - //swab((char *)&header.Height,(char *)&context->Height,2); + if (! Read_bytes(LBM_file,section,4)) + { + File_error=2; + break; + } + // Found body : stop searching + if (!memcmp(section,"BODY",4)) + break; + else if (!memcmp(section,"CRNG",4)) + { + // Handle CRNG + + // The content of a CRNG is as follows: + word padding; + word rate; + word flags; + byte min_col; + byte max_col; + // + if ( (Read_dword_be(LBM_file,§ion_size)) + && (Read_word_be(LBM_file,&padding)) + && (Read_word_be(LBM_file,&rate)) + && (Read_word_be(LBM_file,&flags)) + && (Read_byte(LBM_file,&min_col)) + && (Read_byte(LBM_file,&max_col))) + { + if (section_size == 8 && min_col != max_col) + { + // Valid cycling range + if (max_colCycle_range[context->Color_cycles].Start=min_col; + context->Cycle_range[context->Color_cycles].End=max_col; + context->Cycle_range[context->Color_cycles].Inverse=(flags&2)?1:0; + context->Cycle_range[context->Color_cycles].Speed=(flags&1) ? rate/78 : 0; + + context->Color_cycles++; + } + } + else + { + File_error=2; + break; + } + } + else + { + // ignore any number of unknown sections + if (!LBM_Skip_section()) + { + File_error=2; + break; + } + } + + } + + if ( !File_error ) + { + Read_dword_be(LBM_file,§ion_size); context->Width = header.Width; context->Height = header.Height; - //swab((char *)&header.X_screen,(char *)&Original_screen_X,2); - //swab((char *)&header.Y_screen,(char *)&Original_screen_Y,2); Original_screen_X = header.X_screen; Original_screen_Y = header.Y_screen; @@ -874,6 +957,7 @@ void Save_LBM(T_IO_Context * context) byte temp_byte; word real_width; int file_size; + int i; File_error=0; Get_full_filename(filename, context->File_name, context->File_directory); @@ -890,7 +974,6 @@ void Save_LBM(T_IO_Context * context) // On corrige la largeur de l'image pour qu'elle soit multiple de 2 real_width=context->Width+(context->Width&1); - //swab((byte *)&real_width,(byte *)&header.Width,2); header.Width=context->Width; header.Height=context->Height; header.X_org=0; @@ -923,7 +1006,23 @@ void Save_LBM(T_IO_Context * context) Write_dword_be(LBM_file,sizeof(T_Palette)); Write_bytes(LBM_file,context->Palette,sizeof(T_Palette)); - + + for (i=0; iColor_cycles; i++) + { + word flags=0; + flags|= context->Cycle_range[i].Speed?1:0; // Cycling or not + flags|= context->Cycle_range[i].Inverse?2:0; // Inverted + + Write_bytes(LBM_file,"CRNG",4); + Write_dword_be(LBM_file,8); // Section size + Write_word_be(LBM_file,0); // Padding + Write_word_be(LBM_file,context->Cycle_range[i].Speed*78); // Rate + Write_word_be(LBM_file,flags); // Flags + Write_byte(LBM_file,context->Cycle_range[i].Start); // Min color + Write_byte(LBM_file,context->Cycle_range[i].End); // Max color + // No padding, size is multiple of 2 + } + Write_bytes(LBM_file,"BODY",4); Write_dword_be(LBM_file,0); // On mettra la taille à jour à la fin @@ -948,8 +1047,8 @@ void Save_LBM(T_IO_Context * context) file_size=File_length(filename); LBM_file=fopen(filename,"rb+"); - fseek(LBM_file,820,SEEK_SET); - Write_dword_be(LBM_file,file_size-824); + fseek(LBM_file,820+context->Color_cycles*16,SEEK_SET); + Write_dword_be(LBM_file,file_size-824-context->Color_cycles*16); if (!File_error) { @@ -1554,7 +1653,6 @@ void Save_BMP(T_IO_Context * context) //////////////////////////////////// GIF //////////////////////////////////// -#pragma pack(1) typedef struct { word Width; // Width of the complete image area @@ -1573,7 +1671,6 @@ typedef struct byte Indicator; // Misc image information byte Nb_bits_pixel; // Nb de bits par pixel } T_GIF_IDB; // Image Descriptor Block -#pragma pack() typedef struct { @@ -1735,7 +1832,7 @@ void Load_GIF(T_IO_Context * context) word color_index; // index de traitement d'une couleur byte size_to_read; // Nombre de données à lire (divers) byte block_identifier; // Code indicateur du type de bloc en cours - word initial_nb_bits; // Nb de bits au début du traitement LZW + byte initial_nb_bits; // Nb de bits au début du traitement LZW word special_case=0; // Mémoire pour le cas spécial word old_code=0; // Code précédent word byte_read; // Sauvegarde du code en cours de lecture @@ -1787,8 +1884,6 @@ void Load_GIF(T_IO_Context * context) // Ordre de Classement = (LSDB.Aspect and $80) nb_colors=(1 << ((LSDB.Resol & 0x07)+1)); - initial_nb_bits=(LSDB.Resol & 0x07)+2; - if (LSDB.Resol & 0x80) { // Palette globale dispo: @@ -1796,24 +1891,12 @@ void Load_GIF(T_IO_Context * context) if (Config.Clear_palette) memset(context->Palette,0,sizeof(T_Palette)); - // On peut maintenant charger la nouvelle palette: - if (!(LSDB.Aspect & 0x80)) - // Palette dans l'ordre: - for(color_index=0;color_indexPalette[color_index].R)); - Read_byte(GIF_file,&(context->Palette[color_index].G)); - Read_byte(GIF_file,&(context->Palette[color_index].B)); - } - else + // Load the palette + for(color_index=0;color_indexPalette[color_index].R)); - for (color_index=0;color_indexPalette[color_index].G)); - for (color_index=0;color_indexPalette[color_index].B)); + Read_byte(GIF_file,&(context->Palette[color_index].R)); + Read_byte(GIF_file,&(context->Palette[color_index].G)); + Read_byte(GIF_file,&(context->Palette[color_index].B)); } } @@ -1924,6 +2007,57 @@ void Load_GIF(T_IO_Context * context) } } } + else if (!memcmp(aeb,"CRNG\0\0\0\0" "1.0",0x0B)) + { + // Color animation. Similar to a LBM CRNG chunk. + word rate; + word flags; + byte min_col; + byte max_col; + // + Read_byte(GIF_file,&size_to_read); + for(;size_to_read>0 && !File_error;size_to_read-=6) + { + if ( (Read_word_be(GIF_file,&rate)) + && (Read_word_be(GIF_file,&flags)) + && (Read_byte(GIF_file,&min_col)) + && (Read_byte(GIF_file,&max_col))) + { + if (min_col != max_col) + { + // Valid cycling range + if (max_colCycle_range[context->Color_cycles].Start=min_col; + context->Cycle_range[context->Color_cycles].End=max_col; + context->Cycle_range[context->Color_cycles].Inverse=(flags&2)?1:0; + context->Cycle_range[context->Color_cycles].Speed=(flags&1)?rate/78:0; + + context->Color_cycles++; + } + } + else + { + File_error=1; + } + } + // Read end-of-block delimiter + if (!File_error) + Read_byte(GIF_file,&size_to_read); + if (size_to_read!=0) + File_error=1; + } + else + { + // Unknown extension, skip. + Read_byte(GIF_file,&size_to_read); + while (size_to_read!=0 && !File_error) + { + fseek(GIF_file,size_to_read,SEEK_CUR); + Read_byte(GIF_file,&size_to_read); + } + } } else { @@ -1961,7 +2095,6 @@ void Load_GIF(T_IO_Context * context) && Read_word_le(GIF_file,&(IDB.Image_width)) && Read_word_le(GIF_file,&(IDB.Image_height)) && Read_byte(GIF_file,&(IDB.Indicator)) - && Read_byte(GIF_file,&(IDB.Nb_bits_pixel)) && IDB.Image_width && IDB.Image_height) { @@ -1974,42 +2107,38 @@ void Load_GIF(T_IO_Context * context) { // Palette locale dispo + if (Config.Clear_palette) + memset(context->Palette,0,sizeof(T_Palette)); + nb_colors=(1 << ((IDB.Indicator & 0x07)+1)); - initial_nb_bits=(IDB.Indicator & 0x07)+2; - - if (!(IDB.Indicator & 0x40)) - // Palette dans l'ordre: - for(color_index=0;color_indexPalette[color_index].R)); - Read_byte(GIF_file,&(context->Palette[color_index].G)); - Read_byte(GIF_file,&(context->Palette[color_index].B)); - } - else - { - // Palette triée par composantes: - for (color_index=0;color_indexPalette[color_index].R)); - for (color_index=0;color_indexPalette[color_index].G)); - for (color_index=0;color_indexPalette[color_index].B)); + // Load the palette + for(color_index=0;color_indexPalette[color_index].R)); + Read_byte(GIF_file,&(context->Palette[color_index].G)); + Read_byte(GIF_file,&(context->Palette[color_index].B)); } + } Palette_loaded(context); + + File_error=0; + if (!Read_byte(GIF_file,&(initial_nb_bits))) + File_error=1; - value_clr =nb_colors+0; - value_eof =nb_colors+1; - alphabet_free=nb_colors+2; - GIF_nb_bits =initial_nb_bits; + value_clr =(1<Palette,768)) + for(i=0;i<256 && !File_error;i++) + { + if (!Write_byte(GIF_file,context->Palette[i].R) + ||!Write_byte(GIF_file,context->Palette[i].G) + ||!Write_byte(GIF_file,context->Palette[i].B)) + File_error=1; + } + if (!File_error) { // La palette a été correctement écrite. - // Le jour où on se servira des blocks d'extensions pour placer - // des commentaires, on le fera ici. - // Ecriture de la transparence //Write_bytes(GIF_file,"\x21\xF9\x04\x01\x00\x00\xNN\x00",8); @@ -2275,6 +2408,26 @@ void Save_GIF(T_IO_Context * context) Write_byte(GIF_file,strlen(context->Comment)); Write_bytes(GIF_file,context->Comment,strlen(context->Comment)+1); } + // Write cycling colors + if (context->Color_cycles) + { + int i; + + Write_bytes(GIF_file,"\x21\xff\x0B" "CRNG\0\0\0\0" "1.0",14); + Write_byte(GIF_file,context->Color_cycles*6); + for (i=0; iColor_cycles; i++) + { + word flags=0; + flags|= context->Cycle_range[i].Speed?1:0; // Cycling or not + flags|= context->Cycle_range[i].Inverse?2:0; // Inverted + + Write_word_be(GIF_file,context->Cycle_range[i].Speed*78); // Rate + Write_word_be(GIF_file,flags); // Flags + Write_byte(GIF_file,context->Cycle_range[i].Start); // Min color + Write_byte(GIF_file,context->Cycle_range[i].End); // Max color + } + Write_byte(GIF_file,0); + } // Loop on all layers for (current_layer=0; @@ -2282,7 +2435,7 @@ void Save_GIF(T_IO_Context * context) current_layer++) { // Write a Graphic Control Extension - char GCE_block[] = "\x21\xF9\x04\x04\x05\x00\x00\x00"; + byte GCE_block[] = "\x21\xF9\x04\x04\x05\x00\x00\x00"; // 'Default' values: // Disposal method "Do not dispose" // Duration 5/100s (minimum viable value for current web browsers) @@ -2542,7 +2695,6 @@ void Save_GIF(T_IO_Context * context) //////////////////////////////////// PCX //////////////////////////////////// -#pragma pack(1) typedef struct { byte Manufacturer; // |_ Il font chier ces cons! Ils auraient pu @@ -2564,7 +2716,6 @@ typedef struct word Screen_Y; // | l'écran d'origine byte Filler[54]; // Ca... J'adore! } T_PCX_Header; -#pragma pack() T_PCX_Header PCX_header; @@ -3010,14 +3161,14 @@ void Save_PCX(T_IO_Context * context) Write_word_le(file,PCX_header.Y_max) && Write_word_le(file,PCX_header.X_dpi) && Write_word_le(file,PCX_header.Y_dpi) && - Write_bytes(file,&(PCX_header.Palette_16c),sizeof(PCX_header.Palette_16c)) && + Write_bytes(file,&(PCX_header.Palette_16c),48) && Write_bytes(file,&(PCX_header.Reserved),1) && Write_bytes(file,&(PCX_header.Plane),1) && Write_word_le(file,PCX_header.Bytes_per_plane_line) && Write_word_le(file,PCX_header.Palette_info) && Write_word_le(file,PCX_header.Screen_X) && Write_word_le(file,PCX_header.Screen_Y) && - Write_bytes(file,&(PCX_header.Filler),sizeof(PCX_header.Filler)) ) + Write_bytes(file,&(PCX_header.Filler),54) ) { line_size=PCX_header.Bytes_per_plane_line*PCX_header.Plane; @@ -3102,7 +3253,7 @@ void Test_SCx(T_IO_Context * context) if ((file=fopen(filename, "rb"))) { // Lecture et vérification de la signature - if (Read_bytes(file,SCx_header.Filler1,sizeof(SCx_header.Filler1)) + if (Read_bytes(file,SCx_header.Filler1,4) && Read_word_le(file, &(SCx_header.Width)) && Read_word_le(file, &(SCx_header.Height)) && Read_byte(file, &(SCx_header.Filler2)) @@ -3138,7 +3289,7 @@ void Load_SCx(T_IO_Context * context) { file_size=File_length_file(file); - if (Read_bytes(file,SCx_header.Filler1,sizeof(SCx_header.Filler1)) + if (Read_bytes(file,SCx_header.Filler1,4) && Read_word_le(file, &(SCx_header.Width)) && Read_word_le(file, &(SCx_header.Height)) && Read_byte(file, &(SCx_header.Filler2)) @@ -3259,7 +3410,7 @@ void Save_SCx(T_IO_Context * context) SCx_header.Filler2=0xAF; SCx_header.Planes=0x00; - if (Write_bytes(file,SCx_header.Filler1,sizeof(SCx_header.Filler1)) + if (Write_bytes(file,SCx_header.Filler1,4) && Write_word_le(file, SCx_header.Width) && Write_word_le(file, SCx_header.Height) && Write_byte(file, SCx_header.Filler2) @@ -3294,6 +3445,44 @@ void Save_SCx(T_IO_Context * context) } } +//////////////////////////////////// XPM //////////////////////////////////// +void Save_XPM(T_IO_Context* context) +{ + FILE* file; + char filename[MAX_PATH_CHARACTERS]; + int i,j; + + Get_full_filename(filename, context->File_name, context->File_directory); + File_error = 0; + + file = fopen(filename, "w"); + if (file == NULL) + { + File_error = 1; + return; + } + + fprintf(file, "/* XPM */\nstatic char* pixmap[] = {\n"); + fprintf(file, "\"%d %d 256 2\",\n", context->Width, context->Height); + + for (i = 0; i < 256; i++) + { + fprintf(file,"\"%2.2X c #%2.2x%2.2x%2.2x\",\n", i, context->Palette[i].R, context->Palette[i].G, + context->Palette[i].B); + } + + for (j = 0; j < context->Height; j++) + { + fprintf(file, "\""); + for (i = 0; i < context->Width; i++) + { + fprintf(file, "%2.2X", Get_pixel(context, i, j)); + } + fprintf(file,"\"\n"); + } + + fclose(file); +} //////////////////////////////////// PNG //////////////////////////////////// @@ -3322,7 +3511,71 @@ void Test_PNG(T_IO_Context * context) fclose(file); } } + +/// Used by a callback in Load_PNG +T_IO_Context * PNG_current_context; + +int PNG_read_unknown_chunk(__attribute__((unused)) png_structp ptr, png_unknown_chunkp chunk) +{ + // png_unknown_chunkp members: + // png_byte name[5]; + // png_byte *data; + // png_size_t size; + if (!strcmp((const char *)chunk->name, "crNg")) + { + // Color animation. Similar to a LBM CRNG chunk. + unsigned int i; + byte *chunk_ptr = chunk->data; + + // Should be a multiple of 6 + if (chunk->size % 6) + return (-1); + + + for(i=0;isize/6 && i<16; i++) + { + word rate; + word flags; + byte min_col; + byte max_col; + + // Rate (big-endian word) + rate = *(chunk_ptr++) << 8; + rate |= *(chunk_ptr++); + + // Flags (big-endian) + flags = *(chunk_ptr++) << 8; + flags |= *(chunk_ptr++); + + // Min color + min_col = *(chunk_ptr++); + // Max color + max_col = *(chunk_ptr++); + + // Check validity + if (min_col != max_col) + { + // Valid cycling range + if (max_colCycle_range[i].Start=min_col; + PNG_current_context->Cycle_range[i].End=max_col; + PNG_current_context->Cycle_range[i].Inverse=(flags&2)?1:0; + PNG_current_context->Cycle_range[i].Speed=(flags&1) ? rate/78 : 0; + + PNG_current_context->Color_cycles=i+1; + } + } + + return (1); // >0 = success + } + return (0); /* did not recognize */ + +} + + png_bytep * Row_pointers; // -- Lire un fichier au format PNG ----------------------------------------- void Load_PNG(T_IO_Context * context) @@ -3360,6 +3613,7 @@ void Load_PNG(T_IO_Context * context) { png_byte color_type; png_byte bit_depth; + png_voidp user_chunk_ptr; // Setup a return point. If a pnglib loading error occurs // in this if(), the else will be executed. @@ -3368,11 +3622,18 @@ void Load_PNG(T_IO_Context * context) png_init_io(png_ptr, file); // Inform pnglib we already loaded the header. png_set_sig_bytes(png_ptr, 8); - + + // Hook the handler for unknown chunks + user_chunk_ptr = png_get_user_chunk_ptr(png_ptr); + png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr, &PNG_read_unknown_chunk); + // This is a horrid way to pass parameters, but we don't get + // much choice. PNG loader can't be reintrant. + PNG_current_context=context; + // Load file information png_read_info(png_ptr, info_ptr); - color_type = info_ptr->color_type; - bit_depth = info_ptr->bit_depth; + color_type = png_get_color_type(png_ptr,info_ptr); + bit_depth = png_get_bit_depth(png_ptr,info_ptr); // If it's any supported file // (Note: As of writing this, this test covers every possible @@ -3425,9 +3686,9 @@ void Load_PNG(T_IO_Context * context) } } if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) - Pre_load(context,info_ptr->width,info_ptr->height,File_length_file(file),FORMAT_PNG,PIXEL_SIMPLE,1); + Pre_load(context,png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr),File_length_file(file),FORMAT_PNG,PIXEL_SIMPLE,1); else - Pre_load(context, info_ptr->width,info_ptr->height,File_length_file(file),FORMAT_PNG,context->Ratio,0); + Pre_load(context,png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr),File_length_file(file),FORMAT_PNG,context->Ratio,0); if (File_error==0) { @@ -3535,8 +3796,8 @@ void Load_PNG(T_IO_Context * context) } } - context->Width=info_ptr->width; - context->Height=info_ptr->height; + context->Width=png_get_image_width(png_ptr,info_ptr); + context->Height=png_get_image_height(png_ptr,info_ptr); png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); @@ -3556,7 +3817,7 @@ void Load_PNG(T_IO_Context * context) // 8bpp for (y=0; yHeight; y++) - Row_pointers[y] = (png_byte*) malloc(info_ptr->rowbytes); + Row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr)); row_pointers_allocated = 1; png_read_image(png_ptr, Row_pointers); @@ -3575,7 +3836,7 @@ void Load_PNG(T_IO_Context * context) // It's a preview // Unfortunately we need to allocate loads of memory for (y=0; yHeight; y++) - Row_pointers[y] = (png_byte*) malloc(info_ptr->rowbytes); + Row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr)); row_pointers_allocated = 1; png_read_image(png_ptr, Row_pointers); @@ -3646,6 +3907,8 @@ void Save_PNG(T_IO_Context * context) byte * pixel_ptr; png_structp png_ptr; png_infop info_ptr; + png_unknown_chunk crng_chunk; + byte cycle_data[16*6]; // Storage for color-cycling data, referenced by crng_chunk Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; @@ -3674,9 +3937,15 @@ void Save_PNG(T_IO_Context * context) { // Commentaires texte PNG // Cette partie est optionnelle + #ifdef PNG_iTXt_SUPPORTED + png_text text_ptr[2] = { + {-1, "Software", "Grafx2", 6, 0, NULL, NULL}, + {-1, "Title", NULL, 0, 0, NULL, NULL} + #else png_text text_ptr[2] = { {-1, "Software", "Grafx2", 6}, {-1, "Title", NULL, 0} + #endif }; int nb_text_chunks=1; if (context->Comment[0]) @@ -3710,7 +3979,58 @@ void Save_PNG(T_IO_Context * context) break; default: break; - } + } + // Write cycling colors + if (context->Color_cycles) + { + // Save a chunk called 'crNg' + // The case is selected by the following rules from PNG standard: + // char 1: non-mandatory = lowercase + // char 2: private (not standard) = lowercase + // char 3: reserved = always uppercase + // char 4: can be copied by editors = lowercase + + // First, turn our nice structure into byte array + // (just to avoid padding in structures) + + byte *chunk_ptr = cycle_data; + int i; + + for (i=0; iColor_cycles; i++) + { + word flags=0; + flags|= context->Cycle_range[i].Speed?1:0; // Cycling or not + flags|= context->Cycle_range[i].Inverse?2:0; // Inverted + + // Big end of Rate + *(chunk_ptr++) = (context->Cycle_range[i].Speed*78) >> 8; + // Low end of Rate + *(chunk_ptr++) = (context->Cycle_range[i].Speed*78) & 0xFF; + + // Big end of Flags + *(chunk_ptr++) = (flags) >> 8; + // Low end of Flags + *(chunk_ptr++) = (flags) & 0xFF; + + // Min color + *(chunk_ptr++) = context->Cycle_range[i].Start; + // Max color + *(chunk_ptr++) = context->Cycle_range[i].End; + } + + // Build one unknown_chuck structure + memcpy(crng_chunk.name, "crNg",5); + crng_chunk.data=cycle_data; + crng_chunk.size=context->Color_cycles*6; + crng_chunk.location=PNG_HAVE_PLTE; + + // Give it to libpng + png_set_unknown_chunks(png_ptr, info_ptr, &crng_chunk, 1); + // libpng seems to ignore the location I provided earlier. + png_set_unknown_chunk_location(png_ptr, info_ptr, 0, PNG_HAVE_PLTE); + } + + png_write_info(png_ptr, info_ptr); /* ecriture des pixels de l'image */ diff --git a/src/filesel.c b/src/filesel.c index 738bd94c..6a24a71a 100644 --- a/src/filesel.c +++ b/src/filesel.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2009 Franck Charlet Copyright 2008 Peter Gordon Copyright 2008 Yves Rizoud @@ -22,14 +23,22 @@ along with Grafx2; if not, see */ +#include + #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) #include #include #include #define isHidden(x) (0) + +#elif defined (__MINT__) + #include + #include + #define isHidden(x) (0) #elif defined(__WIN32__) #include #include + #include #define isHidden(x) (GetFileAttributesA((x)->d_name)&FILE_ATTRIBUTE_HIDDEN) #else #include @@ -62,12 +71,66 @@ #include "help.h" #include "filesel.h" -#define NORMAL_FILE_COLOR MC_Light // color du texte pour une ligne de fichier non sélectionné -#define NORMAL_DIRECTORY_COLOR MC_Dark // color du texte pour une ligne de répertoire non sélectionné -#define NORMAL_BACKGROUND_COLOR MC_Black // color du fond pour une ligne non sélectionnée -#define SELECTED_FILE_COLOR MC_White // color du texte pour une ligne de fichier sélectionnée -#define SELECTED_DIRECTORY_COLOR MC_Light // color du texte pour une ligne de repértoire sélectionnée -#define SELECTED_BACKGROUND_COLOR MC_Dark // color du fond pour une ligne sélectionnée +#define NORMAL_FILE_COLOR MC_Light // color du texte pour une ligne de + // fichier non sélectionné +#define NORMAL_DIRECTORY_COLOR MC_Dark // color du texte pour une ligne de + // répertoire non sélectionné +#define NORMAL_BACKGROUND_COLOR MC_Black // color du fond pour une ligne + // non sélectionnée +#define SELECTED_FILE_COLOR MC_White // color du texte pour une ligne de + // fichier sélectionnée +#define SELECTED_DIRECTORY_COLOR MC_Light // color du texte pour une ligne de + // repértoire sélectionnée +#define SELECTED_BACKGROUND_COLOR MC_Dark // color du fond pour une ligne + // sélectionnée + +// -- Native fileselector for WIN32 + +// Returns 0 if all ok, something else if failed +byte Native_filesel(byte load) +{ + //load = load; +#ifdef __WIN32__ + OPENFILENAME ofn; + char szFileName[MAX_PATH] = ""; + SDL_SysWMinfo wminfo; + HWND hwnd; + + SDL_VERSION(&wminfo.version); + SDL_GetWMInfo(&wminfo); + hwnd = wminfo.window; + + ZeroMemory(&ofn, sizeof(ofn)); + + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwnd; + ofn.lpstrFilter = "Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0"; + ofn.lpstrFile = szFileName; + ofn.nMaxFile = MAX_PATH; + ofn.Flags = OFN_EXPLORER; + if(load) ofn.Flags |= OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; + ofn.lpstrDefExt = "txt"; + + if(load) + { + if (GetOpenFileName(&ofn)) + // Do something usefull with the filename stored in szFileName + return 0; + else + // error - check if its just user pressing cancel or something else + return CommDlgExtendedError(); + } else if(GetSaveFileName(&ofn)) { + return 0; + } else { + // Check if cancel + return CommDlgExtendedError(); + } +#else + return 255; // fail ! +#endif +} + +// -- "Standard" fileselector for other platforms // -- Fileselector data @@ -86,7 +149,7 @@ static char Selector_filename[256]; void Recount_files(T_Fileselector *list) { T_Fileselector_item *item; - + list->Nb_files=0; list->Nb_directories=0; list->Nb_elements=0; @@ -146,30 +209,48 @@ void Free_fileselector_list(T_Fileselector *list) Recount_files(list); } -char * Format_filename(const char * fname, int type) +char * Format_filename(const char * fname, word max_length, int type) { - static char result[19]; + static char result[40]; int c; int other_cursor; int pos_last_dot; + // safety + if (max_length>40) + max_length=40; + if (strcmp(fname,PARENT_DIR)==0) { strcpy(result,"<-PARENT DIRECTORY"); + // Append spaces + for (c=18; c= 18) - result[17]=ELLIPSIS_CHARACTER; + if (c >= max_length-1) + result[max_length-2]=ELLIPSIS_CHARACTER; } else { - strcpy(result," . "); + // Initialize as all spaces + for (c = 0; c 13) + if (c > max_length-6) { - result[13]=ELLIPSIS_CHARACTER; + result[max_length-6]=ELLIPSIS_CHARACTER; break; } result[c]=fname[c]; @@ -190,7 +271,7 @@ char * Format_filename(const char * fname, int type) // Ensuite on recopie la partie qui suit le point (si nécessaire): if (pos_last_dot != -1) { - for (c = pos_last_dot+1,other_cursor=15;fname[c]!='\0' && other_cursor < 18;c++,other_cursor++) + for (c = pos_last_dot+1,other_cursor=max_length-4;fname[c]!='\0' && other_cursor < max_length-1;c++,other_cursor++) result[other_cursor]=fname[c]; } } @@ -199,25 +280,29 @@ char * Format_filename(const char * fname, int type) // -- Rajouter a la liste des elements de la liste un element --------------- -void Add_element_to_list(T_Fileselector *list, const char * fname, int type) +void Add_element_to_list(T_Fileselector *list, const char * full_name, const char *short_name, int type, byte icon) // Cette procedure ajoute a la liste chainee un fichier passé en argument. { - // Pointeur temporaire d'insertion + // Working element T_Fileselector_item * temp_item; - // On alloue de la place pour un nouvel element - temp_item=(T_Fileselector_item *)malloc(sizeof(T_Fileselector_item)); + // Allocate enough room for one struct + the visible label + temp_item=(T_Fileselector_item *)malloc(sizeof(T_Fileselector_item)+strlen(short_name)); - // On met a jour le nouvel emplacement: - strcpy(temp_item->Short_name,Format_filename(fname, type)); - strcpy(temp_item->Full_name,fname); + // Initialize element + strcpy(temp_item->Short_name,short_name); + strcpy(temp_item->Full_name,full_name); temp_item->Type = type; + temp_item->Icon = icon; + // Doubly-linked temp_item->Next =list->First; temp_item->Previous=NULL; if (list->First!=NULL) list->First->Previous=temp_item; + + // Put new element at the beginning list->First=temp_item; } @@ -275,8 +360,25 @@ void Read_list_of_files(T_Fileselector *list, byte selected_format) // Après effacement, il ne reste ni fichier ni répertoire dans la liste // On lit tous les répertoires: + +#if defined (__MINT__) + static char path[1024]; + static char path2[1024]; + path[0]='\0'; + path2[0]='\0'; + + char currentDrive='A'; + currentDrive=currentDrive+Dgetdrv(); + + Dgetpath(path,0); + sprintf(path2,"%c:\%s",currentDrive,path); + + strcat(path2,PATH_SEPARATOR); + current_directory=opendir(path2); +#else current_path=getcwd(NULL,0); current_directory=opendir(current_path); +#endif while ((entry=readdir(current_directory))) { // On ignore le répertoire courant @@ -294,7 +396,7 @@ void Read_list_of_files(T_Fileselector *list, byte selected_format) !isHidden(entry))) { // On rajoute le répertoire à la liste - Add_element_to_list(list, entry->d_name, 1); + Add_element_to_list(list, entry->d_name, Format_filename(entry->d_name, 19, 1), 1, ICON_NONE); list->Nb_directories++; } else if (S_ISREG(Infos_enreg.st_mode) && //Il s'agit d'un fichier @@ -307,7 +409,7 @@ void Read_list_of_files(T_Fileselector *list, byte selected_format) if (Check_extension(entry->d_name, ext)) { // On rajoute le fichier à la liste - Add_element_to_list(list, entry->d_name, 0); + Add_element_to_list(list, entry->d_name, Format_filename(entry->d_name, 19, 0), 0, ICON_NONE); list->Nb_files++; // Stop searching ext=NULL; @@ -323,12 +425,35 @@ void Read_list_of_files(T_Fileselector *list, byte selected_format) } #if defined(__MORPHOS__) || defined(__AROS__) || defined (__amigaos4__) || defined(__amigaos__) - Add_element_to_list(list, "/",1); // on amiga systems, / means parent. And there is no .. + Add_element_to_list(list, "/", Format_filename("/",19,1), 1, ICON_NONE); // on amiga systems, / means parent. And there is no .. list->Nb_directories ++; +#elif defined (__MINT__) + T_Fileselector_item *item=NULL; + // check if ".." exists if not add it + // FreeMinT lists ".." already, but this is not so for TOS + // simply adding it will cause double PARENT_DIR under FreeMiNT + + bool bFound= false; + + for (item = list->First; (((item != NULL) && (bFound==false))); item = item->Next){ + if (item->Type == 1){ + if(strncmp(item->Full_name,"..",(sizeof(char)*2))==0) bFound=true; + } + } + + if(!bFound){ + Add_element_to_list(list, "..",1,Format_filename("/",19,1),ICON_NONE); // add if not present + list->Nb_directories ++; + } + #endif closedir(current_directory); +#if defined (__MINT__) + +#else free(current_path); +#endif current_path = NULL; Recount_files(list); @@ -375,7 +500,7 @@ void Read_list_of_drives(T_Fileselector *list) { bstrtostr( dl->dol_Name, tmp, 254 ); strcat( tmp, ":" ); - Add_element_to_list(list, tmp, 2 ); + Add_element_to_list(list, tmp, Format_filename(tmp, 19, 2), 2, ICON_NONE ); list->Nb_directories++; } UnLockDosList( LDF_VOLUMES | LDF_READ ); @@ -387,6 +512,8 @@ void Read_list_of_drives(T_Fileselector *list) int drive_bits = GetLogicalDrives(); int drive_index; int bit_index; + byte icon; + // Sous Windows, on a la totale, presque aussi bien que sous DOS: drive_index = 0; for (bit_index=0; bit_index<26 && drive_index<23; bit_index++) @@ -395,35 +522,51 @@ void Read_list_of_drives(T_Fileselector *list) { // On a ce lecteur, il faut maintenant déterminer son type "physique". // pour profiter des jolies icones de X-man. - int drive_type; char drive_path[]="A:\\"; // Cette API Windows est étrange, je dois m'y faire... drive_path[0]='A'+bit_index; switch (GetDriveType(drive_path)) { case DRIVE_CDROM: - drive_type=ICON_CDROM; + icon=ICON_CDROM; break; case DRIVE_REMOTE: - drive_type=ICON_NETWORK; + icon=ICON_NETWORK; break; case DRIVE_REMOVABLE: - drive_type=ICON_FLOPPY_3_5; + icon=ICON_FLOPPY_3_5; break; case DRIVE_FIXED: - drive_type=ICON_HDD; + icon=ICON_HDD; break; default: - drive_type=ICON_NETWORK; + icon=ICON_NETWORK; break; } drive_name[0]='A'+bit_index; - Add_element_to_list(list, drive_name,2); + Add_element_to_list(list, drive_name, Format_filename(drive_name,18,2), 2, icon); list->Nb_directories++; drive_index++; } } } + #elif defined(__MINT__) + char drive_name[]="A:\\"; + unsigned long drive_bits = Drvmap(); //get drive map bitfield + int drive_index; + int bit_index; + drive_index = 0; + for (bit_index=0; bit_index<32; bit_index++) + { + if ( (1 << bit_index) & drive_bits ) + { + drive_name[0]='A'+bit_index; + Add_element_to_list(list, drive_name,Format_filename(drive_name,19,2),2,ICON_NONE); + list->Nb_directories++; + drive_index++; + } + } + #else { //Sous les différents unix, on va mettre @@ -440,11 +583,11 @@ void Read_list_of_drives(T_Fileselector *list) #else char * home_dir = getenv("HOME"); #endif - Add_element_to_list(list, "/", 2); + Add_element_to_list(list, "/", Format_filename("/",19,2), 2, ICON_NONE); list->Nb_directories++; if(home_dir) { - Add_element_to_list(list, home_dir, 2); + Add_element_to_list(list, home_dir, Format_filename(home_dir, 19, 2), 2, ICON_NONE); list->Nb_directories++; } @@ -454,7 +597,7 @@ void Read_list_of_drives(T_Fileselector *list) { if(mount_points_list->me_dummy == 0 && strcmp(mount_points_list->me_mountdir,"/") && strcmp(mount_points_list->me_mountdir,"/home")) { - Add_element_to_list(list, mount_points_list->me_mountdir,2); + Add_element_to_list(list, mount_points_list->me_mountdir, Format_filename(mount_points_list->me_mountdir, 19, 2), 2, ICON_NONE); list->Nb_directories++; } next = mount_points_list -> me_next; @@ -473,6 +616,15 @@ void Read_list_of_drives(T_Fileselector *list) Recount_files(list); } +// Comparison of file names: +#ifdef WIN32 +// case-insensitive + #define FILENAME_COMPARE strcasecmp +#else +// case-sensitive + #define FILENAME_COMPARE strcmp +#endif + // -- Tri de la liste des fichiers et répertoires --------------------------- void Sort_list_of_files(T_Fileselector *list) @@ -514,7 +666,7 @@ void Sort_list_of_files(T_Fileselector *list) // Si les deux éléments sont de même type et que le nom du suivant // est plus petit que celui du courant -> need_swap else if ( (current_item->Type==next_item->Type) && - (strcmp(current_item->Full_name,next_item->Full_name)>0) ) + (FILENAME_COMPARE(current_item->Full_name,next_item->Full_name)>0) ) need_swap=1; @@ -640,7 +792,14 @@ void Display_file_list(T_Fileselector *list, short offset_first,short selector_o } // On affiche l'élément - Print_in_window(8,95+index*8,current_item->Short_name,text_color,background_color); + if (current_item->Icon != ICON_NONE) + { + // Name preceded by an icon + Print_in_window(16,95+index*8,current_item->Short_name,text_color,background_color); + Window_display_icon_sprite(8,95+index*8,current_item->Icon); + } else + // Name without icon + Print_in_window(8,95+index*8,current_item->Short_name,text_color,background_color); // On passe à la ligne suivante selector_offset--; @@ -889,7 +1048,7 @@ void Prepare_and_display_filelist(short Position, short offset, T_Scroller_butto { button->Nb_elements=Filelist.Nb_elements; button->Position=Position; - Compute_slider_cursor_height(button); + Compute_slider_cursor_length(button); Window_draw_slider(button); // On efface les anciens noms de fichier: Window_rectangle(8-1,95-1,144+2,80+2,MC_Black); @@ -984,12 +1143,8 @@ short Find_file_in_fileselector(T_Fileselector *list, const char * fname) return close_match; } - -void Highlight_file(char * fname) +void Highlight_file(short index) { - short index; - - index=Find_file_in_fileselector(&Filelist, fname); if ((Filelist.Nb_elements<=10) || (index<5)) { @@ -1012,15 +1167,17 @@ void Highlight_file(char * fname) } -char * Find_filename_match(T_Fileselector *list, char * fname) +short Find_filename_match(T_Fileselector *list, char * fname) { - char * best_name_ptr; + short best_match; T_Fileselector_item * current_item; - byte matching_letters=0; - byte counter; - - best_name_ptr=NULL; + short item_number; + byte matching_letters=0; + byte counter; + best_match=-1; + item_number=0; + for (current_item=list->First; current_item!=NULL; current_item=current_item->Next) { if ( (!Config.Find_file_fast) @@ -1031,12 +1188,96 @@ char * Find_filename_match(T_Fileselector *list, char * fname) if (counter>matching_letters) { matching_letters=counter; - best_name_ptr=current_item->Full_name; + best_match=item_number; } } + item_number++; } - return best_name_ptr; + return best_match; +} + +// Quicksearch system +char quicksearch_filename[MAX_PATH_CHARACTERS]=""; + +void Reset_quicksearch(void) +{ + quicksearch_filename[0]='\0'; +} + +short Quicksearch(T_Fileselector *selector) +{ + int len; + short most_matching_item; + + // Autre => On se place sur le nom de fichier qui correspond + len=strlen(quicksearch_filename); + if (Key_ANSI>= ' ' && Key_ANSI < 255 && len<50) + { + quicksearch_filename[len]=Key_ANSI; + quicksearch_filename[len+1]='\0'; + most_matching_item=Find_filename_match(selector, quicksearch_filename); + if ( most_matching_item >= 0 ) + { + return most_matching_item; + } + *quicksearch_filename=0; + } + return -1; +} + +// Translated from Highlight_file +void Locate_list_item(T_List_button * list, T_Fileselector * selector, short selected_item) +{ + + // Safety bounds + if (selected_item<0) + selected_item=0; + else if (selected_item>=list->Scroller->Nb_elements) + selected_item=list->Scroller->Nb_elements-1; + + + if ((list->Scroller->Nb_elements<=list->Scroller->Nb_visibles) || (selected_item<(list->Scroller->Nb_visibles/2))) + { + list->List_start=0; + list->Cursor_position=selected_item; + } + else + { + if (selected_item>=list->Scroller->Nb_elements-(list->Scroller->Nb_visibles/2)) + { + list->List_start=list->Scroller->Nb_elements-list->Scroller->Nb_visibles; + list->Cursor_position=selected_item-list->List_start; + } + else + { + list->List_start=selected_item-(list->Scroller->Nb_visibles/2-1); + list->Cursor_position=(list->Scroller->Nb_visibles/2-1); + } + } +} + +int Quicksearch_list(T_List_button * list, T_Fileselector * selector) +{ + // Try Quicksearch + short selected_item=Quicksearch(selector); + if (selected_item>=0 && selected_item!=list->Cursor_position+list->List_start) + { + Locate_list_item(list, selector, selected_item); + + Hide_cursor(); + // Mise à jour du scroller + list->Scroller->Position=list->List_start; + Window_draw_slider(list->Scroller); + + Window_redraw_list(list); + Display_cursor(); + // Store the selected value as attribute2 + Window_attribute2=list->List_start + list->Cursor_position; + // Return the control ID of the list. + return list->Number; + } + return 0; } byte Button_Load_or_Save(byte load, T_IO_Context *context) @@ -1048,17 +1289,20 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) T_Dropdown_button * formats_dropdown; T_Dropdown_button * bookmark_dropdown[4]; short temp; + unsigned int format; int dummy=0; // Sert à appeler SDL_GetKeyState byte save_or_load_image=0; byte has_clicked_ok=0;// Indique si on a clické sur Load ou Save ou sur //un bouton enclenchant Load ou Save juste après. byte initial_back_color; // | fout en l'air (c'te conne). char previous_directory[MAX_PATH_CHARACTERS]; // Répertoire d'où l'on vient après un CHDIR - char quicksearch_filename[MAX_PATH_CHARACTERS]=""; char save_filename[MAX_PATH_CHARACTERS]; char initial_comment[COMMENT_SIZE+1]; - char * most_matching_filename; short window_shortcut; + + Reset_quicksearch(); + + // if (Native_filesel(load) != 0); // TODO : handle this if (context->Type == CONTEXT_MAIN_IMAGE) window_shortcut = load?(0x100+BUTTON_LOAD):(0x100+BUTTON_SAVE); @@ -1099,7 +1343,7 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) } // Affichage du commentaire if (Get_fileformat(Main_format)->Comment) - Print_in_window(47,70,context->Comment,MC_Black,MC_Light); + Print_in_window(45,70,context->Comment,MC_Black,MC_Light); } Window_set_normal_button(253,180,51,14,"Cancel",0,1,KEY_ESC); // 2 @@ -1124,11 +1368,11 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) Get_fileformat(Main_format)->Label, 1,0,1,RIGHT_SIDE|LEFT_SIDE,0); // 6 - for (temp=0; temp < NB_KNOWN_FORMATS; temp++) + for (format=0; format < Nb_known_formats(); format++) { - if ((load && (File_formats[temp].Identifier <= FORMAT_ALL_FILES || File_formats[temp].Load)) || - (!load && File_formats[temp].Save)) - Window_dropdown_add_item(formats_dropdown,File_formats[temp].Identifier,File_formats[temp].Label); + if ((load && (File_formats[format].Identifier <= FORMAT_ALL_FILES || File_formats[format].Load)) || + (!load && File_formats[format].Save)) + Window_dropdown_add_item(formats_dropdown,File_formats[format].Identifier,File_formats[format].Label); } Print_in_window(70,18,"Format",MC_Dark,MC_Light); @@ -1161,13 +1405,30 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) // On prend bien soin de passer dans le répertoire courant (le bon qui faut! Oui madame!) if (load) { + #if defined(__MINT__) + chdir(Main_current_directory); + static char path[1024]={0}; + Dgetpath(path,0); + strcat(path,PATH_SEPARATOR); + strcpy(Main_current_directory,path); + #else chdir(Main_current_directory); getcwd(Main_current_directory,256); + #endif } else { + #if defined(__MINT__) chdir(context->File_directory); + static char path[1024]={0}; + Dgetpath(path,0); + strcat(path,PATH_SEPARATOR); + strcpy(Main_current_directory,path); + #else getcwd(Main_current_directory,256); + #endif + + } // Affichage des premiers fichiers visibles: @@ -1181,7 +1442,7 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) // On affiche le nouveau nom de fichier Print_filename_in_fileselector(); - Highlight_file(context->File_name); + Highlight_file(Find_file_in_fileselector(&Filelist, context->File_name)); Prepare_and_display_filelist(Main_fileselector_position,Main_fileselector_offset,file_scroller); } @@ -1309,7 +1570,8 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) // On vient de changer de nom de fichier, donc on doit s'appreter // a rafficher une preview New_preview_is_needed=1; - *quicksearch_filename=0; + Reset_quicksearch(); + } else { @@ -1322,7 +1584,7 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) has_clicked_ok=1; New_preview_is_needed=1; - *quicksearch_filename=0; + Reset_quicksearch(); } } Display_cursor(); @@ -1340,26 +1602,40 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) Display_file_list(&Filelist, Main_fileselector_position,Main_fileselector_offset); Display_cursor(); New_preview_is_needed=1; - *quicksearch_filename=0; + Reset_quicksearch(); break; - case 6 : // Scroller des formats - Hide_cursor(); - // On met à jour le format de browsing du fileselect: - Main_format=Window_attribute2; - // Comme on change de liste, on se place en début de liste: - Main_fileselector_position=0; - Main_fileselector_offset=0; - // Affichage des premiers fichiers visibles: - Reload_list_of_files(Main_format,file_scroller); - Display_cursor(); - New_preview_is_needed=1; - *quicksearch_filename=0; + case 6 : // Scroller des formats + // On met à jour le format de browsing du fileselect: + if (Main_format != Window_attribute2) { + char* savename = (char *)strdup(Selector_filename); + int nameLength = strlen(savename); + DEBUG(Selector_filename, 42); + Main_format = Window_attribute2; + // Comme on change de liste, on se place en début de liste: + Main_fileselector_position = 0; + Main_fileselector_offset = 0; + // Affichage des premiers fichiers visibles: + Hide_cursor(); + Reload_list_of_files(Main_format, file_scroller); + New_preview_is_needed = 1; + Reset_quicksearch(); + strcpy(Selector_filename, savename); + if (Get_fileformat(Main_format)->Default_extension[0] != '\0' && + Selector_filename[nameLength - 4] == '.') + { + strcpy(Selector_filename + nameLength - 3, + Get_fileformat(Main_format)->Default_extension); + } + free(savename); + Print_filename_in_fileselector(); + Display_cursor(); + } break; case 7 : // Saisie d'un commentaire pour la sauvegarde if ( (!load) && (Get_fileformat(Main_format)->Comment) ) { - Readline(45,70,context->Comment,32,0); + Readline(45, 70, context->Comment, 32, INPUT_TYPE_STRING); Display_cursor(); } break; @@ -1368,7 +1644,7 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) // Save the filename strcpy(save_filename, Selector_filename); - if (Readline(82,48,Selector_filename,27,2)) + if (Readline(82,48,Selector_filename,27,INPUT_TYPE_FILENAME)) { // On regarde s'il faut rajouter une extension. C'est-à-dire s'il // n'y a pas de '.' dans le nom du fichier. @@ -1382,7 +1658,7 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) if(!Directory_exists(Selector_filename)) { strcat(Selector_filename, "."); - strcat(Selector_filename,Get_fileformat(Main_format)->Default_extension); + strcat(Selector_filename, Get_fileformat(Main_format)->Default_extension); } } else @@ -1438,7 +1714,7 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) Prepare_and_display_filelist(Main_fileselector_position,Main_fileselector_offset,file_scroller); Display_cursor(); New_preview_is_needed=1; - *quicksearch_filename=0; + Reset_quicksearch(); break; default: if (clicked_button>=10 && clicked_button<10+NB_BOOKMARKS) @@ -1451,11 +1727,10 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) case -1: // bouton lui-même: aller au répertoire mémorisé if (Config.Bookmark_directory[clicked_button-10]) { - *quicksearch_filename=0; strcpy(Selector_filename,Config.Bookmark_directory[clicked_button-10]); Selected_type=1; has_clicked_ok=1; - *quicksearch_filename=0; + Reset_quicksearch(); } break; @@ -1490,7 +1765,7 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) strcpy(bookmark_label, Config.Bookmark_label[clicked_button-10]); if (bookmark_label[7]==ELLIPSIS_CHARACTER) bookmark_label[7]='\0'; - if (Readline_ex(bookmark_dropdown[clicked_button-10]->Pos_X+3+10,bookmark_dropdown[clicked_button-10]->Pos_Y+2,bookmark_label,8,8,0,0)) + if (Readline_ex(bookmark_dropdown[clicked_button-10]->Pos_X+3+10,bookmark_dropdown[clicked_button-10]->Pos_Y+2,bookmark_label,8,8,INPUT_TYPE_STRING,0)) strcpy(Config.Bookmark_label[clicked_button-10],bookmark_label); Display_bookmark(bookmark_dropdown[clicked_button-10],clicked_button-10); Display_cursor(); @@ -1515,63 +1790,63 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) { case SDLK_UNKNOWN : break; case SDLK_DOWN : // Bas - *quicksearch_filename=0; + Reset_quicksearch(); Hide_cursor(); Selector_scroll_down(&Main_fileselector_position,&Main_fileselector_offset); Scroll_fileselector(file_scroller); Key=0; break; case SDLK_UP : // Haut - *quicksearch_filename=0; + Reset_quicksearch(); Hide_cursor(); Selector_scroll_up(&Main_fileselector_position,&Main_fileselector_offset); Scroll_fileselector(file_scroller); Key=0; break; case SDLK_PAGEDOWN : // PageDown - *quicksearch_filename=0; + Reset_quicksearch(); Hide_cursor(); Selector_page_down(&Main_fileselector_position,&Main_fileselector_offset,9); Scroll_fileselector(file_scroller); Key=0; break; case SDLK_PAGEUP : // PageUp - *quicksearch_filename=0; + Reset_quicksearch(); Hide_cursor(); Selector_page_up(&Main_fileselector_position,&Main_fileselector_offset,9); Scroll_fileselector(file_scroller); Key=0; break; case SDLK_END : // End - *quicksearch_filename=0; + Reset_quicksearch(); Hide_cursor(); Selector_end(&Main_fileselector_position,&Main_fileselector_offset); Scroll_fileselector(file_scroller); Key=0; break; case SDLK_HOME : // Home - *quicksearch_filename=0; + Reset_quicksearch(); Hide_cursor(); Selector_home(&Main_fileselector_position,&Main_fileselector_offset); Scroll_fileselector(file_scroller); Key=0; break; case KEY_MOUSEWHEELDOWN : - *quicksearch_filename=0; + Reset_quicksearch(); Hide_cursor(); Selector_page_down(&Main_fileselector_position,&Main_fileselector_offset,3); Scroll_fileselector(file_scroller); Key=0; break; case KEY_MOUSEWHEELUP : - *quicksearch_filename=0; + Reset_quicksearch(); Hide_cursor(); Selector_page_up(&Main_fileselector_position,&Main_fileselector_offset,3); Scroll_fileselector(file_scroller); Key=0; break; case SDLK_BACKSPACE : // Backspace - *quicksearch_filename=0; + Reset_quicksearch(); // Si le choix ".." est bien en tête des propositions... if (!strcmp(Filelist.First->Full_name,PARENT_DIR)) { @@ -1585,6 +1860,8 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) default: if (clicked_button<=0) { + short selected_item; + if (Is_shortcut(Key,0x100+BUTTON_HELP)) { Window_help(load?BUTTON_LOAD:BUTTON_SAVE, NULL); @@ -1595,30 +1872,22 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) clicked_button=2; break; } - // Autre => On se place sur le nom de fichier qui correspond - temp=strlen(quicksearch_filename); - if (Key_ANSI>= ' ' && Key_ANSI < 255 && temp<50) + + selected_item=Quicksearch(&Filelist); + if (selected_item>=0) { - quicksearch_filename[temp]=Key_ANSI; - quicksearch_filename[temp+1]='\0'; - most_matching_filename=Find_filename_match(&Filelist, quicksearch_filename); - if ( (most_matching_filename) ) - { temp=Main_fileselector_position+Main_fileselector_offset; Hide_cursor(); - Highlight_file(most_matching_filename); + Highlight_file(selected_item); Prepare_and_display_filelist(Main_fileselector_position,Main_fileselector_offset,file_scroller); Display_cursor(); if (temp!=Main_fileselector_position+Main_fileselector_offset) New_preview_is_needed=1; - } - else - *quicksearch_filename=0; - Key=0; } + // Key=0; ? } else - *quicksearch_filename=0; + Reset_quicksearch(); } if (has_clicked_ok) @@ -1643,13 +1912,20 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) // On doit rentrer dans le répertoire: if (!chdir(Selector_filename)) { + #if defined (__MINT__) + static char path[1024]={0}; + char currentDrive='A'; + currentDrive=currentDrive+Dgetdrv(); + Dgetpath(path,0); + sprintf(Main_current_directory,"%c:\%s",currentDrive,path); + #else getcwd(Main_current_directory,256); - + #endif // On lit le nouveau répertoire Read_list_of_files(&Filelist, Main_format); Sort_list_of_files(&Filelist); // On place la barre de sélection sur le répertoire d'où l'on vient - Highlight_file(previous_directory); + Highlight_file(Find_file_in_fileselector(&Filelist, previous_directory)); } else Error(0); @@ -1659,7 +1935,7 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) New_preview_is_needed=1; // On est dans un nouveau répertoire, donc on remet le quicksearch à 0 - *quicksearch_filename=0; + Reset_quicksearch(); } else // Sinon on essaye de charger ou sauver le fichier { @@ -1681,7 +1957,7 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) // On efface le commentaire précédent Window_rectangle(45,70,32*8,8,MC_Light); // On nettoie la zone où va s'afficher la preview: - Window_rectangle(183,95,120,80,MC_Light); + Window_rectangle(183,95,PREVIEW_WIDTH,PREVIEW_HEIGHT,MC_Light); // On efface les dimensions de l'image Window_rectangle(143,59,72,8,MC_Light); // On efface la taille du fichier @@ -1697,7 +1973,7 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) // Un update pour couvrir les 4 zones: 3 libellés plus le commentaire Update_window_area(45,48,256,30); // Zone de preview - Update_window_area(183,95,120,80); + Update_window_area(183,95,PREVIEW_WIDTH,PREVIEW_HEIGHT); } New_preview_is_needed=0; diff --git a/src/filesel.h b/src/filesel.h index 3fd1fddb..19b6f777 100644 --- a/src/filesel.h +++ b/src/filesel.h @@ -31,12 +31,12 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context); -void Add_element_to_list(T_Fileselector *list, const char * fname, int type); +void Add_element_to_list(T_Fileselector *list, const char * full_name, const char *short_name, int type, byte icon); /// /// Formats a display name for a file, directory, or similar name (drive, volume). -/// The returned value is a pointer to a single static buffer of 19 characters +/// The returned value is a pointer to a single static buffer of maximum 40 characters /// including the '\\0'. -char * Format_filename(const char * fname, int type); +char * Format_filename(const char * fname, word max_length, int type); void Free_fileselector_list(T_Fileselector *list); @@ -48,4 +48,10 @@ T_Fileselector_item * Get_item_by_index(T_Fileselector *list, short index); short Find_file_in_fileselector(T_Fileselector *list, const char * fname); +void Locate_list_item(T_List_button * list, T_Fileselector * selector, short selected_item); + +int Quicksearch_list(T_List_button * list, T_Fileselector * selector); + +void Reset_quicksearch(void); + #endif diff --git a/src/global.h b/src/global.h index 086e227d..3746126b 100644 --- a/src/global.h +++ b/src/global.h @@ -73,6 +73,12 @@ GFX2_GLOBAL byte MC_Light; ///< Index of color to use as "light grey" in the GUI GFX2_GLOBAL byte MC_White; ///< Index of color to use as "white" in the GUI menus. GFX2_GLOBAL byte MC_Trans; ///< Index of color to use as "transparent" while loading the GUI file. +GFX2_GLOBAL byte MC_OnBlack; ///< Index of color immediately lighter than "black" in the GUI menus. +GFX2_GLOBAL byte MC_Window; ///< Index of color to use as window background in the GUI menus. +GFX2_GLOBAL byte MC_Lighter; ///< Index of color lighter than window in the GUI menus. +GFX2_GLOBAL byte MC_Darker; ///< Index of color darker than window in the GUI menus. + + // Input state GFX2_GLOBAL word Mouse_X; ///< Current mouse cursor position. GFX2_GLOBAL word Mouse_Y; ///< Current mouse cursor position. @@ -294,10 +300,6 @@ GFX2_GLOBAL short Main_image_height; GFX2_GLOBAL short Main_offset_X; /// Y position (in image space) of the pixel to display in the top left corner of screen. GFX2_GLOBAL short Main_offset_Y; -/// Backup of ::Main_offset_X, used to store it while the magnifier is open. -GFX2_GLOBAL short Old_main_offset_X; -/// Backup of ::Main_offset_Y, used to store it while the magnifier is open. -GFX2_GLOBAL short Old_main_offset_Y; /// Name of the directory that holds the image currently edited. GFX2_GLOBAL char Main_file_directory[1024]; /// Filename (without directory) of the image currently edited. @@ -364,10 +366,6 @@ GFX2_GLOBAL short Spare_image_height; GFX2_GLOBAL short Spare_offset_X; /// Y position (in image space) of the pixel to display in the top left corner of screen. GFX2_GLOBAL short Spare_offset_Y; -/// Backup of ::Main_offset_X, used to store it while the magnifier is open. -GFX2_GLOBAL short Old_spare_offset_X; -/// Backup of ::Main_offset_Y, used to store it while the magnifier is open. -GFX2_GLOBAL short Old_spare_offset_Y; /// Name of the directory that holds the image currently edited as spare page. GFX2_GLOBAL char Spare_file_directory[MAX_PATH_CHARACTERS]; /// Filename (without directory) of the image currently edited as spare page. @@ -432,8 +430,16 @@ GFX2_GLOBAL T_List_of_pages * Spare_backups; // -- Brush data -/// Pixel data of the current brush. +/// Pixel data of the current brush (remapped). GFX2_GLOBAL byte * Brush; +/// Pixel data of the current brush (before remap). +GFX2_GLOBAL byte * Brush_original_pixels; +/// Palette of the brush, from when it was grabbed. +GFX2_GLOBAL T_Palette Brush_original_palette; +/// Back_color used when the brush was grabbed +GFX2_GLOBAL byte Brush_original_back_color; +/// Color mapping from ::Brush_original_pixels to ::Brush +GFX2_GLOBAL byte Brush_colormap[256]; /// X coordinate of the brush's "hot spot". It is < ::Brush_width GFX2_GLOBAL word Brush_offset_X; /// Y coordinate of the brush's "hot spot". It is < ::Brush_height @@ -492,9 +498,9 @@ GFX2_GLOBAL word Menu_palette_cell_width; GFX2_GLOBAL T_Menu_Bar Menu_bars[MENUBAR_COUNT] #ifdef GLOBAL_VARIABLES = -{{MENU_WIDTH, 9, 1, 45, NULL, 20, BUTTON_HIDE }, // Status - {MENU_WIDTH, 10, 1, 35, NULL, 144, BUTTON_LAYER_SELECT }, // Layers - {MENU_WIDTH, 35, 1, 0, NULL, 254, BUTTON_CHOOSE_COL }} // Main +{{MENU_WIDTH, 9, 1, 45, {NULL,NULL,NULL}, 20, BUTTON_HIDE }, // Status + {MENU_WIDTH, 10, 1, 35, {NULL,NULL,NULL}, 144, BUTTON_LAYER_SELECT }, // Layers + {MENU_WIDTH, 35, 1, 0, {NULL,NULL,NULL}, 254, BUTTON_CHOOSE_COL }} // Main #endif ; @@ -510,71 +516,59 @@ GFX2_GLOBAL word Menu_Y_before_window; /// Backup of ::Paintbrush_hidden, used to store it while a window is open. GFX2_GLOBAL byte Paintbrush_hidden_before_window; -GFX2_GLOBAL word Window_stack_pos_X[8]; +/// The global stack of editor screens. +GFX2_GLOBAL T_Window Window_stack[8]; + /// Position of the left border of the topmost window (in screen coordinates) -#define Window_pos_X Window_stack_pos_X[Windows_open-1] +#define Window_pos_X Window_stack[Windows_open-1].Pos_X -GFX2_GLOBAL word Window_stack_pos_Y[8]; /// Position of the top border of the topmost window (in screen coordinates) -#define Window_pos_Y Window_stack_pos_Y[Windows_open-1] +#define Window_pos_Y Window_stack[Windows_open-1].Pos_Y -GFX2_GLOBAL word Window_stack_width[8]; /// /// Width of the topmost window, in "window pixels" /// (multiply by ::Menu_factor_X to get screen pixels) -#define Window_width Window_stack_width[Windows_open-1] +#define Window_width Window_stack[Windows_open-1].Width -GFX2_GLOBAL word Window_stack_height[8]; /// /// Height of the topmost window, in "window pixels" /// (multiply by ::Menu_factor_Y to get screen pixels) -#define Window_height Window_stack_height[Windows_open-1] +#define Window_height Window_stack[Windows_open-1].Height -GFX2_GLOBAL word Window_stack_nb_buttons[8]; /// Total number of buttons/controls in the topmost window. -#define Window_nb_buttons Window_stack_nb_buttons[Windows_open-1] +#define Window_nb_buttons Window_stack[Windows_open-1].Nb_buttons -GFX2_GLOBAL T_Normal_button * Window_stack_normal_button_list[8]; /// List of normal buttons in the topmost window. -#define Window_normal_button_list Window_stack_normal_button_list[Windows_open-1] +#define Window_normal_button_list Window_stack[Windows_open-1].Normal_button_list -GFX2_GLOBAL T_Palette_button * Window_stack_palette_button_list[8]; /// List of "palette" buttons in the topmost window. -#define Window_palette_button_list Window_stack_palette_button_list[Windows_open-1] +#define Window_palette_button_list Window_stack[Windows_open-1].Palette_button_list -GFX2_GLOBAL T_Scroller_button * Window_stack_scroller_button_list[8]; /// List of sliders (scrollers) in the topmost window. -#define Window_scroller_button_list Window_stack_scroller_button_list[Windows_open-1] +#define Window_scroller_button_list Window_stack[Windows_open-1].Scroller_button_list -GFX2_GLOBAL T_Special_button * Window_stack_special_button_list[8]; /// List of special buttons in the topmost window. -#define Window_special_button_list Window_stack_special_button_list[Windows_open-1] +#define Window_special_button_list Window_stack[Windows_open-1].Special_button_list -GFX2_GLOBAL T_Dropdown_button * Window_stack_dropdown_button_list[8]; /// List of dropdown buttons in the topmost window. -#define Window_dropdown_button_list Window_stack_dropdown_button_list[Windows_open-1] +#define Window_dropdown_button_list Window_stack[Windows_open-1].Dropdown_button_list -GFX2_GLOBAL T_List_button * Window_stack_list_button_list[8]; /// List of list buttons in the topmost window. -#define Window_list_button_list Window_stack_list_button_list[Windows_open-1] +#define Window_list_button_list Window_stack[Windows_open-1].List_button_list - - -GFX2_GLOBAL int Window_stack_attribute1[8]; /// /// The function ::Window_clicked_button() set this to ::LEFT_SIDE or ::RIGHT_SIDE /// after a button is activated through left or right mouse click. -#define Window_attribute1 Window_stack_attribute1[Windows_open-1] +#define Window_attribute1 Window_stack[Windows_open-1].Attribute1 -GFX2_GLOBAL int Window_stack_attribute2[8]; /// /// The function ::Window_clicked_button() set this to return extra information: /// - When a scroller was clicked: the scroller position (0-n) /// - When a palette was clicked: the color index (0-255) /// - When a dropdown was used: the selected item's number T_Dropdown_choice::Number -#define Window_attribute2 Window_stack_attribute2[Windows_open-1] - +#define Window_attribute2 Window_stack[Windows_open-1].Attribute2 +#define Window_draggable Window_stack[Windows_open-1].Draggable /// Definition of the menu (toolbox) @@ -587,6 +581,7 @@ GFX2_GLOBAL struct word Height; ///< Button's active heigth byte Pressed; ///< Button is currently pressed byte Shape; ///< Shape, listed in enum ::BUTTON_SHAPES + char Icon; ///< Which icon to display: Either the one from the toolbar (-1) or one of ::MENU_SPRITE // Triggers on mouse/keyboard Func_action Left_action; ///< Action triggered by a left mouseclick on the button @@ -765,6 +760,8 @@ GFX2_GLOBAL long Gradient_bounds_range; GFX2_GLOBAL long Gradient_total_range; /// Amount of randomness to use in gradient (1-256+) GFX2_GLOBAL long Gradient_random_factor; +/// Gradient speed of cycling (0-64) +GFX2_GLOBAL byte Gradient_speed; /// Pointer to a gradient function, depending on the selected method. GFX2_GLOBAL Func_gradient Gradient_function; /// @@ -772,10 +769,10 @@ GFX2_GLOBAL Func_gradient Gradient_function; /// either ::Pixel (if the gradient must be drawn on menus only) /// or ::Display_pixel (if the gradient must be drawn on the image) GFX2_GLOBAL Func_pixel Gradient_pixel; -/// Settings for all gradients -GFX2_GLOBAL T_Gradient_array Gradient_array[16]; /// Index in ::Gradient_array of the currently selected gradient. GFX2_GLOBAL byte Current_gradient; +/// Boolean, true when the color cycling is active. +GFX2_GLOBAL byte Cycling_mode; // -- Airbrush data @@ -823,6 +820,9 @@ GFX2_GLOBAL byte * Menu_font; /// Pointer to the current active skin. GFX2_GLOBAL T_Gui_skin * Gfx; +/// Pointer to the current active skin. +GFX2_GLOBAL T_Paintbrush Paintbrush[NB_PAINTBRUSH_SPRITES]; + // -- Help data /// Index of the ::Help_section shown by the Help screen. @@ -894,6 +894,7 @@ GFX2_GLOBAL T_Brush_template Brush_container[BRUSH_CONTAINER_COLUMNS*BRUSH_CONTA CURSOR_SHAPE_XOR_TARGET , // Stretch brush CURSOR_SHAPE_TARGET , // Distort brush CURSOR_SHAPE_XOR_TARGET , // Gradient-filled rectangle + CURSOR_SHAPE_COLORPICKER , // Colorpick on right mouse button }; #else /// ::Cursor_shape to use for each operation. @@ -950,34 +951,83 @@ GFX2_GLOBAL SDL_Joystick* Joystick; /// It was chosen to not conflict with any SDL key number. #define KEY_JOYBUTTON (SDLK_LAST+4) -/// Button definitions for the gp2x -#define GP2X_BUTTON_UP (0) -#define GP2X_BUTTON_DOWN (4) -#define GP2X_BUTTON_LEFT (2) -#define GP2X_BUTTON_RIGHT (6) -#define GP2X_BUTTON_UPLEFT (1) -#define GP2X_BUTTON_UPRIGHT (7) -#define GP2X_BUTTON_DOWNLEFT (3) -#define GP2X_BUTTON_DOWNRIGHT (5) -#define GP2X_BUTTON_CLICK (18) -#define GP2X_BUTTON_A (12) -#define GP2X_BUTTON_B (13) -#define GP2X_BUTTON_Y (14) -#define GP2X_BUTTON_X (15) -#define GP2X_BUTTON_L (10) -#define GP2X_BUTTON_R (11) -#define GP2X_BUTTON_START (8) -#define GP2X_BUTTON_SELECT (9) -#define GP2X_BUTTON_VOLUP (16) -#define GP2X_BUTTON_VOLDOWN (17) +/// The joystick axis are {X,Y} - on all platforms so far. +/// If there is ever a platform where they are reversed, put +/// these lines in each platform "case" below. +#define JOYSTICK_AXIS_X (0) +#define JOYSTICK_AXIS_Y (1) -#ifdef __gp2x__ - #define KEY_ESC (KEY_JOYBUTTON+GP2X_BUTTON_X) +#ifdef __GP2X__ + + #define JOYSTICK_THRESHOLD (4096) + + /// Button definitions for the gp2x + #define JOY_BUTTON_UP (0) + #define JOY_BUTTON_DOWN (4) + #define JOY_BUTTON_LEFT (2) + #define JOY_BUTTON_RIGHT (6) + #define JOY_BUTTON_UPLEFT (1) + #define JOY_BUTTON_UPRIGHT (7) + #define JOY_BUTTON_DOWNLEFT (3) + #define JOY_BUTTON_DOWNRIGHT (5) + #define JOY_BUTTON_CLICK (18) + #define JOY_BUTTON_A (12) + #define JOY_BUTTON_B (13) + #define JOY_BUTTON_Y (14) + #define JOY_BUTTON_X (15) + #define JOY_BUTTON_L (10) + #define JOY_BUTTON_R (11) + #define JOY_BUTTON_START (8) + #define JOY_BUTTON_SELECT (9) + #define JOY_BUTTON_VOLUP (16) + #define JOY_BUTTON_VOLDOWN (17) + + #define KEY_ESC (KEY_JOYBUTTON+JOY_BUTTON_X) +#elif defined(__WIZ__) + /// Button definitions for the Wiz + #define JOY_BUTTON_UP (0) + #define JOY_BUTTON_DOWN (4) + #define JOY_BUTTON_LEFT (2) + #define JOY_BUTTON_RIGHT (6) + #define JOY_BUTTON_UPLEFT (1) + #define JOY_BUTTON_UPRIGHT (7) + #define JOY_BUTTON_DOWNLEFT (3) + #define JOY_BUTTON_DOWNRIGHT (5) + #define JOY_BUTTON_L (10) + #define JOY_BUTTON_R (11) + #define JOY_BUTTON_A (12) + #define JOY_BUTTON_B (13) + #define JOY_BUTTON_X (14) + #define JOY_BUTTON_Y (15) + #define JOY_BUTTON_MENU (8) + #define JOY_BUTTON_SELECT (9) + #define JOY_BUTTON_VOLUP (16) + #define JOY_BUTTON_VOLDOWN (17) + + #define KEY_ESC (KEY_JOYBUTTON+JOY_BUTTON_X) +#elif defined (__CAANOO__) + + #define JOYSTICK_THRESHOLD (4096) + + /// Button definitions for the Caanoo + #define JOY_BUTTON_A (0) + #define JOY_BUTTON_X (1) + #define JOY_BUTTON_B (2) + #define JOY_BUTTON_Y (3) + #define JOY_BUTTON_L (4) + #define JOY_BUTTON_R (5) + #define JOY_BUTTON_HOME (6) + #define JOY_BUTTON_HOLD (7) + #define JOY_BUTTON_I (8) + #define JOY_BUTTON_II (9) + #define JOY_BUTTON_JOY (10) + + #define KEY_ESC (KEY_JOYBUTTON+JOY_BUTTON_HOME) #else /// /// This is the key identifier for ESC. When hard-coding keyboard shortcuts /// for buttons, etc. we use this instead of SDLK_ESCAPE, - /// so the GP2X port can get a joybutton equivalent of it. + /// so the console ports can get a joybutton equivalent of it. #define KEY_ESC SDLK_ESCAPE #endif diff --git a/src/graph.c b/src/graph.c index c393ebc0..d2d09ae4 100644 --- a/src/graph.c +++ b/src/graph.c @@ -48,12 +48,13 @@ #include "pxquad.h" #include "windows.h" #include "input.h" +#include "brush.h" #ifdef __VBCC__ #define __attribute__(x) #endif -#if defined(__VBCC__)||defined(__GP2X__) +#if defined(__VBCC__) || defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) #define M_PI 3.141592653589793238462643 #endif @@ -522,6 +523,8 @@ try_again: Menu_factor_Y=1; break; default: // Stay below some reasonable size + if (factor>Max(Pixel_width,Pixel_height)) + factor/=Max(Pixel_width,Pixel_height); Menu_factor_X=Min(factor,abs(Config.Ratio)); Menu_factor_Y=Min(factor,abs(Config.Ratio)); } @@ -617,7 +620,8 @@ void Resize_image(word chosen_width,word chosen_height) // |B| | C = Nouvelle image // +-+-+ - if (Backup_with_new_dimensions(1,Main_backups->Pages->Nb_layers,chosen_width,chosen_height)) + Upload_infos_page_main(Main_backups->Pages); + if (Backup_with_new_dimensions(chosen_width,chosen_height)) { // La nouvelle page a pu être allouée, elle est pour l'instant pleine de // 0s. Elle fait Main_image_width de large. @@ -672,13 +676,16 @@ void Remap_spare(void) // ne seront pas utilisées par Remap_general_lowlevel. for (color=0;color<=255;color++) if (used[color]) - used[color]=Best_color(Spare_palette[color].R,Spare_palette[color].G,Spare_palette[color].B); + used[color]=Best_color_perceptual(Spare_palette[color].R,Spare_palette[color].G,Spare_palette[color].B); // Maintenant qu'on a une super table de conversion qui n'a que le nom // qui craint un peu, on peut faire l'échange dans la brosse de toutes les // teintes. for (layer=0; layerPages->Nb_layers; layer++) - Remap_general_lowlevel(used,Spare_backups->Pages->Image[layer],Spare_image_width,Spare_image_height,Spare_image_width); + Remap_general_lowlevel(used,Spare_backups->Pages->Image[layer],Spare_backups->Pages->Image[layer],Spare_image_width,Spare_image_height,Spare_image_width); + + // Change transparent color index + Spare_backups->Pages->Transparent_color=used[Spare_backups->Pages->Transparent_color]; } @@ -687,43 +694,89 @@ void Get_colors_from_brush(void) { short x_pos; // Variable de balayage de la brosse short y_pos; // Variable de balayage de la brosse - byte used[256]; // Tableau de booléens "La couleur est utilisée" + byte brush_used[256]; // Tableau de booléens "La couleur est utilisée" + dword usage[256]; int color; + int image_color; - if (Confirmation_box("Modify current palette ?")) + //if (Confirmation_box("Modify current palette ?")) + + // Backup with unchanged layers, only palette is modified + Backup_layers(0); + + // Init array of new colors + for (color=0;color<=255;color++) + brush_used[color]=0; + + // Tag used colors + for (y_pos=0;y_pos= Permanent_draw_next_refresh) { Permanent_draw_next_refresh = now+100; diff --git a/src/help.c b/src/help.c index 9fcf976e..7ce41b18 100644 --- a/src/help.c +++ b/src/help.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Peter Gordon Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet @@ -31,6 +32,10 @@ #include #elif defined (__linux__) #include +#elif defined (__MINT__) + #include + #include + #include #endif #include "const.h" @@ -92,7 +97,7 @@ void Redefine_control(word *shortcut, int x_pos, int y_pos) Display_cursor(); while (1) { - while(!Get_input())SDL_Delay(20); + Get_input(20); if (Key==KEY_ESC) return; if (Key!=0) @@ -231,22 +236,102 @@ void Window_set_shortcut(int action_id) Display_cursor(); } -// -- Menu d'aide ----------------------------------------------------------- - -void Display_help(void) +/// +/// Print a line with the 'help' (6x8) font. +short Print_help(short x_pos, short y_pos, const char *line, char line_type, short link_position, short link_size) { + short width; // Largeur physique d'une ligne de texte short x; // Indices d'affichage d'un caractère short y; short x_position; // Parcours de remplissage du buffer de ligne - short line_index; // 0-15 (16 lignes de textes) short char_index; // Parcours des caractères d'une ligne - short start_line=Help_position; + byte * char_pixel; short repeat_menu_x_factor; short repeat_menu_y_factor; short real_x_pos; short real_y_pos; - byte * char_pixel; - short width; // Largeur physique d'une ligne de texte + + real_x_pos=ToWinX(x_pos); + real_y_pos=ToWinY(y_pos); + + // Calcul de la taille + width=strlen(line); + // Les lignes de titres prennent plus de place + if (line_type == 'T' || line_type == '-') + width = width*2; + + // Pour chaque ligne dans la fenêtre: + for (y=0;y<8;y++) + { + x_position=0; + // On crée une nouvelle ligne à splotcher + for (char_index=0;char_index'_' || line[char_index/2]<' ') + char_pixel=&(Gfx->Help_font_norm['!'][0][0]); // Caractère pas géré + else if (char_index & 1) + char_pixel=&(Gfx->Help_font_t2[(unsigned char)(line[char_index/2])-' '][0][0]); + else + char_pixel=&(Gfx->Help_font_t1[(unsigned char)(line[char_index/2])-' '][0][0]); + } + else if (line_type=='-') + { + if (line[char_index/2]>'_' || line[char_index/2]<' ') + char_pixel=&(Gfx->Help_font_norm['!'][0][0]); // Caractère pas géré + else if (char_index & 1) + char_pixel=&(Gfx->Help_font_t4[(unsigned char)(line[char_index/2])-' '][0][0]); + else + char_pixel=&(Gfx->Help_font_t3[(unsigned char)(line[char_index/2])-' '][0][0]); + } + else if (line_type=='S') + char_pixel=&(Gfx->Bold_font[(unsigned char)(line[char_index])][0][0]); + else if (line_type=='N' || line_type=='K') + char_pixel=&(Gfx->Help_font_norm[(unsigned char)(line[char_index])][0][0]); + else + char_pixel=&(Gfx->Help_font_norm['!'][0][0]); // Un garde-fou en cas de probleme + + for (x=0;x<6;x++) + for (repeat_menu_x_factor=0;repeat_menu_x_factor=link_position + && char_index<(link_position+link_size)) + { + if (color == MC_Light) + color=MC_White; + else if (color == MC_Dark) + color=MC_Light; + else if (y<7) + color=MC_Dark; + } + Horizontal_line_buffer[x_position++]=color; + while (repetition--) + Horizontal_line_buffer[x_position++]=color; + } + } + // On la splotche + for (repeat_menu_y_factor=0;repeat_menu_y_factor= Help_section[Current_help_section].Length) { - Block (real_x_pos, - real_y_pos, - 44*6*Menu_factor_X, + Window_rectangle (x_pos, + y_pos + line_index*8, + 44*6, // 44 = Nb max de char (+1 pour éviter les plantages en mode X // causés par une largeur = 0) - (Menu_factor_Y<<3) * (16 - line_index), + (16 - line_index)*8, MC_Black); break; } @@ -307,83 +390,16 @@ void Display_help(void) line = buffer; } - // Calcul de la taille - width=strlen(line); - // Les lignes de titres prennent plus de place - if (line_type == 'T' || line_type == '-') - width = width*2; - - // Pour chaque ligne dans la fenêtre: - for (y=0;y<8;y++) - { - x_position=0; - // On crée une nouvelle ligne à splotcher - for (char_index=0;char_index'_' || line[char_index/2]<' ') - char_pixel=&(Gfx->Help_font_norm['!'][0][0]); // Caractère pas géré - else if (char_index & 1) - char_pixel=&(Gfx->Help_font_t2[(unsigned char)(line[char_index/2])-' '][0][0]); - else - char_pixel=&(Gfx->Help_font_t1[(unsigned char)(line[char_index/2])-' '][0][0]); - } - else if (line_type=='-') - { - if (line[char_index/2]>'_' || line[char_index/2]<' ') - char_pixel=&(Gfx->Help_font_norm['!'][0][0]); // Caractère pas géré - else if (char_index & 1) - char_pixel=&(Gfx->Help_font_t4[(unsigned char)(line[char_index/2])-' '][0][0]); - else - char_pixel=&(Gfx->Help_font_t3[(unsigned char)(line[char_index/2])-' '][0][0]); - } - else if (line_type=='S') - char_pixel=&(Gfx->Bold_font[(unsigned char)(line[char_index])][0][0]); - else if (line_type=='N' || line_type=='K') - char_pixel=&(Gfx->Help_font_norm[(unsigned char)(line[char_index])][0][0]); - else - char_pixel=&(Gfx->Help_font_norm['!'][0][0]); // Un garde-fou en cas de probleme - - for (x=0;x<6;x++) - for (repeat_menu_x_factor=0;repeat_menu_x_factor=link_position - && char_index<(link_position+link_size)) - { - if (color == MC_Light) - color=MC_White; - else if (color == MC_Dark) - color=MC_Light; - else if (y<7) - color=MC_Dark; - } - Horizontal_line_buffer[x_position++]=color; - while (repetition--) - Horizontal_line_buffer[x_position++]=color; - } - } - // On la splotche - for (repeat_menu_y_factor=0;repeat_menu_y_factorPosition=Help_position; - Compute_slider_cursor_height(scroller); + Compute_slider_cursor_length(scroller); Window_draw_slider(scroller); Display_help(); Display_cursor(); @@ -510,7 +526,7 @@ void Window_help(int section, const char *sub_section) nb_lines=Help_section[Current_help_section].Length; scroller->Position=0; scroller->Nb_elements=nb_lines; - Compute_slider_cursor_height(scroller); + Compute_slider_cursor_length(scroller); Window_draw_slider(scroller); } else @@ -627,7 +643,51 @@ void Button_Stats(void) Print_in_window(10,35,"Build options:",STATS_TITLE_COLOR,MC_Black); Print_in_window(146,35,TrueType_is_supported()?"TTF fonts":"no TTF fonts",STATS_DATA_COLOR,MC_Black); +#if defined (__MINT__) + // Affichage de la mémoire restante + Print_in_window(10,43,"Free memory: ",STATS_TITLE_COLOR,MC_Black); + freeRam=0; + char helpBuf[64]; + + unsigned long STRAM,TTRAM; + Atari_Memory_free(&STRAM,&TTRAM); + freeRam=STRAM+TTRAM; + buffer[0]='\0'; + + if(STRAM > (100*1024*1024)) + sprintf(helpBuf,"ST:%u Mb ",(unsigned int)(STRAM/(1024*1024))); + else if(freeRam > 100*1024) + sprintf(helpBuf,"ST:%u Kb ",(unsigned int)(STRAM/1024)); + else + sprintf(helpBuf,"ST:%u b ",(unsigned int)STRAM); + + strncat(buffer,helpBuf,sizeof(char)*37); + + if(TTRAM > (100ULL*1024*1024*1024)) + sprintf(helpBuf,"TT:%u Gb",(unsigned int)(TTRAM/(1024*1024*1024))); + else if(TTRAM > (100*1024*1024)) + sprintf(helpBuf,"TT:%u Mb",(unsigned int)(TTRAM/(1024*1024))); + else if(freeRam > 100*1024) + sprintf(helpBuf,"TT:%u Kb",(unsigned int)(TTRAM/1024)); + else + sprintf(helpBuf,"TT:%u b",(unsigned int)TTRAM); + + strncat(buffer,helpBuf,sizeof(char)*37); + + if(freeRam > (100ULL*1024*1024*1024)) + sprintf(helpBuf,"(%u Gb)",(unsigned int)(freeRam/(1024*1024*1024))); + else if(freeRam > (100*1024*1024)) + sprintf(helpBuf,"(%u Mb)",(unsigned int)(freeRam/(1024*1024))); + else if(freeRam > 100*1024) + sprintf(helpBuf,"(%u Kb)",(unsigned int)(freeRam/1024)); + else + sprintf(helpBuf,"(%u b)",(unsigned int)freeRam); + strncat(buffer,helpBuf,sizeof(char)*37); + + Print_in_window(18,51,buffer,STATS_DATA_COLOR,MC_Black); + +#else // Affichage de la mémoire restante Print_in_window(10,51,"Free memory: ",STATS_TITLE_COLOR,MC_Black); @@ -641,8 +701,12 @@ void Button_Stats(void) sprintf(buffer,"%u Kilobytes",(unsigned int)(freeRam/1024)); else sprintf(buffer,"%u bytes",(unsigned int)freeRam); + Print_in_window(114,51,buffer,STATS_DATA_COLOR,MC_Black); + #endif + + // Used memory Print_in_window(10,59,"Used memory pages: ",STATS_TITLE_COLOR,MC_Black); if(Stats_pages_memory > (100LL*1024*1024*1024)) @@ -670,6 +734,14 @@ void Button_Stats(void) statfs(Main_current_directory,&disk_info); mem_size=(qword) disk_info.f_bfree * (qword) disk_info.f_bsize; } +#elif defined (__MINT__) + _DISKINFO drvInfo; + mem_size=0; + Dfree(&drvInfo,0); + //number of free clusters*sectors per cluster*bytes per sector; + // reports current drive + mem_size=drvInfo.b_free*drvInfo.b_clsiz*drvInfo.b_secsiz; + #else // Free disk space is only for shows. Other platforms can display 0. #warning "Missing code for your platform !!! Check and correct please :)" diff --git a/src/help.h b/src/help.h index 14c866d0..aca208bd 100644 --- a/src/help.h +++ b/src/help.h @@ -46,5 +46,17 @@ void Button_Stats(void); */ void Window_help(int section, const char * sub_section); +/// Opens a window where you can change a shortcut key(s). +void Window_set_shortcut(int action_id); + +/// +/// Print a line with the 'help' (6x8) font. +short Print_help(short x_pos, short y_pos, const char *line, char line_type, short link_position, short link_size); + +// Nom de la touche actuallement assignée à un raccourci d'après son numéro +// de type 0x100+BOUTON_* ou SPECIAL_* +const char * Keyboard_shortcut_value(word shortcut_number); + + #endif diff --git a/src/helpfile.h b/src/helpfile.h index 5e246059..fdeb8a8f 100644 --- a/src/helpfile.h +++ b/src/helpfile.h @@ -62,7 +62,11 @@ static const T_Help_table helptable_about[] = HELP_BOLD (" \"Dragon's Layers\" Edition") HELP_BOLD (" THE ULTIMATE MULTI-RESOLUTION GFX EDITOR") HELP_TEXT (" http://grafx2.googlecode.com") +#if defined(__MINT__) + HELP_TEXT (" atari build ") +#else HELP_TEXT ("") +#endif HELP_TEXT ("Copyright 2007-2010, the Grafx2 project team") HELP_TEXT (" Copyright 1996-2001, SUNSET DESIGN") }; @@ -156,6 +160,7 @@ static const T_Help_table helptable_help[] = HELP_LINK ("Filled polyform: %s", 0x200+BUTTON_POLYFILL) HELP_LINK ("Gradient rectangle: %s", 0x100+BUTTON_GRADRECT) HELP_LINK ("Gradation menu: %s", 0x200+BUTTON_GRADRECT) + HELP_LINK ("Toggle color cycling:%s", SPECIAL_CYCLE_MODE) HELP_LINK ("Spheres: %s", 0x100+BUTTON_SPHERES) HELP_LINK ("Gradient ellipses: %s", 0x200+BUTTON_SPHERES) HELP_LINK ("Adjust picture: %s", 0x100+BUTTON_ADJUST) @@ -204,6 +209,10 @@ static const T_Help_table helptable_help[] = HELP_LINK ("Distort brush: %s", SPECIAL_DISTORT) HELP_LINK ("Outline brush: %s", SPECIAL_OUTLINE) HELP_LINK ("Nibble brush: %s", SPECIAL_NIBBLE) + HELP_LINK ("Double brush size: %s", SPECIAL_BRUSH_DOUBLE) + HELP_LINK ("Halve brush size: %s", SPECIAL_BRUSH_HALVE) + HELP_LINK ("Double brush width: %s", SPECIAL_BRUSH_DOUBLE_WIDTH) + HELP_LINK ("Double brush height: %s", SPECIAL_BRUSH_DOUBLE_HEIGHT) HELP_LINK ("Get brush colors: %s", SPECIAL_GET_BRUSH_COLORS) HELP_LINK ("Recolorize brush: %s", SPECIAL_RECOLORIZE_BRUSH) HELP_LINK ("Rotate brush: %s", SPECIAL_ROTATE_ANY_ANGLE) @@ -228,6 +237,18 @@ static const T_Help_table helptable_help[] = HELP_LINK (" 18:1 %s", SPECIAL_ZOOM_18) HELP_LINK (" 20:1 %s", SPECIAL_ZOOM_20) HELP_LINK ("Brush effects menu: %s", 0x100+BUTTON_BRUSH_EFFECTS) + HELP_LINK ("Brush factory: %s", 0x200+BUTTON_BRUSH_EFFECTS) + HELP_LINK ("Repeat last script: %s", SPECIAL_REPEAT_SCRIPT) + HELP_LINK ("Run script #1: %s", SPECIAL_RUN_SCRIPT_1) + HELP_LINK ("Run script #2: %s", SPECIAL_RUN_SCRIPT_2) + HELP_LINK ("Run script #3: %s", SPECIAL_RUN_SCRIPT_3) + HELP_LINK ("Run script #4: %s", SPECIAL_RUN_SCRIPT_4) + HELP_LINK ("Run script #5: %s", SPECIAL_RUN_SCRIPT_5) + HELP_LINK ("Run script #6: %s", SPECIAL_RUN_SCRIPT_6) + HELP_LINK ("Run script #7: %s", SPECIAL_RUN_SCRIPT_7) + HELP_LINK ("Run script #8: %s", SPECIAL_RUN_SCRIPT_8) + HELP_LINK ("Run script #9: %s", SPECIAL_RUN_SCRIPT_9) + HELP_LINK ("Run script #10: %s", SPECIAL_RUN_SCRIPT_10) HELP_LINK ("Text: %s", 0x100+BUTTON_TEXT) HELP_LINK ("Resolution menu: %s", 0x100+BUTTON_RESOL) HELP_LINK ("Safety resolution: %s", 0x200+BUTTON_RESOL) @@ -424,6 +445,14 @@ static const T_Help_table helptable_credits[] = HELP_TEXT ("") HELP_TEXT (" Luc Schrijvers (Begasus)") HELP_TEXT ("") + HELP_BOLD (" WIZ & CAANOO PORT") + HELP_TEXT ("") + HELP_TEXT (" Alexander Filyanov (PheeL)") + HELP_TEXT ("") + HELP_BOLD (" ATARI PORT") + HELP_TEXT ("") + HELP_TEXT (" Pawel Goralski (Saulot)") + HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT (" ... made it work on your favourite toaster") HELP_TEXT ("") @@ -432,17 +461,18 @@ static const T_Help_table helptable_credits[] = //HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") HELP_TEXT (" anibiqme blumunkee BDCIron ") HELP_TEXT (" Ced DawnBringer El Topo ") - HELP_TEXT (" falenblood fano fogbot121 ") - HELP_TEXT (" Frost Grimmy grknsngn ") + HELP_TEXT (" falenblood fanickbux fano ") + HELP_TEXT (" fogbot121 Frost Grimmy ") HELP_TEXT (" Gürkan Sengün Hatch HoraK-FDF ") HELP_TEXT (" iLKke Iw2evk Jamon ") HELP_TEXT (" keito kusma Lord Graga ") HELP_TEXT (" Lorenzo Gatti MagerValp maymunbeyin ") HELP_TEXT (" mind MooZ Pasi Kallinen ") - HELP_TEXT (" the Peach petter richienyhus ") - HELP_TEXT (" tape.wyrm TeeEmCee tempest ") + HELP_TEXT (" the Peach petter PheeL ") + HELP_TEXT (" richienyhus sm4tik spratek ") + HELP_TEXT (" tape.yrm TeeEmCee tempest ") HELP_TEXT (" Timo Kurrpa titus^Rab Tobé ") - HELP_TEXT (" yakumo9275 00ai99") + HELP_TEXT (" yakumo2975 00ai99") HELP_TEXT ("") HELP_TEXT (" ... posted the annoying bug reports.") HELP_TEXT ("") @@ -631,9 +661,25 @@ static const T_Help_table helptable_paintbrush[] = HELP_TEXT ("brush size by using the keys:") HELP_LINK ("Reduce : %s", SPECIAL_SMALLER_PAINTBRUSH) HELP_LINK ("Increase : %s", SPECIAL_BIGGER_PAINTBRUSH) - HELP_TEXT ("The last 3 paintbrushes in the menu belong") - HELP_TEXT ("to the \"miscellaneous\" family and their size") - HELP_TEXT ("cannot be modified.") + HELP_TEXT ("") + HELP_TEXT ("Other brushes are bitmaps, their size can't") + HELP_TEXT ("be adjusted.") + HELP_TEXT ("") + HELP_TEXT ("Click with left mouse button to choose a ") + HELP_TEXT ("paintbrush, and right mouse button to store") + HELP_TEXT ("your current brush in the slot. If your") + HELP_TEXT ("current brush is a grabbed brush, it will") + HELP_TEXT ("store a monochrome version of it, maximum") + HELP_TEXT ("15x15. (See below 'Brush container' to store") + HELP_TEXT ("backups of a big brush)") + HELP_TEXT ("The stored brushes are saved when you exit") + HELP_TEXT ("the program.") + HELP_TEXT ("") + HELP_TEXT ("The 'Preset' button allows you to pick a") + HELP_TEXT ("brush from any family. It's useful if you've") + HELP_TEXT ("overwritten all normal slots with brushes") + HELP_TEXT ("that you use more often.") + HELP_TEXT ("") HELP_TEXT ("") HELP_BOLD ("BRUSH CONTAINER") HELP_TEXT ("") @@ -1123,6 +1169,27 @@ static const T_Help_table helptable_grad_rect[] = HELP_TEXT ("- Index scroller: Defines the current") HELP_TEXT ("gradation among a set of 16 that will be") HELP_TEXT ("memorised.") + HELP_TEXT ("") + HELP_BOLD ("COLOR CYCLING") + HELP_TEXT ("") + HELP_TEXT ("These options allow you to use animation of") + HELP_TEXT ("colors: Grafx2 will shift palette entries") + HELP_TEXT ("at real-time. Note that only the LBM file") + HELP_TEXT ("format can record these settings, and very") + HELP_TEXT ("few image viewers will play it back.") + HELP_TEXT ("") + HELP_TEXT ("- Cycling: Activates or desactivates the") + HELP_TEXT ("cycling of colors when you're in the editor.") + HELP_LINK ("Key: %s", SPECIAL_CYCLE_MODE) + HELP_TEXT ("") + HELP_TEXT ("- Speed: Sets the speed for the cycling of") + HELP_TEXT ("this range. Zero means this range doesn't") + HELP_TEXT ("cycle. With 1, the range shifts 0.2856 times") + HELP_TEXT ("per second; at speed 64 it's 18.28 times") + HELP_TEXT ("per second. The program activates cycling") + HELP_TEXT ("while you hold the speed slider, so you can") + HELP_TEXT ("preview the speed.") + HELP_TEXT ("") }; static const T_Help_table helptable_spheres[] = { @@ -1253,15 +1320,17 @@ static const T_Help_table helptable_brush_fx[] = HELP_TEXT ("point at coordinates inferior to the ones of") HELP_TEXT ("the first point, the brush will be inverted.") HELP_TEXT ("Meanwhile, you can press the following keys") - HELP_TEXT ("whose effects are: 'D' : double the") - HELP_TEXT ("brush in X and Y 'H' : reduce the") - HELP_TEXT ("brush by half in X and Y 'X' : double") - HELP_TEXT ("the brush in X 'Shift+X': reduce the brush") - HELP_TEXT ("by half in X 'Y' : double the brush") - HELP_TEXT ("in Y 'Shift+Y': reduce the brush by half") - HELP_TEXT ("in Y 'N' : restore the normal size of") - HELP_TEXT ("the brush (can be useful") - HELP_TEXT ("because it's the only way for cancelling)") + HELP_TEXT ("whose effects are:") + HELP_TEXT (" 'D' : Double the brush") + HELP_TEXT (" 'H' : Reduce the brush by half") + HELP_TEXT (" 'X' : Double the brush in X") + HELP_TEXT (" 'Shift+X': Reduce the brush by half in X") + HELP_TEXT (" 'Y' : Double the brush in Y") + HELP_TEXT (" 'Shift+Y': Reduce the brush by half in Y") + HELP_TEXT (" 'N' : Restore the normal size of the") + HELP_TEXT (" brush (can be useful because") + HELP_TEXT (" it's the only way for") + HELP_TEXT (" cancelling)") HELP_TEXT ("") HELP_LINK ("- Distort: (Key:%s)",SPECIAL_DISTORT) HELP_TEXT ("Triggers an interactive operation") @@ -1312,6 +1381,8 @@ static const T_Help_table helptable_brush_fx[] = HELP_TEXT ("") HELP_TITLE("BRUSH FACTORY") HELP_TEXT ("") + HELP_LINK ("(Key:%s)",0x200+BUTTON_BRUSH_EFFECTS) + HELP_TEXT ("") HELP_TEXT ("This menu allows you to run scripts. Scripts") HELP_TEXT ("are written in the Lua language, and allow") HELP_TEXT ("you to modify the brush (hence the name") @@ -1331,6 +1402,8 @@ static const T_Help_table helptable_brush_fx[] = HELP_TEXT ("time you open the window. Scripts are loaded") HELP_TEXT ("from disk when you run them.") HELP_TEXT ("") + HELP_LINK ("- Repeat last script: %s", SPECIAL_REPEAT_SCRIPT) + HELP_TEXT ("") }; static const T_Help_table helptable_effects[] = { @@ -2273,6 +2346,13 @@ static const T_Help_table helptable_settings_details[] = HELP_TEXT ("variants of your original palette, resulting") HELP_TEXT ("in a pretty grid !") HELP_TEXT ("") + HELP_BOLD (" Sync views") + HELP_TEXT ("When this mode is active, scrolling the view") + HELP_TEXT ("(and the magnifier view) affects both the") + HELP_TEXT ("main image and the spare page - as long as") + HELP_TEXT ("they have the same dimensions.") + HELP_TEXT ("") + HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("INPUT") HELP_TEXT ("") @@ -2323,6 +2403,14 @@ static const T_Help_table helptable_settings_details[] = HELP_TEXT ("GrafX2 to recognize them as a combo.") HELP_TEXT ("") HELP_TEXT ("") + HELP_BOLD (" Swap buttons") + HELP_TEXT ("This setting determines which key inverts") + HELP_TEXT ("the mouse buttons when it's held : A left") + HELP_TEXT ("click is then interpreted as a right-click.") + HELP_TEXT ("It's especially useful for one-button") + HELP_TEXT ("controllers, such as touchscreens and") + HELP_TEXT ("tablets.") + HELP_TEXT ("") HELP_TITLE("EDITING") HELP_TEXT ("") HELP_TEXT ("") @@ -2359,7 +2447,14 @@ static const T_Help_table helptable_settings_details[] = HELP_TEXT ("window. (Set it to 'no' if you have a slow") HELP_TEXT ("computer or if you edit huge pictures)") HELP_TEXT ("") - HELP_TEXT ("") + HELP_BOLD (" Right click colorpick") + HELP_TEXT ("This enables a mode where the right mouse") + HELP_TEXT ("buttons acts as a color picker until") + HELP_TEXT ("it's released, and selects Foreground color.") + HELP_TEXT ("This mode prevents you from painting with") + HELP_TEXT ("Background color.") + HELP_TEXT ("This option is ignored when the Shade,") + HELP_TEXT ("Quick-shade, or Tiling mode is used.") }; static const T_Help_table helptable_clear[] = @@ -2474,16 +2569,28 @@ static const T_Help_table helptable_palette[] = HELP_TEXT ("- Gauges: Allow you to modify the") HELP_TEXT ("current selection.") HELP_TEXT ("") + HELP_TEXT ("- RGB or HSL above the gauges: Switches") + HELP_TEXT ("between RGB and HSL color spaces. In HSL") + HELP_TEXT ("mode, the three sliders allow you to set the") + HELP_TEXT ("Hue (tint), Saturation (from grayscale to") + HELP_TEXT ("pure color) and Lightness (from black to") + HELP_TEXT ("white).") + HELP_TEXT ("") + HELP_TEXT ("- numbers below the gauges: Allows you to") + HELP_TEXT ("type in a new color in hexadecimal RRGGBB") + HELP_TEXT ("or RGB: ie. to get blue, you can type either") + HELP_TEXT ("0000ff or 00f.") + HELP_TEXT ("") HELP_TEXT ("- \"+\" and \"-\": Allow you to lighten or") HELP_TEXT ("darken the current selection.") HELP_TEXT ("") - HELP_TEXT ("- Default: Restores the predifined GrafX2") + HELP_TEXT ("- Preset: Restores the predefined GrafX2") HELP_TEXT ("palette.") HELP_TEXT ("") HELP_TEXT ("- Gray: Transforms the current selection") HELP_TEXT ("into its gray-scaled equivalent.") HELP_TEXT ("") - HELP_TEXT ("- Negative: Transforms the current selection") + HELP_TEXT ("- Neg: Transforms the current selection") HELP_TEXT ("into its reverse video equivalent.") HELP_TEXT ("") HELP_TEXT ("- Invert: Swaps the colors of the current") @@ -2520,18 +2627,12 @@ static const T_Help_table helptable_palette[] = HELP_TEXT ("whole palette it will sort this range.") HELP_TEXT ("") HELP_TEXT ("- Used: Indicates the number of colors used") - HELP_TEXT ("in the picture.") + HELP_TEXT ("in the picture and opens a histogram screen.") HELP_TEXT ("") HELP_TEXT ("- Zap unused: Erases the unused colors with") HELP_TEXT ("copies of the current selection. (The") HELP_TEXT ("keyboard shortcut for this button is ).") HELP_TEXT ("") - HELP_TEXT ("- HSL: Switches between RGB and HSL color") - HELP_TEXT ("spaces. In HSL mode, the three sliders") - HELP_TEXT ("allow you to set the Hue (tint), Saturation") - HELP_TEXT ("(from grayscale to pure color) and") - HELP_TEXT ("Lightness (from black to white).") - HELP_TEXT ("") HELP_TEXT ("- Reduce: Allows you to reduce the palette") HELP_TEXT ("to the number of colors you want (and") HELP_TEXT ("modifies the picture).") diff --git a/src/hotkeys.c b/src/hotkeys.c index 46150eb7..302b5644 100644 --- a/src/hotkeys.c +++ b/src/hotkeys.c @@ -884,7 +884,16 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { "", true, SDLK_u, // U - 0}, + // Secondary shortcut is button I on the Caanoo, L on the Wiz, unset on others + #if defined (__CAANOO__) + (KEY_JOYBUTTON+JOY_BUTTON_I) + #elif defined (__WIZ__) + (KEY_JOYBUTTON+JOY_BUTTON_L) + #else + 0 + #endif + // -- + }, {103, "Redo", "Redo the last undone action.", @@ -892,7 +901,16 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { "", true, SDLK_u|MOD_SHIFT, // Shift + U - 0}, + // Secondary shortcut is button II on the Caanoo, R on the Wiz, unset on others + #if defined (__CAANOO__) + (KEY_JOYBUTTON+JOY_BUTTON_II) + #elif defined (__WIZ__) + (KEY_JOYBUTTON+JOY_BUTTON_R) + #else + 0 + #endif + // -- + }, {133, "Kill", "Kills the current page. It actually", @@ -924,7 +942,17 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { "confirmation is asked.", false, SDLK_q, // Q (A en AZERTY) - 0}, + // Secondary shortcut is button Home on the Caanoo, Menu on the Wiz, unset on others + #if defined (__CAANOO__) + (KEY_JOYBUTTON+JOY_BUTTON_HOME) + #elif defined (__WIZ__) + (KEY_JOYBUTTON+JOY_BUTTON_MENU) + #else + 0 + #endif + // -- + + }, {107, "Palette menu", "Opens a menu which allows you to", @@ -1478,13 +1506,149 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { SDLK_HOME|MOD_ALT, // Alt + Home 0}, {181, + "Brush factory", + "Opens a window where you can run a", + "Lua script.", + "", + true, + 0, // No shortcut + 0}, + {182, + "Repeat script", + "Re-run the last script selected", + "in the Brush factory window.", + "", + true, + 0, // No shortcut + 0}, + {183, + "Double brush size", + "Resizes the current user brush", + "by doubling width and height.", + "", + true, + SDLK_h|MOD_SHIFT, // Shift+H + 0}, + {184, + "Double brush width", + "Resizes the current user brush", + "by doubling its width.", + "", + true, + SDLK_x|MOD_SHIFT, // Shift+X + 0}, + {185, + "Double brush height", + "Resizes the current user brush", + "by doubling its height.", + "", + true, + SDLK_y|MOD_SHIFT, // Shift+Y + 0}, + {186, + "Halve brush size", + "Resizes the current user brush", + "by halving its width and height", + "", + true, + SDLK_h, // H + 0}, + {187, + "Run script #1", + "Runs a recorded Lua script.", + "", + "", + true, + 0, // No shortcut + 0}, + {188, + "Run script #2", + "Runs a recorded Lua script.", + "", + "", + true, + 0, // No shortcut + 0}, + {189, + "Run script #3", + "Runs a recorded Lua script.", + "", + "", + true, + 0, // No shortcut + 0}, + {190, + "Run script #4", + "Runs a recorded Lua script.", + "", + "", + true, + 0, // No shortcut + 0}, + {191, + "Run script #5", + "Runs a recorded Lua script.", + "", + "", + true, + 0, // No shortcut + 0}, + {192, + "Run script #6", + "Runs a recorded Lua script.", + "", + "", + true, + 0, // No shortcut + 0}, + {193, + "Run script #7", + "Runs a recorded Lua script.", + "", + "", + true, + 0, // No shortcut + 0}, + {194, + "Run script #8", + "Runs a recorded Lua script.", + "", + "", + true, + 0, // No shortcut + 0}, + {195, + "Run script #9", + "Runs a recorded Lua script.", + "", + "", + true, + 0, // No shortcut + 0}, + {196, + "Run script #10", + "Runs a recorded Lua script.", + "", + "", + true, + 0, // No shortcut + 0}, + {197, + "Toggle color cycling", + "Activates or desactivates color", + "cycling, if the current image has", + "cycling colors. (See gradient menu)", + true, + SDLK_BACKQUOTE|MOD_CTRL, // Ctrl + `~ + 0}, + {198, "Format checker", "Performs a format check on the", "current image.", "", true, 0, - 0}, + 0} }; word Ordering[NB_SHORTCUTS]= @@ -1670,6 +1834,23 @@ word Ordering[NB_SHORTCUTS]= 0x100+BUTTON_LAYER_UP, 0x100+BUTTON_LAYER_DOWN, 0x100+BUTTON_LAYER_MENU, + 0x200+BUTTON_BRUSH_EFFECTS, + SPECIAL_REPEAT_SCRIPT, + SPECIAL_BRUSH_DOUBLE, + SPECIAL_BRUSH_DOUBLE_WIDTH, + SPECIAL_BRUSH_DOUBLE_HEIGHT, + SPECIAL_BRUSH_HALVE, + SPECIAL_RUN_SCRIPT_1, + SPECIAL_RUN_SCRIPT_2, + SPECIAL_RUN_SCRIPT_3, + SPECIAL_RUN_SCRIPT_4, + SPECIAL_RUN_SCRIPT_5, + SPECIAL_RUN_SCRIPT_6, + SPECIAL_RUN_SCRIPT_7, + SPECIAL_RUN_SCRIPT_8, + SPECIAL_RUN_SCRIPT_9, + SPECIAL_RUN_SCRIPT_10, + SPECIAL_CYCLE_MODE, SPECIAL_FORMAT_CHECKER, SPECIAL_FORMAT_CHECKER_MENU, }; diff --git a/src/hotkeys.h b/src/hotkeys.h index 98ef7256..e6f97c63 100644 --- a/src/hotkeys.h +++ b/src/hotkeys.h @@ -33,6 +33,8 @@ #endif #include +#define NB_SHORTCUTS 199 ///< Number of actions that can have a key combination associated to it. + /*** Types definitions and structs ***/ typedef struct diff --git a/src/init.c b/src/init.c index e356572d..2ff75c27 100644 --- a/src/init.c +++ b/src/init.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Peter Gordon Copyright 2008 Yves Rizoud Copyright 2009 Franck Charlet @@ -50,6 +51,12 @@ #if defined(__WIN32__) #include // GetLogicalDrives(), GetDriveType(), DRIVE_* #endif +#ifndef __GP2X__ + #include +#endif +#if defined (__MINT__) + #include +#endif #ifdef GRAFX2_CATCHES_SIGNALS #include #endif @@ -76,6 +83,8 @@ #include "transform.h" #include "windows.h" #include "layers.h" +#include "special.h" +#include "buttons.h" char Gui_loading_error_message[512]; @@ -250,7 +259,6 @@ void Center_GUI_cursor(T_Gui_skin *gfx, byte *cursor_buffer, int cursor_number) byte Parse_skin(SDL_Surface * gui, T_Gui_skin *gfx) { - int index; int i,j; int cursor_x=0,cursor_y=0; byte color; @@ -274,6 +282,7 @@ byte Parse_skin(SDL_Surface * gui, T_Gui_skin *gfx) sprintf(Gui_loading_error_message, "Not a 256-color palette"); return 1; } + // Read the default palette Get_SDL_Palette(SDLPal, gfx->Default_palette); @@ -351,31 +360,51 @@ byte Parse_skin(SDL_Surface * gui, T_Gui_skin *gfx) // Menu if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "menu")) return 1; - if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Menu_block, Menu_bars[MENUBAR_TOOLS].Skin_width, Menu_bars[MENUBAR_TOOLS].Height,"menu",0)) + if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Menu_block[0], Menu_bars[MENUBAR_TOOLS].Skin_width, Menu_bars[MENUBAR_TOOLS].Height,"menu",0)) return 1; // Preview cursor_x += Menu_bars[MENUBAR_TOOLS].Skin_width; if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "preview")) return 1; - if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Preview, 173, 16, "logo", 0)) + if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Preview, 173, 16, "preview", 0)) return 1; cursor_y+= Menu_bars[MENUBAR_TOOLS].Height; // Layerbar if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "layer bar")) return 1; - if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Layerbar_block, Menu_bars[MENUBAR_LAYERS].Skin_width, Menu_bars[MENUBAR_LAYERS].Height,"layer bar",0)) + if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Layerbar_block[0], Menu_bars[MENUBAR_LAYERS].Skin_width, Menu_bars[MENUBAR_LAYERS].Height,"layer bar",0)) return 1; cursor_y+= Menu_bars[MENUBAR_LAYERS].Height; // Status bar if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "status bar")) return 1; - if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Statusbar_block, Menu_bars[MENUBAR_STATUS].Skin_width, Menu_bars[MENUBAR_STATUS].Height,"status bar",0)) + if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Statusbar_block[0], Menu_bars[MENUBAR_STATUS].Skin_width, Menu_bars[MENUBAR_STATUS].Height,"status bar",0)) return 1; cursor_y+= Menu_bars[MENUBAR_STATUS].Height; + // Menu (selected) + if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "selected menu")) + return 1; + if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Menu_block[1], Menu_bars[MENUBAR_TOOLS].Skin_width, Menu_bars[MENUBAR_TOOLS].Height,"selected menu",0)) + return 1; + cursor_y+= Menu_bars[MENUBAR_TOOLS].Height; + + // Layerbar (selected) + if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "selected layer bar")) + return 1; + if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Layerbar_block[1], Menu_bars[MENUBAR_LAYERS].Skin_width, Menu_bars[MENUBAR_LAYERS].Height,"selected layer bar",0)) + return 1; + cursor_y+= Menu_bars[MENUBAR_LAYERS].Height; + + // Status bar (selected) + if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "selected status bar")) + return 1; + if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Statusbar_block[1], Menu_bars[MENUBAR_STATUS].Skin_width, Menu_bars[MENUBAR_STATUS].Height,"selected status bar",0)) + return 1; + cursor_y+= Menu_bars[MENUBAR_STATUS].Height; // Effects for (i=0; iEffect_sprite[i], MENU_SPRITE_WIDTH, MENU_SPRITE_HEIGHT, "effect sprite",0)) + if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Effect_sprite[i], EFFECT_SPRITE_WIDTH, EFFECT_SPRITE_HEIGHT, "effect sprite",0)) return 1; - cursor_x+=MENU_SPRITE_WIDTH; + cursor_x+=EFFECT_SPRITE_WIDTH; } - cursor_y+=MENU_SPRITE_HEIGHT; + cursor_y+=EFFECT_SPRITE_HEIGHT; // Layer sprite for (j=0; j<3; j++) @@ -452,34 +481,31 @@ byte Parse_skin(SDL_Surface * gui, T_Gui_skin *gfx) if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "menu sprite")) return 1; } - if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Menu_sprite[i], MENU_SPRITE_WIDTH, MENU_SPRITE_HEIGHT, "menu sprite",1)) + if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Menu_sprite[0][i], MENU_SPRITE_WIDTH, MENU_SPRITE_HEIGHT, "menu sprite",1)) + return 1; + cursor_x+=MENU_SPRITE_WIDTH; + } + cursor_y+=MENU_SPRITE_HEIGHT; + + // Menu sprites (selected) + for (i=0; iMenu_sprite[1][i], MENU_SPRITE_WIDTH, MENU_SPRITE_HEIGHT, "selected menu sprite",1)) return 1; cursor_x+=MENU_SPRITE_WIDTH; } cursor_y+=MENU_SPRITE_HEIGHT; - // Paintbrushes - for (i=0; iPaintbrush_sprite[i], PAINTBRUSH_WIDTH, PAINTBRUSH_HEIGHT, "brush icon",2)) - return 1; - cursor_x+=PAINTBRUSH_WIDTH; - } - cursor_y+=PAINTBRUSH_HEIGHT; - // Drive sprites for (i=0; iPreset_paintbrush_width [ 0]= 1; - gfx->Preset_paintbrush_height[ 0]= 1; - gfx->Paintbrush_type [ 0]=PAINTBRUSH_SHAPE_SQUARE; - - gfx->Preset_paintbrush_width [ 1]= 2; - gfx->Preset_paintbrush_height[ 1]= 2; - gfx->Paintbrush_type [ 1]=PAINTBRUSH_SHAPE_SQUARE; - - gfx->Preset_paintbrush_width [ 2]= 3; - gfx->Preset_paintbrush_height[ 2]= 3; - gfx->Paintbrush_type [ 2]=PAINTBRUSH_SHAPE_SQUARE; - - gfx->Preset_paintbrush_width [ 3]= 4; - gfx->Preset_paintbrush_height[ 3]= 4; - gfx->Paintbrush_type [ 3]=PAINTBRUSH_SHAPE_SQUARE; - - gfx->Preset_paintbrush_width [ 4]= 5; - gfx->Preset_paintbrush_height[ 4]= 5; - gfx->Paintbrush_type [ 4]=PAINTBRUSH_SHAPE_SQUARE; - - gfx->Preset_paintbrush_width [ 5]= 7; - gfx->Preset_paintbrush_height[ 5]= 7; - gfx->Paintbrush_type [ 5]=PAINTBRUSH_SHAPE_SQUARE; - - gfx->Preset_paintbrush_width [ 6]= 8; - gfx->Preset_paintbrush_height[ 6]= 8; - gfx->Paintbrush_type [ 6]=PAINTBRUSH_SHAPE_SQUARE; - - gfx->Preset_paintbrush_width [ 7]=12; - gfx->Preset_paintbrush_height[ 7]=12; - gfx->Paintbrush_type [ 7]=PAINTBRUSH_SHAPE_SQUARE; - - gfx->Preset_paintbrush_width [ 8]=16; - gfx->Preset_paintbrush_height[ 8]=16; - gfx->Paintbrush_type [ 8]=PAINTBRUSH_SHAPE_SQUARE; - - gfx->Preset_paintbrush_width [ 9]=16; - gfx->Preset_paintbrush_height[ 9]=16; - gfx->Paintbrush_type [ 9]=PAINTBRUSH_SHAPE_SIEVE_SQUARE; - - gfx->Preset_paintbrush_width [10]=15; - gfx->Preset_paintbrush_height[10]=15; - gfx->Paintbrush_type [10]=PAINTBRUSH_SHAPE_DIAMOND; - - gfx->Preset_paintbrush_width [11]= 5; - gfx->Preset_paintbrush_height[11]= 5; - gfx->Paintbrush_type [11]=PAINTBRUSH_SHAPE_DIAMOND; - - gfx->Preset_paintbrush_width [12]= 3; - gfx->Preset_paintbrush_height[12]= 3; - gfx->Paintbrush_type [12]=PAINTBRUSH_SHAPE_ROUND; - - gfx->Preset_paintbrush_width [13]= 4; - gfx->Preset_paintbrush_height[13]= 4; - gfx->Paintbrush_type [13]=PAINTBRUSH_SHAPE_ROUND; - - gfx->Preset_paintbrush_width [14]= 5; - gfx->Preset_paintbrush_height[14]= 5; - gfx->Paintbrush_type [14]=PAINTBRUSH_SHAPE_ROUND; - - gfx->Preset_paintbrush_width [15]= 6; - gfx->Preset_paintbrush_height[15]= 6; - gfx->Paintbrush_type [15]=PAINTBRUSH_SHAPE_ROUND; - - gfx->Preset_paintbrush_width [16]= 8; - gfx->Preset_paintbrush_height[16]= 8; - gfx->Paintbrush_type [16]=PAINTBRUSH_SHAPE_ROUND; - - gfx->Preset_paintbrush_width [17]=10; - gfx->Preset_paintbrush_height[17]=10; - gfx->Paintbrush_type [17]=PAINTBRUSH_SHAPE_ROUND; - - gfx->Preset_paintbrush_width [18]=12; - gfx->Preset_paintbrush_height[18]=12; - gfx->Paintbrush_type [18]=PAINTBRUSH_SHAPE_ROUND; - - gfx->Preset_paintbrush_width [19]=14; - gfx->Preset_paintbrush_height[19]=14; - gfx->Paintbrush_type [19]=PAINTBRUSH_SHAPE_ROUND; - - gfx->Preset_paintbrush_width [20]=16; - gfx->Preset_paintbrush_height[20]=16; - gfx->Paintbrush_type [20]=PAINTBRUSH_SHAPE_ROUND; - - gfx->Preset_paintbrush_width [21]=15; - gfx->Preset_paintbrush_height[21]=15; - gfx->Paintbrush_type [21]=PAINTBRUSH_SHAPE_SIEVE_ROUND; - - gfx->Preset_paintbrush_width [22]=11; - gfx->Preset_paintbrush_height[22]=11; - gfx->Paintbrush_type [22]=PAINTBRUSH_SHAPE_SIEVE_ROUND; - - gfx->Preset_paintbrush_width [23]= 5; - gfx->Preset_paintbrush_height[23]= 5; - gfx->Paintbrush_type [23]=PAINTBRUSH_SHAPE_SIEVE_ROUND; - - gfx->Preset_paintbrush_width [24]= 2; - gfx->Preset_paintbrush_height[24]= 1; - gfx->Paintbrush_type [24]=PAINTBRUSH_SHAPE_HORIZONTAL_BAR; - - gfx->Preset_paintbrush_width [25]= 3; - gfx->Preset_paintbrush_height[25]= 1; - gfx->Paintbrush_type [25]=PAINTBRUSH_SHAPE_HORIZONTAL_BAR; - - gfx->Preset_paintbrush_width [26]= 4; - gfx->Preset_paintbrush_height[26]= 1; - gfx->Paintbrush_type [26]=PAINTBRUSH_SHAPE_HORIZONTAL_BAR; - - gfx->Preset_paintbrush_width [27]= 8; - gfx->Preset_paintbrush_height[27]= 1; - gfx->Paintbrush_type [27]=PAINTBRUSH_SHAPE_HORIZONTAL_BAR; - - gfx->Preset_paintbrush_width [28]= 1; - gfx->Preset_paintbrush_height[28]= 2; - gfx->Paintbrush_type [28]=PAINTBRUSH_SHAPE_VERTICAL_BAR; - - gfx->Preset_paintbrush_width [29]= 1; - gfx->Preset_paintbrush_height[29]= 3; - gfx->Paintbrush_type [29]=PAINTBRUSH_SHAPE_VERTICAL_BAR; - - gfx->Preset_paintbrush_width [30]= 1; - gfx->Preset_paintbrush_height[30]= 4; - gfx->Paintbrush_type [30]=PAINTBRUSH_SHAPE_VERTICAL_BAR; - - gfx->Preset_paintbrush_width [31]= 1; - gfx->Preset_paintbrush_height[31]= 8; - gfx->Paintbrush_type [31]=PAINTBRUSH_SHAPE_VERTICAL_BAR; - - gfx->Preset_paintbrush_width [32]= 3; - gfx->Preset_paintbrush_height[32]= 3; - gfx->Paintbrush_type [32]=PAINTBRUSH_SHAPE_CROSS; - - gfx->Preset_paintbrush_width [33]= 5; - gfx->Preset_paintbrush_height[33]= 5; - gfx->Paintbrush_type [33]=PAINTBRUSH_SHAPE_CROSS; - - gfx->Preset_paintbrush_width [34]= 5; - gfx->Preset_paintbrush_height[34]= 5; - gfx->Paintbrush_type [34]=PAINTBRUSH_SHAPE_PLUS; - - gfx->Preset_paintbrush_width [35]=15; - gfx->Preset_paintbrush_height[35]=15; - gfx->Paintbrush_type [35]=PAINTBRUSH_SHAPE_PLUS; - - gfx->Preset_paintbrush_width [36]= 2; - gfx->Preset_paintbrush_height[36]= 2; - gfx->Paintbrush_type [36]=PAINTBRUSH_SHAPE_SLASH; - - gfx->Preset_paintbrush_width [37]= 4; - gfx->Preset_paintbrush_height[37]= 4; - gfx->Paintbrush_type [37]=PAINTBRUSH_SHAPE_SLASH; - - gfx->Preset_paintbrush_width [38]= 8; - gfx->Preset_paintbrush_height[38]= 8; - gfx->Paintbrush_type [38]=PAINTBRUSH_SHAPE_SLASH; - - gfx->Preset_paintbrush_width [39]= 2; - gfx->Preset_paintbrush_height[39]= 2; - gfx->Paintbrush_type [39]=PAINTBRUSH_SHAPE_ANTISLASH; - - gfx->Preset_paintbrush_width [40]= 4; - gfx->Preset_paintbrush_height[40]= 4; - gfx->Paintbrush_type [40]=PAINTBRUSH_SHAPE_ANTISLASH; - - gfx->Preset_paintbrush_width [41]= 8; - gfx->Preset_paintbrush_height[41]= 8; - gfx->Paintbrush_type [41]=PAINTBRUSH_SHAPE_ANTISLASH; - - gfx->Preset_paintbrush_width [42]= 4; - gfx->Preset_paintbrush_height[42]= 4; - gfx->Paintbrush_type [42]=PAINTBRUSH_SHAPE_RANDOM; - - gfx->Preset_paintbrush_width [43]= 8; - gfx->Preset_paintbrush_height[43]= 8; - gfx->Paintbrush_type [43]=PAINTBRUSH_SHAPE_RANDOM; - - gfx->Preset_paintbrush_width [44]=13; - gfx->Preset_paintbrush_height[44]=13; - gfx->Paintbrush_type [44]=PAINTBRUSH_SHAPE_RANDOM; - - gfx->Preset_paintbrush_width [45]= 3; - gfx->Preset_paintbrush_height[45]= 3; - gfx->Paintbrush_type [45]=PAINTBRUSH_SHAPE_MISC; - - gfx->Preset_paintbrush_width [46]= 3; - gfx->Preset_paintbrush_height[46]= 3; - gfx->Paintbrush_type [46]=PAINTBRUSH_SHAPE_MISC; - - gfx->Preset_paintbrush_width [47]= 7; - gfx->Preset_paintbrush_height[47]= 7; - gfx->Paintbrush_type [47]=PAINTBRUSH_SHAPE_MISC; - - for (index=0;indexPreset_paintbrush_offset_X[index]=(gfx->Preset_paintbrush_width [index]>>1); - gfx->Preset_paintbrush_offset_Y[index]=(gfx->Preset_paintbrush_height[index]>>1); - } + // Copy unselected bitmaps to current ones + memcpy(gfx->Menu_block[2], gfx->Menu_block[0], + Menu_bars[MENUBAR_TOOLS].Skin_width*Menu_bars[MENUBAR_TOOLS].Height); + memcpy(gfx->Layerbar_block[2], gfx->Layerbar_block[0], + Menu_bars[MENUBAR_LAYERS].Skin_width*Menu_bars[MENUBAR_LAYERS].Height); + memcpy(gfx->Statusbar_block[2], gfx->Statusbar_block[0], + Menu_bars[MENUBAR_STATUS].Skin_width*Menu_bars[MENUBAR_STATUS].Height); + + return 0; } -T_Gui_skin * Load_graphics(const char * skin_file) +T_Gui_skin * Load_graphics(const char * skin_file, T_Gradient_array *gradients) { T_Gui_skin * gfx; char filename[MAX_PATH_CHARACTERS]; @@ -820,10 +658,10 @@ T_Gui_skin * Load_graphics(const char * skin_file) // Read the "skin" file strcpy(filename,Data_directory); - strcat(filename,"skins" PATH_SEPARATOR); + strcat(filename,SKINS_SUBDIRECTORY PATH_SEPARATOR); strcat(filename,skin_file); - gui=Load_surface(filename); + gui=Load_surface(filename, gradients); if (!gui) { sprintf(Gui_loading_error_message, "Unable to load the skin image (missing? not an image file?)\n"); @@ -899,9 +737,9 @@ byte * Load_font(const char * font_name) } // Read the file containing the image - sprintf(filename,"%sskins%s%s", Data_directory, PATH_SEPARATOR, font_name); + sprintf(filename,"%s" SKINS_SUBDIRECTORY "%s%s", Data_directory, PATH_SEPARATOR, font_name); - image=Load_surface(filename); + image=Load_surface(filename, NULL); if (!image) { sprintf(Gui_loading_error_message, "Unable to load the skin image (missing? not an image file?)\n"); @@ -944,6 +782,7 @@ void Init_button(byte btn_number, Buttons_Pool[btn_number].Width =width-1; Buttons_Pool[btn_number].Height =height-1; Buttons_Pool[btn_number].Pressed =0; + Buttons_Pool[btn_number].Icon =-1; Buttons_Pool[btn_number].Shape =shape; Buttons_Pool[btn_number].Left_action =left_action; Buttons_Pool[btn_number].Right_action =right_action; @@ -1463,21 +1302,21 @@ void Init_operations(void) Init_operation(OPERATION_LINE,2,5, Line_12_5,0,FAST_MOUSE); - Init_operation(OPERATION_K_LIGNE,1,0, + Init_operation(OPERATION_K_LINE,1,0, K_line_12_0,HIDE_CURSOR,FAST_MOUSE); - Init_operation(OPERATION_K_LIGNE,1,6, + Init_operation(OPERATION_K_LINE,1,6, K_line_12_6,0,FAST_MOUSE); - Init_operation(OPERATION_K_LIGNE,1,7, + Init_operation(OPERATION_K_LINE,1,7, K_line_12_7,HIDE_CURSOR,FAST_MOUSE); - Init_operation(OPERATION_K_LIGNE,2,FAST_MOUSE, + Init_operation(OPERATION_K_LINE,2,FAST_MOUSE, K_line_12_0,HIDE_CURSOR,FAST_MOUSE); - Init_operation(OPERATION_K_LIGNE,2,6, + Init_operation(OPERATION_K_LINE,2,6, K_line_12_6,0,FAST_MOUSE); - Init_operation(OPERATION_K_LIGNE,2,7, + Init_operation(OPERATION_K_LINE,2,7, K_line_12_7,HIDE_CURSOR,FAST_MOUSE); - Init_operation(OPERATION_K_LIGNE,0,6, + Init_operation(OPERATION_K_LINE,0,6, K_line_0_6,HIDE_CURSOR,FAST_MOUSE); - Init_operation(OPERATION_K_LIGNE,0,7, + Init_operation(OPERATION_K_LINE,0,7, K_line_12_6,0,FAST_MOUSE); Init_operation(OPERATION_EMPTY_RECTANGLE,1,0, @@ -1798,6 +1637,10 @@ void Init_operations(void) Centered_lines_12_7,0,FAST_MOUSE); Init_operation(OPERATION_CENTERED_LINES,0,7, Centered_lines_0_7,0,FAST_MOUSE); + + Init_operation(OPERATION_RMB_COLORPICK,0,1, + Rightclick_colorpick_0_1,0,FAST_MOUSE); + } @@ -1860,7 +1703,7 @@ void Set_all_video_modes(void) // The first mode will have index number 0. // It will be the default mode if an unsupported one // is requested in gfx2.ini - #if defined(__GP2X__) + #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) // Native GP2X resolution Set_video_mode( 320,240,0, 1); #else @@ -1870,7 +1713,7 @@ void Set_all_video_modes(void) Set_video_mode( 320,200,0, 1); Set_video_mode( 320,224,0, 1); - #if !defined(__GP2X__) + #if !defined(__GP2X__) && !defined(__WIZ__) && !defined(__CAANOO__) // For the GP2X, this one is already declared above. Set_video_mode( 320,240,0, 1); #endif @@ -1939,7 +1782,7 @@ void Set_all_video_modes(void) for (index=0; Modes[index]; index++) { int index2; -#if defined(__GP2X__) +#if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) // On the GP2X the first mode is not windowed, so include it in the search. index2=0; #else @@ -1986,7 +1829,7 @@ int Load_CFG(int reload_all) if ((Handle=fopen(filename,"rb"))==NULL) return ERROR_CFG_MISSING; - if ( (file_size<(long)sizeof(cfg_header)) + if ( (file_size<7) || (!Read_bytes(Handle, &cfg_header.Signature, 3)) || memcmp(cfg_header.Signature,"CFG",3) || (!Read_byte(Handle, &cfg_header.Version1)) @@ -2027,7 +1870,7 @@ int Load_CFG(int reload_all) case CHUNK_KEYS: // Touches if (reload_all) { - for (index=0; index<(long)(Chunk.Size/sizeof(cfg_shortcut_info)); index++) + for (index=0; index<(long)(Chunk.Size/6); index++) { if (!Read_word_le(Handle, &cfg_shortcut_info.Number) || !Read_word_le(Handle, &cfg_shortcut_info.Key) || @@ -2080,14 +1923,14 @@ int Load_CFG(int reload_all) } break; case CHUNK_VIDEO_MODES: // Modes vidéo - for (index=0; index<(long)(Chunk.Size/sizeof(cfg_video_mode)); index++) + for (index=0; index<(long)(Chunk.Size/5); index++) { if (!Read_byte(Handle, &cfg_video_mode.State) || !Read_word_le(Handle, &cfg_video_mode.Width) || !Read_word_le(Handle, &cfg_video_mode.Height) ) goto Erreur_lecture_config; -#if defined(__GP2X__) +#if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) index2=0; #else index2=1; @@ -2161,7 +2004,10 @@ int Load_CFG(int reload_all) } break; case CHUNK_GRADIENTS: // Infos sur les dégradés - if (reload_all) + // The gradients chunk is deprecated since the data + // is now loaded/saved in GIF and LBM formats. + // The chunk will be completely ignored. + /*if (reload_all) { if (! Read_byte(Handle, &Current_gradient)) goto Erreur_lecture_config; @@ -2176,7 +2022,7 @@ int Load_CFG(int reload_all) } Load_gradient_data(Current_gradient); } - else + else*/ { if (fseek(Handle,Chunk.Size,SEEK_CUR)==-1) goto Erreur_lecture_config; @@ -2240,6 +2086,96 @@ int Load_CFG(int reload_all) goto Erreur_lecture_config; } break; + + case CHUNK_BRUSH: + if (reload_all) + { + int index; + for (index=0; index> (i&7))) != 0); + } + } + } + else + { + if (fseek(Handle,Chunk.Size,SEEK_CUR)==-1) + goto Erreur_lecture_config; + } + break; + + + case CHUNK_SCRIPTS: + if (reload_all) + { + int current_size=0; + int current_script=0; + + while(current_size=10) + break; + } + + + } + break; + default: // Chunk inconnu goto Erreur_lecture_config; } @@ -2272,7 +2208,7 @@ int Save_CFG(void) T_Config_video_mode cfg_video_mode={0,0,0}; strcpy(filename,Config_directory); - strcat(filename,"gfx2.cfg"); + strcat(filename,CONFIG_FILENAME); if ((Handle=fopen(filename,"wb"))==NULL) return ERROR_SAVING_CFG; @@ -2292,7 +2228,7 @@ int Save_CFG(void) // Enregistrement des touches Chunk.Number=CHUNK_KEYS; - Chunk.Size=NB_SHORTCUTS*sizeof(cfg_shortcut_info); + Chunk.Size=NB_SHORTCUTS*6; if (!Write_byte(Handle, Chunk.Number) || !Write_word_le(Handle, Chunk.Size) ) @@ -2323,7 +2259,7 @@ int Save_CFG(void) // D'abord compter les modes pour lesquels l'utilisateur a mis une préférence modes_to_save=0; -#if defined(__GP2X__) +#if defined(__GP2X__) || defined (__WIZ__) || defined (__CAANOO__) index = 0; #else index = 1; @@ -2334,12 +2270,12 @@ int Save_CFG(void) // Sauvegarde de l'état de chaque mode vidéo Chunk.Number=CHUNK_VIDEO_MODES; - Chunk.Size=modes_to_save * sizeof(cfg_video_mode); + Chunk.Size=modes_to_save * 5; if (!Write_byte(Handle, Chunk.Number) || !Write_word_le(Handle, Chunk.Size) ) goto Erreur_sauvegarde_config; -#if defined(__GP2X__) +#if defined(__GP2X__) || defined (__WIZ__) || defined (__CAANOO__) index = 0; #else index = 1; @@ -2359,7 +2295,7 @@ int Save_CFG(void) // Ecriture des données du Shade (précédées du shade en cours) Chunk.Number=CHUNK_SHADE; - Chunk.Size=sizeof(Shade_list)+sizeof(Shade_current); + Chunk.Size=8209; if (!Write_byte(Handle, Chunk.Number) || !Write_word_le(Handle, Chunk.Size) ) goto Erreur_sauvegarde_config; @@ -2379,7 +2315,7 @@ int Save_CFG(void) // Sauvegarde des informations du Masque Chunk.Number=CHUNK_MASK; - Chunk.Size=sizeof(Mask_table); + Chunk.Size=256; if (!Write_byte(Handle, Chunk.Number) || !Write_word_le(Handle, Chunk.Size) ) goto Erreur_sauvegarde_config; @@ -2388,7 +2324,7 @@ int Save_CFG(void) // Sauvegarde des informations du Stencil Chunk.Number=CHUNK_STENCIL; - Chunk.Size=sizeof(Stencil); + Chunk.Size=256; if (!Write_byte(Handle, Chunk.Number) || !Write_word_le(Handle, Chunk.Size) ) goto Erreur_sauvegarde_config; @@ -2396,8 +2332,11 @@ int Save_CFG(void) goto Erreur_sauvegarde_config; // Sauvegarde des informations des dégradés + // The gradients chunk is deprecated since the data + // is now loaded/saved in GIF and LBM formats. + /* Chunk.Number=CHUNK_GRADIENTS; - Chunk.Size=sizeof(Gradient_array)+1; + Chunk.Size=14*16+1; if (!Write_byte(Handle, Chunk.Number) || !Write_word_le(Handle, Chunk.Size) ) goto Erreur_sauvegarde_config; @@ -2412,10 +2351,11 @@ int Save_CFG(void) !Write_dword_le(Handle, Gradient_array[index].Technique) ) goto Erreur_sauvegarde_config; } + */ // Sauvegarde de la matrice du Smooth Chunk.Number=CHUNK_SMOOTH; - Chunk.Size=sizeof(Smooth_matrix); + Chunk.Size=9; if (!Write_byte(Handle, Chunk.Number) || !Write_word_le(Handle, Chunk.Size) ) goto Erreur_sauvegarde_config; @@ -2426,7 +2366,7 @@ int Save_CFG(void) // Sauvegarde des couleurs à exclure Chunk.Number=CHUNK_EXCLUDE_COLORS; - Chunk.Size=sizeof(Exclude_color); + Chunk.Size=256; if (!Write_byte(Handle, Chunk.Number) || !Write_word_le(Handle, Chunk.Size) ) goto Erreur_sauvegarde_config; @@ -2435,7 +2375,7 @@ int Save_CFG(void) // Sauvegarde des informations du Quick-shade Chunk.Number=CHUNK_QUICK_SHADE; - Chunk.Size=sizeof(Quick_shade_step)+sizeof(Quick_shade_loop); + Chunk.Size=2; if (!Write_byte(Handle, Chunk.Number) || !Write_word_le(Handle, Chunk.Size) ) goto Erreur_sauvegarde_config; @@ -2459,7 +2399,104 @@ int Save_CFG(void) if (!Write_word_le(Handle, Snap_offset_Y)) goto Erreur_sauvegarde_config; + // Save brush data + { + long total_size=0; + int index; + // Compute size: monochrome paintbrushes + for (index=0; index> (i&7); + if ((i&7) == 7) + { + // Write one byte + if (!Write_byte(Handle, current_byte)) + goto Erreur_sauvegarde_config; + current_byte=0; + } + } + // Remainder + if ((i&7) != 0) + { + // Write one byte + if (!Write_byte(Handle, current_byte)) + goto Erreur_sauvegarde_config; + } + } + } + + // Save script shortcuts + { + int i; + Chunk.Number=CHUNK_SCRIPTS; + // Compute size : Data stored as 10 pascal strings + Chunk.Size=0; + for (i=0; i<10; i++) + { + if (Bound_script[i]==NULL) + Chunk.Size+=1; + else + Chunk.Size+=strlen(Bound_script[i])+1; + } + // Header + if (!Write_byte(Handle, Chunk.Number) || + !Write_word_le(Handle, Chunk.Size) ) + goto Erreur_sauvegarde_config; + + // Strings + for (i=0; i<10; i++) + { + byte size=0; + if (Bound_script[i]!=NULL) + size=strlen(Bound_script[i]); + + if (!Write_byte(Handle, size)) + goto Erreur_sauvegarde_config; + + if (size) + if (!Write_bytes(Handle, Bound_script[i], size)) + goto Erreur_sauvegarde_config; + } + } + if (fclose(Handle)) return ERROR_SAVING_CFG; @@ -2520,19 +2557,7 @@ void Set_config_defaults(void) // Stencil for (index=0; index<256; index++) Stencil[index]=1; - - // Dégradés - Current_gradient=0; - for(index=0;index<16;index++) - { - Gradient_array[index].Start=0; - Gradient_array[index].End=0; - Gradient_array[index].Inverse=0; - Gradient_array[index].Mix=0; - Gradient_array[index].Technique=0; - } - Load_gradient_data(Current_gradient); - + // Smooth Smooth_matrix[0][0]=1; Smooth_matrix[0][1]=2; @@ -2614,16 +2639,18 @@ void Init_brush_container(void) for (i=0; iColor[2]; MC_White = gfx->Color[3]; MC_Trans = gfx->Color_trans; + MC_OnBlack=MC_Dark; + MC_Window=MC_Light; + MC_Lighter=MC_White; + MC_Darker=MC_Dark; + // Set menubars to point to the new data - Menu_bars[MENUBAR_TOOLS].Skin = (byte*)&(gfx->Menu_block); - Menu_bars[MENUBAR_LAYERS].Skin = (byte*)&(gfx->Layerbar_block); - Menu_bars[MENUBAR_STATUS].Skin = (byte*)&(gfx->Statusbar_block); + for (i=0; i<3; i++) + { + Menu_bars[MENUBAR_TOOLS ].Skin[i] = (byte*)&(gfx->Menu_block[i]); + Menu_bars[MENUBAR_LAYERS].Skin[i] = (byte*)&(gfx->Layerbar_block[i]); + Menu_bars[MENUBAR_STATUS].Skin[i] = (byte*)&(gfx->Statusbar_block[i]); + } } /// @@ -2686,3 +2723,253 @@ void Compute_menu_offsets(void) Menu_Y = Screen_height - Menu_height * Menu_factor_Y; } +void Init_paintbrush(int index, int width, int height, byte shape, const char * bitmap) +{ + if (bitmap!=NULL) + { + int i; + + Paintbrush[index].Shape=shape; + Paintbrush[index].Width=width; + Paintbrush[index].Height=height; + Paintbrush[index].Offset_X=width>>1; + Paintbrush[index].Offset_Y=height>>1; + + // Decode pixels + for (i=0;i> (i&7))) != 0); + } + } + else + { + Paintbrush_shape=shape; + Set_paintbrush_size(width, height); + Store_paintbrush(index); + } + +} + + +void Init_paintbrushes(void) +{ + int index; + + Init_paintbrush( 0, 1, 1,PAINTBRUSH_SHAPE_SQUARE, NULL); + Init_paintbrush( 1, 2, 2,PAINTBRUSH_SHAPE_SQUARE, NULL); + Init_paintbrush( 2, 3, 3,PAINTBRUSH_SHAPE_SQUARE, NULL); + Init_paintbrush( 3, 4, 4,PAINTBRUSH_SHAPE_SQUARE, NULL); + Init_paintbrush( 4, 5, 5,PAINTBRUSH_SHAPE_SQUARE, NULL); + Init_paintbrush( 5, 7, 7,PAINTBRUSH_SHAPE_SQUARE, NULL); + Init_paintbrush( 6, 8, 8,PAINTBRUSH_SHAPE_SQUARE, NULL); + Init_paintbrush( 7,12,12,PAINTBRUSH_SHAPE_SQUARE, NULL); + Init_paintbrush( 8,16,16,PAINTBRUSH_SHAPE_SQUARE, NULL); + Init_paintbrush( 9,16,16,PAINTBRUSH_SHAPE_SIEVE_SQUARE, NULL); + Init_paintbrush(10,15,15,PAINTBRUSH_SHAPE_DIAMOND, NULL); + Init_paintbrush(11, 5, 5,PAINTBRUSH_SHAPE_DIAMOND, NULL); + Init_paintbrush(12, 3, 3,PAINTBRUSH_SHAPE_ROUND, NULL); + Init_paintbrush(13, 4, 4,PAINTBRUSH_SHAPE_ROUND, NULL); + Init_paintbrush(14, 5, 5,PAINTBRUSH_SHAPE_ROUND, NULL); + Init_paintbrush(15, 6, 6,PAINTBRUSH_SHAPE_ROUND, NULL); + Init_paintbrush(16, 8, 8,PAINTBRUSH_SHAPE_ROUND, NULL); + Init_paintbrush(17,10,10,PAINTBRUSH_SHAPE_ROUND, NULL); + Init_paintbrush(18,12,12,PAINTBRUSH_SHAPE_ROUND, NULL); + Init_paintbrush(19,14,14,PAINTBRUSH_SHAPE_ROUND, NULL); + Init_paintbrush(20,16,16,PAINTBRUSH_SHAPE_ROUND, NULL); + Init_paintbrush(21,15,15,PAINTBRUSH_SHAPE_SIEVE_ROUND, NULL); + Init_paintbrush(22,11,11,PAINTBRUSH_SHAPE_SIEVE_ROUND, NULL); + Init_paintbrush(23, 5, 5,PAINTBRUSH_SHAPE_SIEVE_ROUND, NULL); + Init_paintbrush(24, 2, 1,PAINTBRUSH_SHAPE_HORIZONTAL_BAR, NULL); + Init_paintbrush(25, 3, 1,PAINTBRUSH_SHAPE_HORIZONTAL_BAR, NULL); + Init_paintbrush(26, 4, 1,PAINTBRUSH_SHAPE_HORIZONTAL_BAR, NULL); + Init_paintbrush(27, 8, 1,PAINTBRUSH_SHAPE_HORIZONTAL_BAR, NULL); + Init_paintbrush(28, 1, 2,PAINTBRUSH_SHAPE_VERTICAL_BAR, NULL); + Init_paintbrush(29, 1, 3,PAINTBRUSH_SHAPE_VERTICAL_BAR, NULL); + Init_paintbrush(30, 1, 4,PAINTBRUSH_SHAPE_VERTICAL_BAR, NULL); + Init_paintbrush(31, 1, 8,PAINTBRUSH_SHAPE_VERTICAL_BAR, NULL); + Init_paintbrush(32, 3, 3,PAINTBRUSH_SHAPE_CROSS, NULL); + Init_paintbrush(33, 5, 5,PAINTBRUSH_SHAPE_CROSS, NULL); + Init_paintbrush(34, 5, 5,PAINTBRUSH_SHAPE_PLUS, NULL); + Init_paintbrush(35,15,15,PAINTBRUSH_SHAPE_PLUS, NULL); + Init_paintbrush(36, 2, 2,PAINTBRUSH_SHAPE_SLASH, NULL); + Init_paintbrush(37, 4, 4,PAINTBRUSH_SHAPE_SLASH, NULL); + Init_paintbrush(38, 8, 8,PAINTBRUSH_SHAPE_SLASH, NULL); + Init_paintbrush(39, 2, 2,PAINTBRUSH_SHAPE_ANTISLASH, NULL); + Init_paintbrush(40, 4, 4,PAINTBRUSH_SHAPE_ANTISLASH, NULL); + Init_paintbrush(41, 8, 8,PAINTBRUSH_SHAPE_ANTISLASH, NULL); + + Init_paintbrush(42, 4, 4,PAINTBRUSH_SHAPE_RANDOM, "\x20\x81"); + Init_paintbrush(43, 8, 8,PAINTBRUSH_SHAPE_RANDOM, "\x44\x00\x11\x00\x88\x01\x40\x08"); + Init_paintbrush(44,13,13,PAINTBRUSH_SHAPE_RANDOM, "\x08\x00\x08\x90\x00\x10\x42\x10\x02\x06\x02\x02\x04\x02\x08\x42\x10\x44\x00\x00\x44\x00"); + + Init_paintbrush(45, 3, 3,PAINTBRUSH_SHAPE_MISC, "\x7f\x00"); + Init_paintbrush(46, 3, 3,PAINTBRUSH_SHAPE_MISC, "\xdd\x80"); + Init_paintbrush(47, 7, 7,PAINTBRUSH_SHAPE_MISC, "\x06\x30\x82\x04\x10\x20\x00"); + + for (index=0;index>1); + Paintbrush[index].Offset_Y=(Paintbrush[index].Height>>1); + } +} + +/// Set application icon(s) +void Define_icon(void) +{ +#ifdef WIN32 + // Specific code for Win32: + // Load icon from embedded resource. + // This will provide both the 16x16 and 32x32 versions. + do + { + HICON hicon; + HRSRC hresource; + HINSTANCE hInstance; + LPVOID lpResIconDir; + LPVOID lpResIcon16; + LPVOID lpResIcon32; + HGLOBAL hMem; + WORD nID; + SDL_SysWMinfo info; + + hInstance = (HINSTANCE)GetModuleHandle(NULL); + if (hInstance==NULL) + break; + + // Icon is resource #1 + hresource = FindResource(hInstance, + MAKEINTRESOURCE(1), + RT_GROUP_ICON); + if (hresource==NULL) + break; + + // Load and lock the icon directory. + hMem = LoadResource(hInstance, hresource); + if (hMem==NULL) + break; + + lpResIconDir = LockResource(hMem); + if (lpResIconDir==NULL) + break; + + SDL_VERSION(&info.version); + SDL_GetWMInfo(&info); + + // + // 16x16 + // + + // Get the identifier of the 16x16 icon + nID = LookupIconIdFromDirectoryEx((PBYTE) lpResIconDir, TRUE, + 16, 16, LR_DEFAULTCOLOR); + if (nID==0) + break; + + // Find the bits for the nID icon. + hresource = FindResource(hInstance, + MAKEINTRESOURCE(nID), + MAKEINTRESOURCE((long)RT_ICON)); + if (hresource==NULL) + break; + + // Load and lock the icon. + hMem = LoadResource(hInstance, hresource); + if (hMem==NULL) + break; + lpResIcon16 = LockResource(hMem); + if (lpResIcon16==NULL) + break; + + // Create a handle to the icon. + hicon = CreateIconFromResourceEx((PBYTE) lpResIcon16, + SizeofResource(hInstance, hresource), TRUE, 0x00030000, + 16, 16, LR_DEFAULTCOLOR); + if (hicon==NULL) + break; + + // Set it + SetClassLongPtr(info.window, GCL_HICONSM, (LONG_PTR)hicon); + + + // + // 32x32 + // + + // Get the identifier of the 32x32 icon + nID = LookupIconIdFromDirectoryEx((PBYTE) lpResIconDir, TRUE, + 32, 32, LR_DEFAULTCOLOR); + if (nID==0) + break; + + // Find the bits for the nID icon. + hresource = FindResource(hInstance, + MAKEINTRESOURCE(nID), + MAKEINTRESOURCE((long)RT_ICON)); + if (hresource==NULL) + break; + + // Load and lock the icon. + hMem = LoadResource(hInstance, hresource); + if (hMem==NULL) + break; + lpResIcon32 = LockResource(hMem); + if (lpResIcon32==NULL) + break; + + // Create a handle to the icon. + hicon = CreateIconFromResourceEx((PBYTE) lpResIcon32, + SizeofResource(hInstance, hresource), TRUE, 0x00030000, + 32, 32, LR_DEFAULTCOLOR); + if (hicon==NULL) + break; + + // Set it + SetClassLongPtr(info.window, GCL_HICON, (LONG_PTR)hicon); + + + // Success + return; + } while (0); + // Failure: fall back on normal SDL version: + +#endif + // General version: Load icon from the file gfx2.gif + { + char icon_path[MAX_PATH_CHARACTERS]; + SDL_Surface * icon; + sprintf(icon_path, "%s%s", Data_directory, "gfx2.gif"); + icon = IMG_Load(icon_path); + if (icon && icon->w == 32 && icon->h == 32) + { + Uint32 pink; + pink = SDL_MapRGB(icon->format, 255, 0, 255); + + if (icon->format->BitsPerPixel == 8) + { + // 8bit image: use color key + + SDL_SetColorKey(icon, SDL_SRCCOLORKEY, pink); + SDL_WM_SetIcon(icon,NULL); + } + else + { + // 24bit image: need to build a mask on magic pink + + byte *icon_mask; + int x,y; + + icon_mask=malloc(128); + memset(icon_mask,0,128); + for (y=0;y<32;y++) + for (x=0;x<32;x++) + if (Get_SDL_pixel_hicolor(icon, x, y) != pink) + icon_mask[(y*32+x)/8] |=0x80>>(x&7); + SDL_WM_SetIcon(icon,icon_mask); + free(icon_mask); + icon_mask = NULL; + } + SDL_FreeSurface(icon); + } + } +} \ No newline at end of file diff --git a/src/init.h b/src/init.h index 8d8ca318..3f64ae7a 100644 --- a/src/init.h +++ b/src/init.h @@ -24,7 +24,7 @@ /// Initialization (and some de-initialization) functions. ////////////////////////////////////////////////////////////////////////////// -T_Gui_skin *Load_graphics(const char * skin_file); +T_Gui_skin *Load_graphics(const char * skin_file, T_Gradient_array *gradients); void Set_current_skin(const char *skinfile, T_Gui_skin *gfx); void Init_buttons(void); void Init_operations(void); @@ -34,6 +34,10 @@ int Save_CFG(void); void Set_all_video_modes(void); void Set_config_defaults(void); void Init_sighandler(void); +void Init_paintbrushes(void); + +/// Set application icon(s) +void Define_icon(void); extern char Gui_loading_error_message[512]; diff --git a/src/input.c b/src/input.c index f9875245..45b54b6f 100644 --- a/src/input.c +++ b/src/input.c @@ -21,6 +21,12 @@ */ #include +#include + +#ifdef __WIN32__ + #include + #include +#endif #include "global.h" #include "keyboard.h" @@ -28,7 +34,9 @@ #include "windows.h" #include "errors.h" #include "misc.h" +#include "buttons.h" #include "input.h" +#include "loadsave.h" #ifdef __VBCC__ #define __attribute__(x) @@ -36,6 +44,7 @@ void Handle_window_resize(SDL_ResizeEvent event); void Handle_window_exit(SDL_QuitEvent event); +int Color_cycling(__attribute__((unused)) void* useless); // public Globals (available as extern) @@ -44,8 +53,11 @@ int Snap_axis = 0; int Snap_axis_origin_X; int Snap_axis_origin_Y; +char * Drop_file_name = NULL; + // -- +// Digital joystick state byte Directional_up; byte Directional_up_right; byte Directional_right; @@ -56,14 +68,22 @@ byte Directional_left; byte Directional_up_left; byte Directional_click; -long Directional_delay; +// Emulated directional controller. +// This has a distinct state from Directional_, because some joysticks send +// "I'm not moving" SDL events when idle, thus stopping the emulated one. +byte Directional_emulated_up; +byte Directional_emulated_right; +byte Directional_emulated_down; +byte Directional_emulated_left; + +long Directional_first_move; long Directional_last_move; -long Directional_step; int Mouse_moved; ///< Boolean, Set to true if any cursor movement occurs. word Input_new_mouse_X; word Input_new_mouse_Y; byte Input_new_mouse_K; +byte Button_inverter=0; // State of the key that swaps mouse buttons. byte Mouse_mode = 0; ///< Mouse mode = 0:normal, 1:emulated with custom sensitivity. short Mouse_virtual_x_position; @@ -71,21 +91,84 @@ short Mouse_virtual_y_position; short Mouse_virtual_width; short Mouse_virtual_height; -// TODO: move to config -#ifdef __GP2X__ -short Joybutton_shift=GP2X_BUTTON_L; // Button number that serves as a "shift" modifier -short Joybutton_control=GP2X_BUTTON_R; // Button number that serves as a "ctrl" modifier -short Joybutton_alt=GP2X_BUTTON_CLICK; // Button number that serves as a "alt" modifier -short Joybutton_left_click=GP2X_BUTTON_B; // Button number that serves as left click -short Joybutton_right_click=GP2X_BUTTON_Y; // Button number that serves as right-click -#else -short Joybutton_shift=-1; // Button number that serves as a "shift" modifier -short Joybutton_control=-1; // Button number that serves as a "ctrl" modifier -short Joybutton_alt=-1; // Button number that serves as a "alt" modifier -short Joybutton_left_click=0; // Button number that serves as left click -short Joybutton_right_click=0; // Button number that serves as right-click +// Joystick/pad configurations for the various console ports. +// See the #else for the documentation of fields. +// TODO: Make these user-settable somehow. +#if defined(__GP2X__) + + #define JOYSTICK_THRESHOLD (4096) + short Joybutton_shift= JOY_BUTTON_L; + short Joybutton_control= JOY_BUTTON_R; + short Joybutton_alt= JOY_BUTTON_CLICK; + short Joybutton_left_click= JOY_BUTTON_B; + short Joybutton_right_click=JOY_BUTTON_Y; + +#elif defined(__WIZ__) + + #define JOYSTICK_THRESHOLD (4096) + short Joybutton_shift= JOY_BUTTON_X; + short Joybutton_control= JOY_BUTTON_SELECT; + short Joybutton_alt= JOY_BUTTON_Y; + short Joybutton_left_click= JOY_BUTTON_A; + short Joybutton_right_click=JOY_BUTTON_B; + +#elif defined(__CAANOO__) + + #define JOYSTICK_THRESHOLD (4096) + short Joybutton_shift= JOY_BUTTON_L; + short Joybutton_control= JOY_BUTTON_R; + short Joybutton_alt= JOY_BUTTON_Y; + short Joybutton_left_click= JOY_BUTTON_A; + short Joybutton_right_click=JOY_BUTTON_B; + +#else // Default : Any joystick on a computer platform + /// + /// This is the sensitivity threshold for the directional + /// pad of a cheap digital joypad on the PC. It has been set through + /// trial and error : If value is too large then the movement is + /// randomly interrupted; if the value is too low the cursor will + /// move by itself, controlled by parasits. + /// YR 04/11/2010: I just observed a -8700 when joystick is idle. + #define JOYSTICK_THRESHOLD (10000) + + /// A button that is marked as "modifier" will + short Joybutton_shift=-1; ///< Button number that serves as a "shift" modifier; -1 for none + short Joybutton_control=-1; ///< Button number that serves as a "ctrl" modifier; -1 for none + short Joybutton_alt=-1; ///< Button number that serves as a "alt" modifier; -1 for none + + short Joybutton_left_click=0; ///< Button number that serves as left click; -1 for none + short Joybutton_right_click=1; ///< Button number that serves as right-click; -1 for none + #endif +int Has_shortcut(word function) +{ + if (function == 0xFFFF) + return 0; + + if (function & 0x100) + { + if (Buttons_Pool[function&0xFF].Left_shortcut[0]!=KEY_NONE) + return 1; + if (Buttons_Pool[function&0xFF].Left_shortcut[1]!=KEY_NONE) + return 1; + return 0; + } + if (function & 0x200) + { + if (Buttons_Pool[function&0xFF].Right_shortcut[0]!=KEY_NONE) + return 1; + if (Buttons_Pool[function&0xFF].Right_shortcut[1]!=KEY_NONE) + return 1; + return 0; + } + if(Config_Key[function][0]!=KEY_NONE) + return 1; + if(Config_Key[function][1]!=KEY_NONE) + return 1; + return 0; +} + int Is_shortcut(word key, word function) { if (key == 0 || function == 0xFFFF) @@ -177,16 +260,18 @@ int Move_cursor_with_constraints() feedback=1; if (Input_new_mouse_K == 0) + { Input_sticky_control = 0; + } } // Hide cursor, because even just a click change needs it if (!Mouse_moved) { - Mouse_moved++; // Hide cursor (erasing icon and brush on screen // before changing the coordinates. Hide_cursor(); } + Mouse_moved++; if (Input_new_mouse_X != Mouse_X || Input_new_mouse_Y != Mouse_Y) { Mouse_X=Input_new_mouse_X; @@ -194,8 +279,8 @@ int Move_cursor_with_constraints() } Mouse_K=Input_new_mouse_K; - if (Mouse_moved > Config.Mouse_merge_movement) - if (! Operation[Current_operation][Mouse_K_unique] + if (Mouse_moved > Config.Mouse_merge_movement + && !Operation[Current_operation][Mouse_K_unique] [Operation_stack_size].Fast_mouse) feedback=1; } @@ -254,11 +339,19 @@ int Handle_mouse_click(SDL_MouseButtonEvent event) switch(event.button) { case SDL_BUTTON_LEFT: - Input_new_mouse_K |= 1; + if (Button_inverter) + Input_new_mouse_K |= 2; + else + Input_new_mouse_K |= 1; + break; break; case SDL_BUTTON_RIGHT: - Input_new_mouse_K |= 2; + if (Button_inverter) + Input_new_mouse_K |= 1; + else + Input_new_mouse_K |= 2; + break; break; case SDL_BUTTON_MIDDLE: @@ -284,11 +377,17 @@ int Handle_mouse_release(SDL_MouseButtonEvent event) switch(event.button) { case SDL_BUTTON_LEFT: - Input_new_mouse_K &= ~1; + if (Button_inverter) + Input_new_mouse_K &= ~2; + else + Input_new_mouse_K &= ~1; break; case SDL_BUTTON_RIGHT: - Input_new_mouse_K &= ~2; + if (Button_inverter) + Input_new_mouse_K &= ~1; + else + Input_new_mouse_K &= ~2; break; } @@ -300,27 +399,64 @@ int Handle_mouse_release(SDL_MouseButtonEvent event) int Handle_key_press(SDL_KeyboardEvent event) { //Appui sur une touche du clavier + int modifier; + Key = Keysym_to_keycode(event.keysym); Key_ANSI = Keysym_to_ANSI(event.keysym); + switch(event.keysym.sym) + { + case SDLK_RSHIFT: + case SDLK_LSHIFT: + modifier=MOD_SHIFT; + break; + + case SDLK_RCTRL: + case SDLK_LCTRL: + modifier=MOD_CTRL; + break; + + case SDLK_RALT: + case SDLK_LALT: + case SDLK_MODE: + modifier=MOD_ALT; + break; + + case SDLK_RMETA: + case SDLK_LMETA: + modifier=MOD_META; + break; + + default: + modifier=0; + } + if (Config.Swap_buttons && modifier == Config.Swap_buttons && Button_inverter==0) + { + Button_inverter=1; + if (Input_new_mouse_K) + { + Input_new_mouse_K ^= 3; // Flip bits 0 and 1 + return Move_cursor_with_constraints(); + } + } if(Is_shortcut(Key,SPECIAL_MOUSE_UP)) { - Directional_up=1; + Directional_emulated_up=1; return 0; } else if(Is_shortcut(Key,SPECIAL_MOUSE_DOWN)) { - Directional_down=1; + Directional_emulated_down=1; return 0; } else if(Is_shortcut(Key,SPECIAL_MOUSE_LEFT)) { - Directional_left=1; + Directional_emulated_left=1; return 0; } else if(Is_shortcut(Key,SPECIAL_MOUSE_RIGHT)) { - Directional_right=1; + Directional_emulated_right=1; return 0; } else if(Is_shortcut(Key,SPECIAL_CLICK_LEFT) && Keyboard_click_allowed > 0) @@ -349,26 +485,35 @@ int Release_control(int key_code, int modifier) Snap_axis = 0; need_feedback = 1; } + if (Config.Swap_buttons && modifier == Config.Swap_buttons && Button_inverter==1) + { + Button_inverter=0; + if (Input_new_mouse_K) + { + Input_new_mouse_K ^= 3; // Flip bits 0 and 1 + return Move_cursor_with_constraints(); + } + } if((key_code && key_code == (Config_Key[SPECIAL_MOUSE_UP][0]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_UP][0]&modifier) || (key_code && key_code == (Config_Key[SPECIAL_MOUSE_UP][1]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_UP][1]&modifier)) { - Directional_up=0; + Directional_emulated_up=0; } if((key_code && key_code == (Config_Key[SPECIAL_MOUSE_DOWN][0]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_DOWN][0]&modifier) || (key_code && key_code == (Config_Key[SPECIAL_MOUSE_DOWN][1]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_DOWN][1]&modifier)) { - Directional_down=0; + Directional_emulated_down=0; } if((key_code && key_code == (Config_Key[SPECIAL_MOUSE_LEFT][0]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_LEFT][0]&modifier) || (key_code && key_code == (Config_Key[SPECIAL_MOUSE_LEFT][1]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_LEFT][1]&modifier)) { - Directional_left=0; + Directional_emulated_left=0; } if((key_code && key_code == (Config_Key[SPECIAL_MOUSE_RIGHT][0]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_RIGHT][0]&modifier) || (key_code && key_code == (Config_Key[SPECIAL_MOUSE_RIGHT][1]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_RIGHT][1]&modifier)) { - Directional_right=0; + Directional_emulated_right=0; } if((key_code && key_code == (Config_Key[SPECIAL_CLICK_LEFT][0]&0x0FFF)) || (Config_Key[SPECIAL_CLICK_LEFT][0]&modifier) || (key_code && key_code == (Config_Key[SPECIAL_CLICK_LEFT][1]&0x0FFF)) || (Config_Key[SPECIAL_CLICK_LEFT][1]&modifier)) @@ -445,54 +590,88 @@ int Handle_joystick_press(SDL_JoyButtonEvent event) if (event.button == Joybutton_control) { SDL_SetModState(SDL_GetModState() | KMOD_CTRL); + if (Config.Swap_buttons == MOD_CTRL && Button_inverter==0) + { + Button_inverter=1; + if (Input_new_mouse_K) + { + Input_new_mouse_K ^= 3; // Flip bits 0 and 1 + return Move_cursor_with_constraints(); + } + } return 0; } if (event.button == Joybutton_alt) { SDL_SetModState(SDL_GetModState() | (KMOD_ALT|KMOD_META)); + if (Config.Swap_buttons == MOD_ALT && Button_inverter==0) + { + Button_inverter=1; + if (Input_new_mouse_K) + { + Input_new_mouse_K ^= 3; // Flip bits 0 and 1 + return Move_cursor_with_constraints(); + } + } return 0; } if (event.button == Joybutton_left_click) { - Input_new_mouse_K=1; + Input_new_mouse_K = Button_inverter ? 2 : 1; return Move_cursor_with_constraints(); } if (event.button == Joybutton_right_click) { - Input_new_mouse_K=2; + Input_new_mouse_K = Button_inverter ? 1 : 2; return Move_cursor_with_constraints(); } - #ifdef __GP2X__ switch(event.button) { - case GP2X_BUTTON_UP: + #ifdef JOY_BUTTON_UP + case JOY_BUTTON_UP: Directional_up=1; break; - case GP2X_BUTTON_UPRIGHT: + #endif + #ifdef JOY_BUTTON_UPRIGHT + case JOY_BUTTON_UPRIGHT: Directional_up_right=1; break; - case GP2X_BUTTON_RIGHT: + #endif + #ifdef JOY_BUTTON_RIGHT + case JOY_BUTTON_RIGHT: Directional_right=1; break; - case GP2X_BUTTON_DOWNRIGHT: + #endif + #ifdef JOY_BUTTON_DOWNRIGHT + case JOY_BUTTON_DOWNRIGHT: Directional_down_right=1; break; - case GP2X_BUTTON_DOWN: + #endif + #ifdef JOY_BUTTON_DOWN + case JOY_BUTTON_DOWN: Directional_down=1; break; - case GP2X_BUTTON_DOWNLEFT: + #endif + #ifdef JOY_BUTTON_DOWNLEFT + case JOY_BUTTON_DOWNLEFT: Directional_down_left=1; break; - case GP2X_BUTTON_LEFT: + #endif + #ifdef JOY_BUTTON_LEFT + case JOY_BUTTON_LEFT: Directional_left=1; break; - case GP2X_BUTTON_UPLEFT: + #endif + #ifdef JOY_BUTTON_UPLEFT + case JOY_BUTTON_UPLEFT: Directional_up_left=1; break; + #endif + default: break; } - #endif + Key = (KEY_JOYBUTTON+event.button)|Key_modifiers(SDL_GetModState()); // TODO: systeme de répétition @@ -527,58 +706,75 @@ int Handle_joystick_release(SDL_JoyButtonEvent event) return Move_cursor_with_constraints(); } - #ifdef __GP2X__ switch(event.button) { - case GP2X_BUTTON_UP: - Directional_up=0; + #ifdef JOY_BUTTON_UP + case JOY_BUTTON_UP: + Directional_up=1; break; - case GP2X_BUTTON_UPRIGHT: - Directional_up_right=0; + #endif + #ifdef JOY_BUTTON_UPRIGHT + case JOY_BUTTON_UPRIGHT: + Directional_up_right=1; break; - case GP2X_BUTTON_RIGHT: - Directional_right=0; + #endif + #ifdef JOY_BUTTON_RIGHT + case JOY_BUTTON_RIGHT: + Directional_right=1; break; - case GP2X_BUTTON_DOWNRIGHT: - Directional_down_right=0; + #endif + #ifdef JOY_BUTTON_DOWNRIGHT + case JOY_BUTTON_DOWNRIGHT: + Directional_down_right=1; break; - case GP2X_BUTTON_DOWN: - Directional_down=0; + #endif + #ifdef JOY_BUTTON_DOWN + case JOY_BUTTON_DOWN: + Directional_down=1; break; - case GP2X_BUTTON_DOWNLEFT: - Directional_down_left=0; + #endif + #ifdef JOY_BUTTON_DOWNLEFT + case JOY_BUTTON_DOWNLEFT: + Directional_down_left=1; break; - case GP2X_BUTTON_LEFT: - Directional_left=0; + #endif + #ifdef JOY_BUTTON_LEFT + case JOY_BUTTON_LEFT: + Directional_left=1; break; - case GP2X_BUTTON_UPLEFT: - Directional_up_left=0; + #endif + #ifdef JOY_BUTTON_UPLEFT + case JOY_BUTTON_UPLEFT: + Directional_up_left=1; + break; + #endif + + default: break; } - #endif return Move_cursor_with_constraints(); } void Handle_joystick_movement(SDL_JoyAxisEvent event) { - if (event.axis==0) // X + if (event.axis==JOYSTICK_AXIS_X) { Directional_right=Directional_left=0; - if (event.value<-1000) + if (event.value<-JOYSTICK_THRESHOLD) { Directional_left=1; } - else if (event.value>1000) + else if (event.value>JOYSTICK_THRESHOLD) Directional_right=1; } - else if (event.axis==1) // Y + else if (event.axis==JOYSTICK_AXIS_Y) { Directional_up=Directional_down=0; - if (event.value<-1000) + if (event.value<-JOYSTICK_THRESHOLD) { Directional_up=1; } - else if (event.value>1000) + else if (event.value>JOYSTICK_THRESHOLD) Directional_down=1; } } @@ -616,138 +812,222 @@ int Cursor_displace(short delta_x, short delta_y) return Move_cursor_with_constraints(); } +// This function is the acceleration profile for directional (digital) cursor +// controllers. +int Directional_acceleration(int msec) +{ + const int initial_delay = 250; + const int linear_factor = 200; + const int accel_factor = 10000; + // At beginning there is 1 pixel move, then nothing for N milliseconds + if (msecmsg == WM_DROPFILES) + { + int file_count; + HDROP hdrop = (HDROP)(event.syswm.msg->wParam); + if((file_count = DragQueryFile(hdrop,(UINT)-1,(LPTSTR) NULL ,(UINT) 0)) > 0) + { + long len; + // Query filename length + len = DragQueryFile(hdrop,0 ,NULL ,0); + if (len) + { + Drop_file_name=calloc(len+1,1); + if (Drop_file_name) + { + if (DragQueryFile(hdrop,0 ,(LPTSTR) Drop_file_name ,(UINT) MAX_PATH)) + { + // Success + } + else + { + free(Drop_file_name); + // Don't report name copy error + } + } + else + { + // Don't report alloc error (for a file name? :/ ) + } + } + else + { + // Don't report weird Windows error + } + } + else + { + // Drop of zero files. Thanks for the information, Bill. + } + } +#endif + break; + + default: + //DEBUG("Unhandled SDL event number : ",event.type); + break; + } } // Directional controller if (!(Directional_up||Directional_up_right||Directional_right|| - Directional_down_right||Directional_down||Directional_down_left|| - Directional_left||Directional_up_left)) + Directional_down_right||Directional_down||Directional_down_left|| + Directional_left||Directional_up_left||Directional_emulated_up|| + Directional_emulated_right||Directional_emulated_down|| + Directional_emulated_left)) { - Directional_delay=-1; - Directional_last_move=SDL_GetTicks(); + Directional_first_move=0; } else { long time_now; + int step=0; time_now=SDL_GetTicks(); - if (time_now>Directional_last_move+Directional_delay) + if (Directional_first_move==0) + { + Directional_first_move=time_now; + step=1; + } + else + { + // Compute how much the cursor has moved since last call. + // This tries to make smooth cursor movement + // no matter the frequency of calls to Get_input() + step = + Directional_acceleration(time_now - Directional_first_move) - + Directional_acceleration(Directional_last_move - Directional_first_move); + + // Clip speed at 3 pixel per visible frame. + if (step > 3) + step=3; + + } + Directional_last_move = time_now; + if (step) { - // Speed parameters, acceleration etc. are here - if (Directional_delay==-1) - { - Directional_delay=150; - Directional_step=16; - } - else if (Directional_delay==150) - Directional_delay=40; - else if (Directional_delay!=0) - Directional_delay=Directional_delay*8/10; - else if (Directional_step<16*4) - Directional_step++; - Directional_last_move = time_now; - // Directional controller UP - if ((Directional_up||Directional_up_left||Directional_up_right) && - !(Directional_down_right||Directional_down||Directional_down_left)) + if ((Directional_up||Directional_emulated_up||Directional_up_left||Directional_up_right) && + !(Directional_down_right||Directional_down||Directional_emulated_down||Directional_down_left)) { - Cursor_displace(0, -Directional_step/16); + Cursor_displace(0, -step); } // Directional controller RIGHT - if ((Directional_up_right||Directional_right||Directional_down_right) && - !(Directional_down_left||Directional_left||Directional_up_left)) + if ((Directional_up_right||Directional_right||Directional_emulated_right||Directional_down_right) && + !(Directional_down_left||Directional_left||Directional_emulated_left||Directional_up_left)) { - Cursor_displace(Directional_step/16,0); + Cursor_displace(step,0); } // Directional controller DOWN - if ((Directional_down_right||Directional_down||Directional_down_left) && - !(Directional_up_left||Directional_up||Directional_up_right)) + if ((Directional_down_right||Directional_down||Directional_emulated_down||Directional_down_left) && + !(Directional_up_left||Directional_up||Directional_emulated_up||Directional_up_right)) { - Cursor_displace(0, Directional_step/16); + Cursor_displace(0, step); } // Directional controller LEFT - if ((Directional_down_left||Directional_left||Directional_up_left) && - !(Directional_up_right||Directional_right||Directional_down_right)) + if ((Directional_down_left||Directional_left||Directional_emulated_left||Directional_up_left) && + !(Directional_up_right||Directional_right||Directional_emulated_right||Directional_down_right)) { - Cursor_displace(-Directional_step/16,0); + Cursor_displace(-step,0); } } } @@ -757,14 +1037,15 @@ int Get_input(void) { Compute_paintbrush_coordinates(); Display_cursor(); + return 1; } - // Commit any pending screen update. - // This is done in this function because it's called after reading - // some user input. - Flush_update(); - + if (user_feedback_required) + return 1; - return (Mouse_moved!=0) || user_feedback_required; + // Nothing significant happened + if (sleep_time) + SDL_Delay(sleep_time); + return 0; } void Adjust_mouse_sensitivity(word fullscreen) @@ -796,3 +1077,74 @@ void Set_mouse_position(void) Mouse_virtual_y_position = 12*Mouse_Y*Pixel_height; } } + +int Color_cycling(__attribute__((unused)) void* useless) +{ + static byte offset[16]; + int i, color; + static SDL_Color PaletteSDL[256]; + int changed; // boolean : true if the palette needs a change in this tick. + + long now; + static long start=0; + + if (start==0) + { + // First run + start = SDL_GetTicks(); + return 1; + } + if (!Allow_colorcycling || !Cycling_mode) + return 1; + + + now = SDL_GetTicks(); + changed=0; + + // Check all cycles for a change at this tick + for (i=0; i<16; i++) + { + int len; + + len=Main_backups->Pages->Gradients->Range[i].End-Main_backups->Pages->Gradients->Range[i].Start+1; + if (len>1 && Main_backups->Pages->Gradients->Range[i].Speed) + { + int new_offset; + + new_offset=(now-start)/(int)(1000.0/(Main_backups->Pages->Gradients->Range[i].Speed*0.2856)) % len; + if (!Main_backups->Pages->Gradients->Range[i].Inverse) + new_offset=len - new_offset; + + if (new_offset!=offset[i]) + changed=1; + offset[i]=new_offset; + } + } + if (changed) + { + // Initialize the palette + for(color=0;color<256;color++) + { + PaletteSDL[color].r=Main_palette[color].R; + PaletteSDL[color].g=Main_palette[color].G; + PaletteSDL[color].b=Main_palette[color].B; + } + for (i=0; i<16; i++) + { + int len; + + len=Main_backups->Pages->Gradients->Range[i].End-Main_backups->Pages->Gradients->Range[i].Start+1; + if (len>1 && Main_backups->Pages->Gradients->Range[i].Speed) + { + for(color=Main_backups->Pages->Gradients->Range[i].Start;color<=Main_backups->Pages->Gradients->Range[i].End;color++) + { + PaletteSDL[color].r=Main_palette[Main_backups->Pages->Gradients->Range[i].Start+((color-Main_backups->Pages->Gradients->Range[i].Start+offset[i])%len)].R; + PaletteSDL[color].g=Main_palette[Main_backups->Pages->Gradients->Range[i].Start+((color-Main_backups->Pages->Gradients->Range[i].Start+offset[i])%len)].G; + PaletteSDL[color].b=Main_palette[Main_backups->Pages->Gradients->Range[i].Start+((color-Main_backups->Pages->Gradients->Range[i].Start+offset[i])%len)].B; + } + } + } + SDL_SetPalette(Screen_SDL, SDL_PHYSPAL | SDL_LOGPAL, PaletteSDL,0,256); + } + return 0; +} diff --git a/src/input.h b/src/input.h index dee65dd7..9ee0d7e7 100644 --- a/src/input.h +++ b/src/input.h @@ -33,11 +33,14 @@ /// The latest input variables are held in ::Key, ::Key_ANSI, ::Mouse_X, ::Mouse_Y, ::Mouse_K. /// Note that ::Key and ::Key_ANSI are not persistent, they will be reset to 0 /// on subsequent calls to ::Get_input(). -int Get_input(void); +int Get_input(int sleep_time); /// Returns true if the keycode has been set as a keyboard shortcut for the function. int Is_shortcut(word key, word function); +/// Returns true if the function has any shortcut key. +int Has_shortcut(word function); + /// Adjust mouse sensitivity (and actual mouse input mode) void Adjust_mouse_sensitivity(word fullscreen); @@ -56,3 +59,8 @@ extern int Snap_axis; extern int Snap_axis_origin_X; /// For the :Snap_axis mode, sets the origin's point (in image coordinates) extern int Snap_axis_origin_Y; + +/// +/// This malloced string is set when a drag-and-drop event +/// brings a file to Grafx2's window. +extern char * Drop_file_name; diff --git a/src/io.c b/src/io.c index 4707ed3c..d770a84f 100644 --- a/src/io.c +++ b/src/io.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) @@ -32,14 +33,24 @@ #include #include -#if defined(__amigaos4__) +#if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) #include + #include #include + #define isHidden(x) (0) #elif defined(__WIN32__) #include #include + //#include + #define isHidden(x) (GetFileAttributesA((x)->d_name)&FILE_ATTRIBUTE_HIDDEN) +#elif defined(__MINT__) + #include + #include + #include + #define isHidden(x) (0) #else #include + #define isHidden(x) ((x)->d_name[0]=='.') #endif #include "struct.h" @@ -276,6 +287,38 @@ void For_each_file(const char * directory_name, void Callback(const char *)) closedir(current_directory); } +/// Scans a directory, calls Callback for each file or directory in it, +void For_each_directory_entry(const char * directory_name, void Callback(const char *, byte is_file, byte is_directory, byte is_hidden)) +{ + // Pour scan de répertoire + DIR* current_directory; //Répertoire courant + struct dirent* entry; // Structure de lecture des éléments + char full_filename[MAX_PATH_CHARACTERS]; + int filename_position; + strcpy(full_filename, directory_name); + current_directory=opendir(directory_name); + if(current_directory == NULL) return; // Répertoire invalide ... + filename_position = strlen(full_filename); + if (filename_position==0 || strcmp(full_filename+filename_position-1,PATH_SEPARATOR)) + { + strcat(full_filename, PATH_SEPARATOR); + filename_position = strlen(full_filename); + } + while ((entry=readdir(current_directory))) + { + struct stat Infos_enreg; + strcpy(&full_filename[filename_position], entry->d_name); + stat(full_filename,&Infos_enreg); + Callback( + full_filename, + S_ISREG(Infos_enreg.st_mode), + S_ISDIR(Infos_enreg.st_mode), + isHidden(entry)?1:0); + } + closedir(current_directory); +} + + void Get_full_filename(char * output_name, char * file_name, char * directory_name) { strcpy(output_name,directory_name); @@ -299,7 +342,7 @@ int Lock_file_handle = -1; byte Create_lock_file(const char *file_directory) { - #ifdef __amigaos__ + #if defined (__amigaos__)||(__AROS__) #warning "Missing code for your platform, please check and correct!" #else char lock_filename[MAX_PATH_CHARACTERS]; @@ -336,7 +379,7 @@ byte Create_lock_file(const char *file_directory) return -1; } #endif - #endif // __amigaos__ + #endif // __amigaos__ or __AROS__ return 0; } diff --git a/src/io.h b/src/io.h index 98cecb43..53237f3f 100644 --- a/src/io.h +++ b/src/io.h @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Yves Rizoud Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) @@ -71,6 +72,8 @@ char * Find_last_slash(const char * str); #if defined(__WIN32__) #define PATH_SEPARATOR "\\" +#elif defined(__MINT__) + #define PATH_SEPARATOR "\\" #else #define PATH_SEPARATOR "/" #endif @@ -90,6 +93,10 @@ int Directory_exists(char * directory); /// Scans a directory, calls Callback for each file in it, void For_each_file(const char * directory_name, void Callback(const char *)); +/// Scans a directory, calls Callback for each file or directory in it, +void For_each_directory_entry(const char * directory_name, void Callback(const char *, byte is_file, byte is_directory, byte is_hidden)); + + /// /// Creates a fully qualified name from a directory and filename. /// The point is simply to insert a PATH_SEPARATOR when needed. diff --git a/src/keyboard.c b/src/keyboard.c index 01071125..b459b83c 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2010 Alexander Filyanov Copyright 2009 Franck Charlet Copyright 2008 Yves Rizoud Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) @@ -465,38 +466,93 @@ const char * Key_name(word key) key=key & ~(MOD_CTRL|MOD_ALT|MOD_SHIFT); - if (key>=KEY_JOYBUTTON && key<=KEY_JOYBUTTON+18) + // 99 is only a sanity check + if (key>=KEY_JOYBUTTON && key<=KEY_JOYBUTTON+99) { -#ifdef __GP2X__ char *button_name; switch(key-KEY_JOYBUTTON) - { - case GP2X_BUTTON_UP: button_name="[UP]"; break; - case GP2X_BUTTON_DOWN: button_name="[DOWN]"; break; - case GP2X_BUTTON_LEFT: button_name="[LEFT]"; break; - case GP2X_BUTTON_RIGHT: button_name="[RIGHT]"; break; - case GP2X_BUTTON_UPLEFT: button_name="[UP-LEFT]"; break; - case GP2X_BUTTON_UPRIGHT: button_name="[UP-RIGHT]"; break; - case GP2X_BUTTON_DOWNLEFT: button_name="[DOWN-LEFT]"; break; - case GP2X_BUTTON_DOWNRIGHT: button_name="[DOWN-RIGHT]"; break; - case GP2X_BUTTON_CLICK: button_name="[CLICK]"; break; - case GP2X_BUTTON_A: button_name="[A]"; break; - case GP2X_BUTTON_B: button_name="[B]"; break; - case GP2X_BUTTON_X: button_name="[X]"; break; - case GP2X_BUTTON_Y: button_name="[Y]"; break; - case GP2X_BUTTON_L: button_name="[L]"; break; - case GP2X_BUTTON_R: button_name="[R]"; break; - case GP2X_BUTTON_START: button_name="[START]"; break; - case GP2X_BUTTON_SELECT: button_name="[SELECT]"; break; - case GP2X_BUTTON_VOLUP: button_name="[VOL UP]"; break; - case GP2X_BUTTON_VOLDOWN: button_name="[VOL DOWN]"; break; - default: sprintf(buffer+strlen(buffer), "[B%d]", key);return buffer; + { + #ifdef JOY_BUTTON_UP + case JOY_BUTTON_UP: button_name="[UP]"; break; + #endif + #ifdef JOY_BUTTON_DOWN + case JOY_BUTTON_DOWN: button_name="[DOWN]"; break; + #endif + #ifdef JOY_BUTTON_LEFT + case JOY_BUTTON_LEFT: button_name="[LEFT]"; break; + #endif + #ifdef JOY_BUTTON_RIGHT + case JOY_BUTTON_RIGHT: button_name="[RIGHT]"; break; + #endif + #ifdef JOY_BUTTON_UPLEFT + case JOY_BUTTON_UPLEFT: button_name="[UP-LEFT]"; break; + #endif + #ifdef JOY_BUTTON_UPRIGHT + case JOY_BUTTON_UPRIGHT: button_name="[UP-RIGHT]"; break; + #endif + #ifdef JOY_BUTTON_DOWNLEFT + case JOY_BUTTON_DOWNLEFT: button_name="[DOWN-LEFT]"; break; + #endif + #ifdef JOY_BUTTON_DOWNRIGHT + case JOY_BUTTON_DOWNRIGHT: button_name="[DOWN-RIGHT]"; break; + #endif + #ifdef JOY_BUTTON_CLICK + case JOY_BUTTON_CLICK: button_name="[CLICK]"; break; + #endif + #ifdef JOY_BUTTON_A + case JOY_BUTTON_A: button_name="[A]"; break; + #endif + #ifdef JOY_BUTTON_B + case JOY_BUTTON_B: button_name="[B]"; break; + #endif + #ifdef JOY_BUTTON_X + case JOY_BUTTON_X: button_name="[X]"; break; + #endif + #ifdef JOY_BUTTON_Y + case JOY_BUTTON_Y: button_name="[Y]"; break; + #endif + #ifdef JOY_BUTTON_L + case JOY_BUTTON_L: button_name="[L]"; break; + #endif + #ifdef JOY_BUTTON_R + case JOY_BUTTON_R: button_name="[R]"; break; + #endif + #ifdef JOY_BUTTON_START + case JOY_BUTTON_START: button_name="[START]"; break; + #endif + #ifdef JOY_BUTTON_SELECT + case JOY_BUTTON_SELECT: button_name="[SELECT]"; break; + #endif + #ifdef JOY_BUTTON_VOLUP + case JOY_BUTTON_VOLUP: button_name="[VOL UP]"; break; + #endif + #ifdef JOY_BUTTON_VOLDOWN + case JOY_BUTTON_VOLDOWN: button_name="[VOL DOWN]"; break; + #endif + #ifdef JOY_BUTTON_MENU + case JOY_BUTTON_MENU: button_name="[MENU]"; break; + #endif + #ifdef JOY_BUTTON_HOME + case JOY_BUTTON_HOME: button_name="[HOME]"; break; + #endif + #ifdef JOY_BUTTON_HOLD + case JOY_BUTTON_HOLD: button_name="[HOLD]"; break; + #endif + #ifdef JOY_BUTTON_I + case JOY_BUTTON_I: button_name="[BUTTON I]"; break; + #endif + #ifdef JOY_BUTTON_II + case JOY_BUTTON_II: button_name="[BUTTON II]"; break; + #endif + #ifdef JOY_BUTTON_JOY + case JOY_BUTTON_JOY: button_name="[THUMB JOY]"; break; + #endif + + default: sprintf(buffer+strlen(buffer), "[B%d]", key-KEY_JOYBUTTON);return buffer; } strcat(buffer,button_name); -#else - sprintf(buffer+strlen(buffer), "[B%d]", key-KEY_JOYBUTTON); -#endif + return buffer; } diff --git a/src/loadsave.c b/src/loadsave.c index b8f1075e..87238a54 100644 --- a/src/loadsave.c +++ b/src/loadsave.c @@ -2,6 +2,8 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski + Copyright 2010 Alexander Filyanov Copyright 2009 Petter Lindquist Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet @@ -47,6 +49,8 @@ #include "struct.h" #include "windows.h" #include "engine.h" +#include "brush.h" +#include "setup.h" // -- PKM ------------------------------------------------------------------- void Test_PKM(T_IO_Context *); @@ -121,6 +125,10 @@ void Save_C64(T_IO_Context *); // -- SCR (Amstrad CPC) void Save_SCR(T_IO_Context *); +// -- XPM (X PixMap) +// Loading is done through SDL_Image +void Save_XPM(T_IO_Context*); + // -- PNG ------------------------------------------------------------------- #ifndef __no_pnglib__ void Test_PNG(T_IO_Context *); @@ -133,7 +141,7 @@ void Save_PNG(T_IO_Context *); void Load_SDL_Image(T_IO_Context *); // ENUM Name TestFunc LoadFunc SaveFunc PalOnly Comment Layers Ext Exts -T_Format File_formats[NB_KNOWN_FORMATS] = { +T_Format File_formats[] = { {FORMAT_ALL_IMAGES, "(all)", NULL, NULL, NULL, 0, 0, 0, "", "gif;png;bmp;pcx;pkm;lbm;iff;img;sci;scq;scf;scn;sco;pi1;pc1;cel;neo;kcf;pal;c64;koa;koala;fli;bml;cdu;prg;tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff;ico"}, {FORMAT_ALL_FILES, "(*.*)", NULL, NULL, NULL, 0, 0, 0, "", "*"}, {FORMAT_GIF, " gif", Test_GIF, Load_GIF, Save_GIF, 0, 1, 1, "gif", "gif"}, @@ -143,7 +151,7 @@ T_Format File_formats[NB_KNOWN_FORMATS] = { {FORMAT_BMP, " bmp", Test_BMP, Load_BMP, Save_BMP, 0, 0, 0, "bmp", "bmp"}, {FORMAT_PCX, " pcx", Test_PCX, Load_PCX, Save_PCX, 0, 0, 0, "pcx", "pcx"}, {FORMAT_PKM, " pkm", Test_PKM, Load_PKM, Save_PKM, 0, 1, 0, "pkm", "pkm"}, - {FORMAT_LBM, " lbm", Test_LBM, Load_LBM, Save_LBM, 0, 0, 0, "lbm", "lbm;iff"}, + {FORMAT_LBM, " lbm", Test_LBM, Load_LBM, Save_LBM, 0, 0, 0, "lbm", "lbm;iff;ilbm"}, {FORMAT_IMG, " img", Test_IMG, Load_IMG, Save_IMG, 0, 0, 0, "img", "img"}, {FORMAT_SCx, " sc?", Test_SCx, Load_SCx, Save_SCx, 0, 0, 0, "sc?", "sci;scq;scf;scn;sco"}, {FORMAT_PI1, " pi1", Test_PI1, Load_PI1, Save_PI1, 0, 0, 0, "pi1", "pi1"}, @@ -154,9 +162,16 @@ T_Format File_formats[NB_KNOWN_FORMATS] = { {FORMAT_PAL, " pal", Test_PAL, Load_PAL, Save_PAL, 1, 0, 0, "pal", "pal"}, {FORMAT_C64, " c64", Test_C64, Load_C64, Save_C64, 0, 1, 0, "c64", "c64;koa;koala;fli;bml;cdu;prg"}, {FORMAT_SCR, " cpc", NULL, NULL, Save_SCR, 0, 0, 0, "cpc", "cpc;scr"}, + {FORMAT_XPM, " xpm", NULL, NULL, Save_XPM, 0, 0, 0, "xpm", "xpm"}, {FORMAT_MISC,"misc.",NULL, NULL, NULL, 0, 0, 0, "", "tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff;ico"}, }; +/// Total number of known file formats +unsigned int Nb_known_formats(void) +{ + return sizeof(File_formats)/sizeof(File_formats[0]); +} + /// Set the color of a pixel (on load) void Set_pixel(T_IO_Context *context, short x_pos, short y_pos, byte color) { @@ -180,38 +195,32 @@ void Set_pixel(T_IO_Context *context, short x_pos, short y_pos, byte color) // Chargement des pixels dans la preview case CONTEXT_PREVIEW: // Skip pixels of transparent index if : - // - It's the first layer, and image has transparent background. - // - or it's a layer above the first one - if (color == context->Transparent_color && (context->Current_layer > 0 || context->Background_transparent)) + // it's a layer above the first one + if (color == context->Transparent_color && context->Current_layer > 0) break; + if (((x_pos % context->Preview_factor_X)==0) && ((y_pos % context->Preview_factor_Y)==0)) { + // Tag the color as 'used' + context->Preview_usage[color]=1; + + // Store pixel if (context->Ratio == PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE2) { - Pixel(context->Preview_pos_X+(x_pos/context->Preview_factor_X*2), - context->Preview_pos_Y+(y_pos/context->Preview_factor_Y), - color); - Pixel(context->Preview_pos_X+(x_pos/context->Preview_factor_X*2)+1, - context->Preview_pos_Y+(y_pos/context->Preview_factor_Y), - color); + context->Preview_bitmap[x_pos/context->Preview_factor_X*2 + (y_pos/context->Preview_factor_Y)*PREVIEW_WIDTH*Menu_factor_X]=color; + context->Preview_bitmap[x_pos/context->Preview_factor_X*2+1 + (y_pos/context->Preview_factor_Y)*PREVIEW_WIDTH*Menu_factor_X]=color; } else if (context->Ratio == PIXEL_TALL && Pixel_ratio != PIXEL_TALL && Pixel_ratio != PIXEL_TALL2) { - Pixel(context->Preview_pos_X+(x_pos/context->Preview_factor_X), - context->Preview_pos_Y+(y_pos/context->Preview_factor_Y*2), - color); - Pixel(context->Preview_pos_X+(x_pos/context->Preview_factor_X), - context->Preview_pos_Y+(y_pos/context->Preview_factor_Y*2)+1, - color); + context->Preview_bitmap[x_pos/context->Preview_factor_X + (y_pos/context->Preview_factor_Y*2)*PREVIEW_WIDTH*Menu_factor_X]=color; + context->Preview_bitmap[x_pos/context->Preview_factor_X + (y_pos/context->Preview_factor_Y*2+1)*PREVIEW_WIDTH*Menu_factor_X]=color; } else - Pixel(context->Preview_pos_X+(x_pos/context->Preview_factor_X), - context->Preview_pos_Y+(y_pos/context->Preview_factor_Y), - color); + context->Preview_bitmap[x_pos/context->Preview_factor_X + (y_pos/context->Preview_factor_Y)*PREVIEW_WIDTH*Menu_factor_X]=color; } break; @@ -234,8 +243,6 @@ void Palette_loaded(T_IO_Context *context) { case CONTEXT_MAIN_IMAGE: case CONTEXT_PREVIEW: - Set_palette(context->Palette); - break; case CONTEXT_BRUSH: case CONTEXT_SURFACE: break; @@ -243,67 +250,7 @@ void Palette_loaded(T_IO_Context *context) switch (context->Type) { - case CONTEXT_PREVIEW: - - Compute_optimal_menu_colors(context->Palette); - /* - if( - ( - context->Palette[MC_Black].R==context->Palette[MC_Dark].R && - context->Palette[MC_Black].G==context->Palette[MC_Dark].G && - context->Palette[MC_Black].B==context->Palette[MC_Dark].B - ) || - ( - context->Palette[MC_Light].R==context->Palette[MC_Dark].R && - context->Palette[MC_Light].G==context->Palette[MC_Dark].G && - context->Palette[MC_Light].B==context->Palette[MC_Dark].B - ) || - ( - context->Palette[MC_White].R==context->Palette[MC_Light].R && - context->Palette[MC_White].G==context->Palette[MC_Light].G && - context->Palette[MC_White].B==context->Palette[MC_Light].B - ) - ) - - { - // Si on charge une image monochrome, le fileselect ne sera plus visible. Dans ce cas on force quelques couleurs à des valeurs sures - - int black = - Main_palette[MC_Black].R + - Main_palette[MC_Black].G + - Main_palette[MC_Black].B; - int white = - Main_palette[MC_White].R + - Main_palette[MC_White].G + - Main_palette[MC_White].B; - - //Set_color(MC_Light,(2*white+black)/9,(2*white+black)/9,(2*white+black)/9); - //Set_color(MC_Dark,(2*black+white)/9,(2*black+white)/9,(2*black+white)/9); - Main_palette[MC_Dark].R=(2*black+white)/9; - Main_palette[MC_Dark].G=(2*black+white)/9; - Main_palette[MC_Dark].B=(2*black+white)/9; - Main_palette[MC_Light].R=(2*white+black)/9; - Main_palette[MC_Light].G=(2*white+black)/9; - Main_palette[MC_Light].B=(2*white+black)/9; - - Set_palette(Main_palette); - } - */ - Remap_screen_after_menu_colors_change(); - - // Preview palette - if (Get_fileformat(context->Format)->Palette_only) - { - short index; - - if (context->Type == CONTEXT_PREVIEW) - for (index=0; index<256; index++) - Window_rectangle(183+(index/16)*7,95+(index&15)*5,5,5,index); - - Update_window_area(183,95,120,80); - } - break; - + case CONTEXT_PREVIEW: case CONTEXT_MAIN_IMAGE: case CONTEXT_BRUSH: case CONTEXT_SURFACE: @@ -336,17 +283,17 @@ void Set_pixel_24b(T_IO_Context *context, short x_pos, short y_pos, byte r, byte break; case CONTEXT_PREVIEW: - { - if (((x_pos % context->Preview_factor_X)==0) && ((y_pos % context->Preview_factor_Y)==0)) - { - color=((r >> 5) << 5) | - ((g >> 5) << 2) | - ((b >> 6)); - Pixel(context->Preview_pos_X+(x_pos/context->Preview_factor_X), - context->Preview_pos_Y+(y_pos/context->Preview_factor_Y), - color); - } + if (((x_pos % context->Preview_factor_X)==0) && ((y_pos % context->Preview_factor_Y)==0)) + { + color=((r >> 5) << 5) | + ((g >> 5) << 2) | + ((b >> 6)); + + // Tag the color as 'used' + context->Preview_usage[color]=1; + + context->Preview_bitmap[x_pos/context->Preview_factor_X + (y_pos/context->Preview_factor_Y)*PREVIEW_WIDTH*Menu_factor_X]=color; } break; } @@ -388,6 +335,11 @@ void Pre_load(T_IO_Context *context, short width, short height, long file_size, // Preview case CONTEXT_PREVIEW: // Préparation du chargement d'une preview: + + context->Preview_bitmap=malloc(PREVIEW_WIDTH*PREVIEW_HEIGHT*Menu_factor_X*Menu_factor_Y); + if (!context->Preview_bitmap) + File_error=1; + // Affichage des données "Image size:" if ((width<10000) && (height<10000)) { @@ -426,11 +378,12 @@ void Pre_load(T_IO_Context *context, short width, short height, long file_size, { Print_in_window( 59,59,Get_fileformat(format)->Label,MC_Black,MC_Light); } - + // On efface le commentaire précédent Window_rectangle(45,70,32*8,8,MC_Light); // Affichage du commentaire - Print_in_window(45,70,context->Comment,MC_Black,MC_Light); + if (Get_fileformat(format)->Comment) + Print_in_window(45,70,Main_comment,MC_Black,MC_Light); // Calcul des données nécessaires à l'affichage de la preview: if (ratio == PIXEL_WIDE && @@ -442,8 +395,8 @@ void Pre_load(T_IO_Context *context, short width, short height, long file_size, Pixel_ratio != PIXEL_TALL2) height*=2; - context->Preview_factor_X=Round_div_max(width,122*Menu_factor_X); - context->Preview_factor_Y=Round_div_max(height, 82*Menu_factor_Y); + context->Preview_factor_X=Round_div_max(width,120*Menu_factor_X); + context->Preview_factor_Y=Round_div_max(height, 80*Menu_factor_Y); if ( (!Config.Maximize_preview) && (context->Preview_factor_X!=context->Preview_factor_Y) ) { @@ -457,17 +410,17 @@ void Pre_load(T_IO_Context *context, short width, short height, long file_size, context->Preview_pos_Y=Window_pos_Y+ 95*Menu_factor_Y; // On nettoie la zone où va s'afficher la preview: - Window_rectangle(183,95,120,80,MC_Light); + Window_rectangle(183,95,PREVIEW_WIDTH,PREVIEW_HEIGHT,MC_Light); // Un update pour couvrir les 4 zones: 3 libellés plus le commentaire Update_window_area(45,48,256,30); // Zone de preview - Update_window_area(183,95,120,80); + Update_window_area(183,95,PREVIEW_WIDTH,PREVIEW_HEIGHT); break; // Other loading case CONTEXT_MAIN_IMAGE: - if (Backup_with_new_dimensions(0,1,width,height)) + if (Backup_new_image(1,width,height)) { // La nouvelle page a pu être allouée, elle est pour l'instant pleine // de 0s. Elle fait Main_image_width de large. @@ -605,7 +558,10 @@ void Load_image(T_IO_Context *context) { unsigned int index; // index de balayage des formats T_Format *format = &(File_formats[2]); // Format du fichier à charger - + int i; + + // Not sure it's the best place... + context->Color_cycles=0; // On place par défaut File_error à vrai au cas où on ne sache pas // charger le format du fichier: @@ -622,7 +578,7 @@ void Load_image(T_IO_Context *context) { // Sinon, on va devoir scanner les différents formats qu'on connait pour // savoir à quel format est le fichier: - for (index=0; index < NB_KNOWN_FORMATS; index++) + for (index=0; index < Nb_known_formats(); index++) { format = Get_fileformat(index); // Loadable format @@ -714,7 +670,7 @@ void Load_image(T_IO_Context *context) case CONTEXT_SURFACE: if (Convert_24b_bitmap_to_256(context->Surface->pixels,context->Buffer_image_24b,context->Width,context->Height,context->Palette)) - File_error=1; + File_error=1; break; } @@ -722,11 +678,34 @@ void Load_image(T_IO_Context *context) free(context->Buffer_image_24b); context->Buffer_image_24b = NULL; } + else if (context->Type == CONTEXT_MAIN_IMAGE) + { + // Non-24b main image: Add menu colors + if (Config.Safety_colors) + { + dword color_usage[256]; + memset(color_usage,0,sizeof(color_usage)); + if (Count_used_colors(color_usage)<252) + { + int gui_index=0; + int c; + for (c=255; c>=0 && gui_index<4; c--) + { + if (color_usage[c]==0) + { + context->Palette[c]=*Favorite_GUI_color(gui_index); + gui_index++; + } + } + } + } + } if (context->Type == CONTEXT_MAIN_IMAGE) { if ( File_error!=1) { + Set_palette(context->Palette); if (format->Palette_only) { // Make a backup step @@ -773,6 +752,21 @@ void Load_image(T_IO_Context *context) Main_image_width=1; if (Main_image_height<1) Main_image_height=1; + + // Color cyling ranges: + for (i=0; i<16; i++) + Main_backups->Pages->Gradients->Range[i].Speed=0; + for (i=0; iColor_cycles; i++) + { + Main_backups->Pages->Gradients->Range[i].Start=context->Cycle_range[i].Start; + Main_backups->Pages->Gradients->Range[i].End=context->Cycle_range[i].End; + Main_backups->Pages->Gradients->Range[i].Inverse=context->Cycle_range[i].Inverse; + Main_backups->Pages->Gradients->Range[i].Speed=context->Cycle_range[i].Speed; + } + + // Comment + strcpy(Main_comment, context->Comment); + } } else if (File_error!=1) @@ -791,19 +785,16 @@ void Load_image(T_IO_Context *context) } else if (context->Type == CONTEXT_BRUSH && File_error==0) { - free(Brush); - Brush=context->Buffer_image; - context->Buffer_image = NULL; - - Brush_width=context->Width; - Brush_height=context->Height; - - free(Smear_brush); - Smear_brush_width=(Brush_width>MAX_PAINTBRUSH_SIZE)?Brush_width:MAX_PAINTBRUSH_SIZE; - Smear_brush_height=(Brush_height>MAX_PAINTBRUSH_SIZE)?Brush_height:MAX_PAINTBRUSH_SIZE; - Smear_brush=(byte *)malloc(Smear_brush_width*Smear_brush_height); - if (!Smear_brush) + + if (Realloc_brush(context->Width, context->Height, context->Buffer_image, NULL)) + { File_error=3; + free(context->Buffer_image); + } + memcpy(Brush_original_palette, context->Palette, sizeof(T_Palette)); + Remap_brush(); + + context->Buffer_image = NULL; } else if (context->Type == CONTEXT_SURFACE) { @@ -822,6 +813,91 @@ void Load_image(T_IO_Context *context) SDL_SetColors(context->Surface, colors, 0, 256); } } + else if (context->Type == CONTEXT_PREVIEW + /*&& !context->Buffer_image_24b*/ + /*&& !Get_fileformat(context->Format)->Palette_only*/) + { + + // Try to adapt the palette to accomodate the GUI. + int c; + int count_unused; + byte unused_color[4]; + + count_unused=0; + // Try find 4 unused colors and insert good colors there + for (c=255; c>=0 && count_unused<4; c--) + { + if (!context->Preview_usage[c]) + { + unused_color[count_unused]=c; + count_unused++; + } + } + // Found! replace them with some favorites + if (count_unused==4) + { + int gui_index; + for (gui_index=0; gui_index<4; gui_index++) + { + context->Palette[unused_color[gui_index]]=*Favorite_GUI_color(gui_index); + } + } + // All preview display is here + + // Update palette and screen first + Compute_optimal_menu_colors(context->Palette); + Remap_screen_after_menu_colors_change(); + Set_palette(context->Palette); + + // Display palette preview + if (Get_fileformat(context->Format)->Palette_only) + { + short index; + + if (context->Type == CONTEXT_PREVIEW) + for (index=0; index<256; index++) + Window_rectangle(183+(index/16)*7,95+(index&15)*5,5,5,index); + + } + // Display normal image + else if (context->Preview_bitmap) + { + int x_pos,y_pos; + int width,height; + width=context->Width/context->Preview_factor_X; + height=context->Height/context->Preview_factor_Y; + if (context->Ratio == PIXEL_WIDE && + Pixel_ratio != PIXEL_WIDE && + Pixel_ratio != PIXEL_WIDE2) + width*=2; + else if (context->Ratio == PIXEL_TALL && + Pixel_ratio != PIXEL_TALL && + Pixel_ratio != PIXEL_TALL2) + height*=2; + + for (y_pos=0; y_posPreview_bitmap[x_pos+y_pos*PREVIEW_WIDTH*Menu_factor_X]; + + // Skip transparent if image has transparent background. + if (color == context->Transparent_color && context->Background_transparent) + color=MC_Window; + + Pixel(context->Preview_pos_X+x_pos, + context->Preview_pos_Y+y_pos, + color); + } + } + // Refresh modified part + Update_window_area(183,95,PREVIEW_WIDTH,PREVIEW_HEIGHT); + + // Preview comment + Print_in_window(45,70,context->Comment,MC_Black,MC_Light); + //Update_window_area(45,70,32*8,8); + + } + } @@ -916,8 +992,10 @@ void Load_SDL_Image(T_IO_Context *context) } else { - // Hi/Trucolor - Pre_load(context, surface->w, surface->h, file_size ,FORMAT_ALL_IMAGES, PIXEL_SIMPLE, 1); + { + // Hi/Trucolor + Pre_load(context, surface->w, surface->h, file_size ,FORMAT_ALL_IMAGES, PIXEL_SIMPLE, 1); + } for (y_pos=0; y_posHeight; y_pos++) { @@ -938,8 +1016,10 @@ void Load_SDL_Image(T_IO_Context *context) SDL_FreeSurface(surface); } +/// /// Load an arbitrary SDL_Surface. -SDL_Surface * Load_surface(char *full_name) +/// @param gradients Pass the address of a target T_Gradient_array if you want the gradients, NULL otherwise +SDL_Surface * Load_surface(char *full_name, T_Gradient_array *gradients) { SDL_Surface * bmp=NULL; T_IO_Context context; @@ -948,8 +1028,23 @@ SDL_Surface * Load_surface(char *full_name) Load_image(&context); if (context.Surface) + { bmp=context.Surface; - + // Caller wants the gradients: + if (gradients != NULL) + { + int i; + + memset(gradients, 0, sizeof(T_Gradient_array)); + for (i=0; iRange[i].Start=context.Cycle_range[i].Start; + gradients->Range[i].End=context.Cycle_range[i].End; + gradients->Range[i].Inverse=context.Cycle_range[i].Inverse; + gradients->Range[i].Speed=context.Cycle_range[i].Speed; + } + } + } Destroy_context(&context); return bmp; @@ -1011,10 +1106,12 @@ void Emergency_backup(const char *fname, byte *source, int width, int height, T_ void Image_emergency_backup() { +#ifndef NOLAYERS if (Main_backups && Main_backups->Pages && Main_backups->Pages->Nb_layers == 1) - Emergency_backup("a999999.bkp",Main_screen, Main_image_width, Main_image_height, &Main_palette); + Emergency_backup(SAFETYBACKUP_PREFIX_A "999999" BACKUP_FILE_EXTENSION,Main_screen, Main_image_width, Main_image_height, &Main_palette); if (Spare_backups && Spare_backups->Pages && Spare_backups->Pages->Nb_layers == 1) - Emergency_backup("b999999.bkp",Spare_visible_image.Image, Spare_image_width, Spare_image_height, &Spare_palette); + Emergency_backup(SAFETYBACKUP_PREFIX_B "999999" BACKUP_FILE_EXTENSION,Spare_visible_image.Image, Spare_image_width, Spare_image_height, &Spare_palette); +#endif } T_Format * Get_fileformat(byte format) @@ -1022,7 +1119,7 @@ T_Format * Get_fileformat(byte format) unsigned int i; T_Format * safe_default = File_formats; - for (i=0; i < NB_KNOWN_FORMATS; i++) + for (i=0; i < Nb_known_formats(); i++) { if (File_formats[i].Identifier == format) return &(File_formats[i]); @@ -1041,11 +1138,12 @@ byte Get_pixel(T_IO_Context *context, short x, short y) return *(context->Target_address + y*context->Pitch + x); } -/// Cleans up resources (currently: the 24bit buffer) +/// Cleans up resources void Destroy_context(T_IO_Context *context) { free(context->Buffer_image_24b); free(context->Buffer_image); + free(context->Preview_bitmap); memset(context, 0, sizeof(T_IO_Context)); } @@ -1069,6 +1167,8 @@ void Init_context_backup_image(T_IO_Context * context, char *file_name, char *fi /// Setup for loading/saving the current main image void Init_context_layered_image(T_IO_Context * context, char *file_name, char *file_directory) { + int i; + memset(context, 0, sizeof(T_IO_Context)); context->Type = CONTEXT_MAIN_IMAGE; @@ -1091,6 +1191,18 @@ void Init_context_layered_image(T_IO_Context * context, char *file_name, char *f context->Target_address=Main_backups->Pages->Image[0]; context->Pitch=Main_image_width; + // Color cyling ranges: + for (i=0; i<16; i++) + { + if (Main_backups->Pages->Gradients->Range[i].Start!=Main_backups->Pages->Gradients->Range[i].End) + { + context->Cycle_range[context->Color_cycles].Start=Main_backups->Pages->Gradients->Range[i].Start; + context->Cycle_range[context->Color_cycles].End=Main_backups->Pages->Gradients->Range[i].End; + context->Cycle_range[context->Color_cycles].Inverse=Main_backups->Pages->Gradients->Range[i].Inverse; + context->Cycle_range[context->Color_cycles].Speed=Main_backups->Pages->Gradients->Range[i].Speed; + context->Color_cycles++; + } + } } /// Setup for loading/saving the flattened version of current main image @@ -1332,8 +1444,13 @@ int Check_recovery(void) int restored_main; // First check if can write backups - if (Create_lock_file(Config_directory)) +#if defined (__MINT__) + //TODO: enable file lock under Freemint only + return 0; +#else +if (Create_lock_file(Config_directory)) return -1; +#endif Safety_backup_active=1; @@ -1389,7 +1506,7 @@ void Rotate_safety_backups(void) { // Clear a previous save (rotating saves) - sprintf(deleted_file, "%s%c%6.6d.bkp", + sprintf(deleted_file, "%s%c%6.6d" BACKUP_FILE_EXTENSION, Config_directory, Main_safety_backup_prefix, (Uint32)(Main_safety_number + 1000000l - Rotation_safety_backup) % (Uint32)1000000l); @@ -1400,7 +1517,7 @@ void Rotate_safety_backups(void) Main_time_of_safety_backup=now; // Create a new file name and save - sprintf(file_name, "%c%6.6d.bkp", + sprintf(file_name, "%c%6.6d" BACKUP_FILE_EXTENSION, Main_safety_backup_prefix, (Uint32)Main_safety_number); Init_context_backup_image(&context, file_name, Config_directory); @@ -1442,6 +1559,10 @@ void Delete_safety_backups(void) } // Release lock file +#if defined (__MINT__) + //TODO: release file lock under Freemint only +#else Release_lock_file(Config_directory); +#endif } diff --git a/src/loadsave.h b/src/loadsave.h index f82383b9..8fcd6376 100644 --- a/src/loadsave.h +++ b/src/loadsave.h @@ -37,6 +37,14 @@ enum CONTEXT_TYPE { CONTEXT_SURFACE, }; +/// Data for a cycling color series. Heavily cloned from T_Gradient_array. +typedef struct +{ + byte Start; ///< First color + byte End; ///< Last color + byte Inverse; ///< Boolean, true if the gradient goes in descending order + byte Speed; ///< Frequency of cycling, from 1 (slow) to 64 (fast) +} T_Color_cycle; typedef struct { @@ -71,6 +79,9 @@ typedef struct /// Original file directory, stored in GIF file char * Original_file_directory; + byte Color_cycles; + T_Color_cycle Cycle_range[16]; + /// Internal: during load, marks which layer is being loaded. short Current_layer; @@ -87,12 +98,17 @@ typedef struct short Preview_factor_Y; short Preview_pos_X; short Preview_pos_Y; + byte *Preview_bitmap; + byte Preview_usage[256]; // Internal: returned surface for SDL_Surface case SDL_Surface * Surface; } T_IO_Context; +#define PREVIEW_WIDTH 120 +#define PREVIEW_HEIGHT 80 + /// Type of a function that can be called for a T_IO_Context. Kind of a method. typedef void (* Func_IO) (T_IO_Context *); @@ -165,8 +181,10 @@ extern T_Format File_formats[]; /// is too high. void Image_emergency_backup(void); +/// /// Load an arbitrary SDL_Surface. -SDL_Surface * Load_surface(char *full_name); +/// @param gradients Pass the address of a target T_Gradient_array if you want the gradients, NULL otherwise +SDL_Surface * Load_surface(char *full_name, T_Gradient_array *gradients); /* @@ -178,12 +196,8 @@ T_Format * Get_fileformat(byte format); // -- File formats -#ifndef __no_pnglib__ -#define NB_KNOWN_FORMATS 19 ///< Total number of known file formats. -#else -// Without pnglib -#define NB_KNOWN_FORMATS 18 ///< Total number of known file formats. -#endif +/// Total number of known file formats +unsigned int Nb_known_formats(void); // Internal use @@ -210,7 +224,6 @@ void Set_layer(T_IO_Context *context, byte layer); // ================================================================= // This is here and not in fileformats.c because the emergency save uses it... -#pragma pack(1) typedef struct { byte Filler1[6]; @@ -219,7 +232,6 @@ typedef struct byte Filler2[118]; T_Palette Palette; } T_IMG_Header; -#pragma pack() // Data for 24bit loading diff --git a/src/main.c b/src/main.c index 54ce1bdb..3ba10ff9 100644 --- a/src/main.c +++ b/src/main.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2009 Pasi Kallinen Copyright 2008 Peter Gordon Copyright 2008 Franck Charlet @@ -40,7 +41,7 @@ // There is no WM on the GP2X... -#ifndef __GP2X__ +#if !defined(__GP2X__) && !defined(__WIZ__) && !defined(__CAANOO__) #include #endif @@ -65,11 +66,14 @@ #include "brush.h" #include "palette.h" #include "realpath.h" +#include "input.h" #if defined(__WIN32__) #include #include #define chdir(dir) SetCurrentDirectory(dir) +#elif defined (__MINT__) + #include #elif defined(__macosx__) #import #import @@ -85,6 +89,8 @@ extern DECLSPEC int SDLCALL SDL_putenv(const char *variable); #endif +extern char Program_version[]; // generated in pversion.c + //--- Affichage de la syntaxe, et de la liste des modes vidéos disponibles --- void Display_syntax(void) { @@ -139,7 +145,7 @@ void Error_function(int error_code, const char *filename, int line_number, const for (index=0;index<=255;index++) temp_palette[index].R=255; Set_palette(temp_palette); - SDL_Delay(500); + Delay_with_active_mouse(50); // Half a second of red flash Set_palette(Main_palette); } else @@ -400,22 +406,39 @@ int Analyze_command_line(int argc, char * argv[], char *main_filename, char *mai return file_in_command_line; } +// Compile-time assertions: +#define CT_ASSERT(e) extern char (*ct_assert(void)) [sizeof(char[1 - 2*!(e)])] + +// This line will raise an error at compile time +// when sizeof(T_Components) is not 3. +CT_ASSERT(sizeof(T_Components)==3); + +// This line will raise an error at compile time +// when sizeof(T_Palette) is not 768. +CT_ASSERT(sizeof(T_Palette)==768); + // ------------------------ Initialiser le programme ------------------------- // Returns 0 on fail int Init_program(int argc,char * argv[]) -{ +{ int temp; int starting_videomode; static char program_directory[MAX_PATH_CHARACTERS]; T_Gui_skin *gfx; int file_in_command_line; + T_Gradient_array initial_gradients; static char main_filename [MAX_PATH_CHARACTERS]; static char main_directory[MAX_PATH_CHARACTERS]; static char spare_filename [MAX_PATH_CHARACTERS]; static char spare_directory[MAX_PATH_CHARACTERS]; - - - + + #if defined(__MINT__) + printf("===============================\n"); + printf(" /|\\ GrafX2 %.19s\n", Program_version); + printf(" compilation date: %.16s\n", __DATE__); + printf("===============================\n"); + #endif + // On crée dès maintenant les descripteurs des listes de pages pour la page // principale et la page de brouillon afin que leurs champs ne soient pas // invalide lors des appels aux multiples fonctions manipulées à @@ -431,9 +454,12 @@ int Init_program(int argc,char * argv[]) Set_data_directory(program_directory,Data_directory); // Choose directory for settings (read/write) Set_config_directory(program_directory,Config_directory); - - // On détermine le répertoire courant: +#if defined(__MINT__) + strcpy(Main_current_directory,program_directory); +#else +// On détermine le répertoire courant: getcwd(Main_current_directory,256); +#endif // On en profite pour le mémoriser dans le répertoire principal: strcpy(Initial_directory,Main_current_directory); @@ -473,8 +499,6 @@ int Init_program(int argc,char * argv[]) // On initialise d'ot' trucs Main_offset_X=0; Main_offset_Y=0; - Old_main_offset_X=0; - Old_main_offset_Y=0; Main_separator_position=0; Main_X_zoom=0; Main_separator_proportion=INITIAL_SEPARATOR_PROPORTION; @@ -486,8 +510,6 @@ int Init_program(int argc,char * argv[]) Main_magnifier_offset_Y=0; Spare_offset_X=0; Spare_offset_Y=0; - Old_spare_offset_X=0; - Old_spare_offset_Y=0; Spare_separator_position=0; Spare_X_zoom=0; Spare_separator_proportion=INITIAL_SEPARATOR_PROPORTION; @@ -497,62 +519,27 @@ int Init_program(int argc,char * argv[]) Spare_magnifier_width=0; Spare_magnifier_offset_X=0; Spare_magnifier_offset_Y=0; - Keyboard_click_allowed = 0; + Keyboard_click_allowed = 1; - Main_safety_backup_prefix = 'a'; - Spare_safety_backup_prefix = 'b'; + Main_safety_backup_prefix = SAFETYBACKUP_PREFIX_A[0]; + Spare_safety_backup_prefix = SAFETYBACKUP_PREFIX_B[0]; Main_time_of_safety_backup = 0; Spare_time_of_safety_backup = 0; // SDL - if(SDL_Init(SDL_INIT_TIMER|SDL_INIT_VIDEO|SDL_INIT_JOYSTICK) < 0) + if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_JOYSTICK) < 0) { // The program can't continue without that anyway printf("Couldn't initialize SDL.\n"); return(0); } - + Joystick = SDL_JoystickOpen(0); SDL_EnableKeyRepeat(250, 32); SDL_EnableUNICODE(SDL_ENABLE); SDL_WM_SetCaption("GrafX2","GrafX2"); - - { - // Routine pour définir l'icone. - char icon_path[MAX_PATH_CHARACTERS]; - SDL_Surface * icon; - sprintf(icon_path, "%s%s", Data_directory, "gfx2.gif"); - icon = IMG_Load(icon_path); - if (icon && icon->w == 32 && icon->h == 32) - { - Uint32 pink; - pink = SDL_MapRGB(icon->format, 255, 0, 255); - - if (icon->format->BitsPerPixel == 8) - { - SDL_SetColorKey(icon, SDL_SRCCOLORKEY, pink); - SDL_WM_SetIcon(icon,NULL); - } - else - { - byte *icon_mask; - int x,y; - - icon_mask=malloc(128); - memset(icon_mask,0,128); - for (y=0;y<32;y++) - for (x=0;x<32;x++) - if (Get_SDL_pixel_hicolor(icon, x, y) != pink) - icon_mask[(y*32+x)/8] |=0x80>>(x&7); - SDL_WM_SetIcon(icon,icon_mask); - free(icon_mask); - icon_mask = NULL; - } - - SDL_FreeSurface(icon); - } - } + Define_icon(); // Texte Init_text(); @@ -574,7 +561,6 @@ int Init_program(int argc,char * argv[]) // Données sur le pinceau: Paintbrush_X=0; Paintbrush_Y=0; - Paintbrush_shape=PAINTBRUSH_SHAPE_ROUND; Paintbrush_hidden=0; // On initialise tout ce qui concerne les opérations et les effets @@ -634,6 +620,25 @@ int Init_program(int argc,char * argv[]) Windows_open=0; + // Paintbrush + if (!(Paintbrush_sprite=(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE))) Error(ERROR_MEMORY); + + // Load preset paintbrushes (uses Paintbrush_ variables) + Init_paintbrushes(); + + // Set a valid paintbrush afterwards + *Paintbrush_sprite=1; + Paintbrush_width=1; + Paintbrush_height=1; + Paintbrush_offset_X=0; + Paintbrush_offset_Y=0; + Paintbrush_shape=PAINTBRUSH_SHAPE_ROUND; + + #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) + // Prefer cycling active by default + Cycling_mode=1; + #endif + // Charger la configuration des touches Set_config_defaults(); @@ -662,10 +667,10 @@ int Init_program(int argc,char * argv[]) Help_position=0; // Load sprites, palette etc. - gfx = Load_graphics(Config.Skin_file); + gfx = Load_graphics(Config.Skin_file, &initial_gradients); if (gfx == NULL) { - gfx = Load_graphics("skin_DPaint.png"); + gfx = Load_graphics(DEFAULT_SKIN_FILENAME, &initial_gradients); if (gfx == NULL) { printf("%s", Gui_loading_error_message); @@ -678,7 +683,10 @@ int Init_program(int argc,char * argv[]) // Gfx->Default_palette[MC_Dark] =Config.Fav_menu_colors[1]; // Gfx->Default_palette[MC_Light]=Config.Fav_menu_colors[2]; // Gfx->Default_palette[MC_White]=Config.Fav_menu_colors[3]; -// Compute_optimal_menu_colors(Gfx->Default_palette); + + // Even when using the skin's palette, if RGB range is small + // the colors will be unusable. + Compute_optimal_menu_colors(Gfx->Default_palette); // Infos sur les trames (Sieve) Sieve_mode=0; @@ -686,9 +694,9 @@ int Init_program(int argc,char * argv[]) // Font if (!(Menu_font=Load_font(Config.Font_file))) - if (!(Menu_font=Load_font("font_DPaint.png"))) + if (!(Menu_font=Load_font(DEFAULT_FONT_FILENAME))) { - printf("Unable to open the default font file: %s\n", "font_Classic.png"); + printf("Unable to open the default font file: %s\n", DEFAULT_FONT_FILENAME); Error(ERROR_GUI_MISSING); } @@ -701,11 +709,6 @@ int Init_program(int argc,char * argv[]) if (!(Brush =(byte *)malloc( 1* 1))) Error(ERROR_MEMORY); if (!(Smear_brush =(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE))) Error(ERROR_MEMORY); - // Pinceau - if (!(Paintbrush_sprite=(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE))) Error(ERROR_MEMORY); - *Paintbrush_sprite=1; - Paintbrush_width=1; - Paintbrush_height=1; starting_videomode=Current_resolution; Horizontal_line_buffer=NULL; @@ -731,6 +734,9 @@ int Init_program(int argc,char * argv[]) SetWindowPos(pInfo.window, 0, Config.Window_pos_x, Config.Window_pos_y, 0, 0, SWP_NOSIZE); } } + + // Open a console for debugging... + //ActivateConsole(); #endif Main_image_width=Screen_width/Pixel_width; @@ -745,15 +751,29 @@ int Init_program(int argc,char * argv[]) // Nettoyage de l'écran virtuel (les autres recevront celui-ci par copie) memset(Main_screen,0,Main_image_width*Main_image_height); + // Now that the backup system is there, we can store the gradients. + memcpy(Main_backups->Pages->Gradients->Range, initial_gradients.Range, sizeof(initial_gradients.Range)); + memcpy(Spare_backups->Pages->Gradients->Range, initial_gradients.Range, sizeof(initial_gradients.Range)); + + Gradient_function=Gradient_basic; + Gradient_lower_bound=0; + Gradient_upper_bound=0; + Gradient_random_factor=1; + Gradient_bounds_range=1; + + Current_gradient=0; + // Initialisation de diverses variables par calcul: Compute_magnifier_data(); Compute_limits(); Compute_paintbrush_coordinates(); // On affiche le menu: - Display_menu(); Display_paintbrush_in_menu(); - Display_sprite_in_menu(BUTTON_PAL_LEFT,18+(Config.Palette_vertical!=0)); + Display_sprite_in_menu(BUTTON_PAL_LEFT,Config.Palette_vertical?MENU_SPRITE_VERTICAL_PALETTE_SCROLL:-1); + Display_menu(); + Draw_menu_button(BUTTON_PAL_LEFT,BUTTON_RELEASED); + Draw_menu_button(BUTTON_PAL_RIGHT,BUTTON_RELEASED); // On affiche le curseur pour débutter correctement l'état du programme: Display_cursor(); @@ -770,8 +790,11 @@ int Init_program(int argc,char * argv[]) // On initialise la brosse initiale à 1 pixel blanc: Brush_width=1; Brush_height=1; + for (temp=0;temp<256;temp++) + Brush_colormap[temp]=temp; Capture_brush(0,0,0,0,0); *Brush=MC_White; + *Brush_original_pixels=MC_White; // Test de recuperation de fichiers sauvés switch (Check_recovery()) @@ -843,6 +866,9 @@ int Init_program(int argc,char * argv[]) break; } } + + Allow_drag_and_drop(1); + return(1); } @@ -908,6 +934,12 @@ void Program_shutdown(void) Error(ERROR_MISSING_DIRECTORY); SDL_Quit(); + + #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) + chdir("/usr/gp2x"); + execl("/usr/gp2x/gp2xmenu", "/usr/gp2x/gp2xmenu", NULL); + #endif + } diff --git a/src/misc.c b/src/misc.c index de374850..932cde1d 100644 --- a/src/misc.c +++ b/src/misc.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2007 Adrien Destugues @@ -177,7 +178,8 @@ void Wait_end_of_click(void) { // On désactive tous les raccourcis clavier - while(Mouse_K) if(!Get_input()) SDL_Delay(20); + while(Mouse_K) + Get_input(20); } void Clear_current_image_with_stencil(byte color, byte * stencil) @@ -339,7 +341,7 @@ void Rotate_270_deg_lowlevel(byte * source, byte * dest, short width, short heig // Replace une couleur par une autre dans un buffer -void Remap_general_lowlevel(byte * conversion_table,byte * buffer,short width,short height,short buffer_width) +void Remap_general_lowlevel(byte * conversion_table,byte * in_buffer, byte *out_buffer,short width,short height,short buffer_width) { int dx,cx; @@ -349,17 +351,19 @@ void Remap_general_lowlevel(byte * conversion_table,byte * buffer,short width,sh // Pour chaque pixel for(cx=width;cx>0;cx--) { - *buffer = conversion_table[*buffer]; - buffer++; + *out_buffer = conversion_table[*in_buffer]; + in_buffer++; + out_buffer++; } - buffer += buffer_width-width; + in_buffer += buffer_width-width; + out_buffer += buffer_width-width; } } void Copy_image_to_brush(short start_x,short start_y,short Brush_width,short Brush_height,word image_width) { byte* src=start_y*image_width+start_x+Main_backups->Pages->Image[Main_current_layer]; //Adr départ image (ESI) - byte* dest=Brush; //Adr dest brosse (EDI) + byte* dest=Brush_original_pixels; //Adr dest brosse (EDI) int dx; for (dx=Brush_height;dx!=0;dx--) @@ -499,6 +503,22 @@ byte Effect_substractive_colorize(word x,word y,byte color) blueTimer_start) Timer_state=1; @@ -659,17 +679,6 @@ void Rescale(byte *src_buffer, short src_width, short src_height, byte *dst_buff } } -void Slider_timer(byte speed) - //Boucle d'attente pour faire bouger les scrollbars à une vitesse correcte -{ - Uint32 end; - byte original_mouse_k = Mouse_K; - end = SDL_GetTicks() + speed*10; - do - { - if (!Get_input()) SDL_Delay(20); - } while (Mouse_K == original_mouse_k && SDL_GetTicks() +#elif defined(__MINT__) + #include + #include #elif defined(__SKYOS__) #include #else #include // sysinfo() for free RAM #endif +#if defined (__MINT__) +// atari have two kinds of memory +// standard and fast ram +void Atari_Memory_free(unsigned long *stRam,unsigned long *ttRam){ + //TODO: return STRAM/TT-RAM + unsigned long mem=0; + *stRam=Mxalloc(-1L,0); + *ttRam = Mxalloc(-1L,1); +} +#else // Indique quelle est la mémoire disponible unsigned long Memory_free(void) { @@ -778,6 +800,8 @@ unsigned long Memory_free(void) return info.freeram*info.mem_unit; #endif } +#endif + // Arrondir un nombre réel à la valeur entière la plus proche diff --git a/src/misc.h b/src/misc.h index bd365211..cee6f39c 100644 --- a/src/misc.h +++ b/src/misc.h @@ -33,7 +33,7 @@ #define SWAP_PBYTES(a,b) { byte * c=a; a=b; b=c;} void Copy_image_to_brush(short start_x,short start_y,short Brush_width,short Brush_height,word image_width); -void Remap_general_lowlevel(byte * conversion_table,byte * buffer,short width,short height,short buffer_width); +void Remap_general_lowlevel(byte * conversion_table,byte * in_buffer, byte *out_buffer,short width,short height,short buffer_width); void Scroll_picture(byte * main_src, byte * main_dest, short x_offset,short y_offset); void Wait_end_of_click(void); void Set_color(byte color, byte red, byte green, byte blue); @@ -42,7 +42,6 @@ void Palette_256_to_64(T_Palette palette); void Palette_64_to_256(T_Palette palette); void Clear_current_image(byte color); void Clear_current_image_with_stencil(byte color, byte * stencil); -void Slider_timer(byte speed); dword Round_div(dword numerator,dword divisor); word Count_used_colors(dword * usage); word Count_used_colors_area(dword* usage, word start_x, word start_y, word width, word height); @@ -86,6 +85,7 @@ void Replace_colors_within_limits(byte * replace_table); byte Effect_interpolated_colorize (word x,word y,byte color); byte Effect_additive_colorize (word x,word y,byte color); byte Effect_substractive_colorize(word x,word y,byte color); +byte Effect_alpha_colorize(word x,word y,byte color); byte Effect_sieve(word x,word y); /// diff --git a/src/miscfileformats.c b/src/miscfileformats.c index 28453236..dd3c518c 100644 --- a/src/miscfileformats.c +++ b/src/miscfileformats.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2009 Petter Lindquist Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet @@ -368,7 +369,8 @@ void Load_PKM(T_IO_Context * context) Compteur_de_donnees_packees=0; Compteur_de_pixels=0; - Taille_pack=(file_size)-sizeof(T_PKM_Header)-header.Jump; + // Header size is 780 + Taille_pack=(file_size)-780-header.Jump; // Boucle de décompression: while ( (Compteur_de_pixels>1)*header1.Height)!=size ) ) { // Tentative de reconnaissance de la signature des nouveaux fichiers @@ -735,7 +735,7 @@ void Load_CEL(T_IO_Context * context) short y_pos; byte last_byte=0; long file_size; - const long int header_size = (long int)(sizeof(header1.Width)+sizeof(header1.Height)); + const long int header_size = 4; File_error=0; Get_full_filename(filename, context->File_name, context->File_directory); @@ -775,7 +775,7 @@ void Load_CEL(T_IO_Context * context) // On réessaye avec le nouveau format fseek(file,0,SEEK_SET); - if (Read_bytes(file,header2.Signature,sizeof(header2.Signature)) + if (Read_bytes(file,header2.Signature,4) && Read_byte(file,&(header2.Kind)) && Read_byte(file,&(header2.Nb_bits)) && Read_word_le(file,&(header2.Filler1)) @@ -783,7 +783,7 @@ void Load_CEL(T_IO_Context * context) && Read_word_le(file,&(header2.Height)) && Read_word_le(file,&(header2.X_offset)) && Read_word_le(file,&(header2.Y_offset)) - && Read_bytes(file,header2.Filler2,sizeof(header2.Filler2)) + && Read_bytes(file,header2.Filler2,16) ) { // Chargement d'un fichier CEL avec signature (nouveaux fichiers) @@ -942,7 +942,7 @@ void Save_CEL(T_IO_Context * context) for (x_pos=0;x_pos<16;x_pos++) // Initialisation du filler 2 (?) header2.Filler2[x_pos]=0; - if (Write_bytes(file,header2.Signature,sizeof(header2.Signature)) + if (Write_bytes(file,header2.Signature,4) && Write_byte(file,header2.Kind) && Write_byte(file,header2.Nb_bits) && Write_word_le(file,header2.Filler1) @@ -950,7 +950,7 @@ void Save_CEL(T_IO_Context * context) && Write_word_le(file,header2.Height) && Write_word_le(file,header2.X_offset) && Write_word_le(file,header2.Y_offset) - && Write_bytes(file,header2.Filler2,sizeof(header2.Filler2)) + && Write_bytes(file,header2.Filler2,14) ) { // Sauvegarde de l'image @@ -974,7 +974,6 @@ void Save_CEL(T_IO_Context * context) //////////////////////////////////// KCF //////////////////////////////////// -#pragma pack(1) typedef struct { struct @@ -986,7 +985,6 @@ typedef struct } color[16]; } Palette[10]; } T_KCF_Header; -#pragma pack() // -- Tester si un fichier est au format KCF -------------------------------- @@ -994,7 +992,7 @@ void Test_KCF(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; - T_KCF_Header buffer; + T_KCF_Header header1; T_CEL_Header2 header2; int pal_index; int color_index; @@ -1003,18 +1001,22 @@ void Test_KCF(T_IO_Context * context) Get_full_filename(filename, context->File_name, context->File_directory); if ((file=fopen(filename, "rb"))) { - if (File_length_file(file)==sizeof(T_KCF_Header)) + if (File_length_file(file)==320) { - Read_bytes(file,&buffer,sizeof(T_KCF_Header)); + for (pal_index=0;pal_index<10 && !File_error;pal_index++) + for (color_index=0;color_index<16 && !File_error;color_index++) + if (!Read_byte(file,&header1.Palette[pal_index].color[color_index].Byte1) || + !Read_byte(file,&header1.Palette[pal_index].color[color_index].Byte2)) + File_error=1; // On vérifie une propriété de la structure de palette: for (pal_index=0;pal_index<10;pal_index++) for (color_index=0;color_index<16;color_index++) - if ((buffer.Palette[pal_index].color[color_index].Byte2>>4)!=0) + if ((header1.Palette[pal_index].color[color_index].Byte2>>4)!=0) File_error=1; } else { - if (Read_bytes(file,header2.Signature,sizeof(header2.Signature)) + if (Read_bytes(file,header2.Signature,4) && Read_byte(file,&(header2.Kind)) && Read_byte(file,&(header2.Nb_bits)) && Read_word_le(file,&(header2.Filler1)) @@ -1022,7 +1024,7 @@ void Test_KCF(T_IO_Context * context) && Read_word_le(file,&(header2.Height)) && Read_word_le(file,&(header2.X_offset)) && Read_word_le(file,&(header2.Y_offset)) - && Read_bytes(file,header2.Filler2,sizeof(header2.Filler2)) + && Read_bytes(file,header2.Filler2,14) ) { if (memcmp(header2.Signature,"KiSS",4)==0) @@ -1049,7 +1051,7 @@ void Load_KCF(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; - T_KCF_Header buffer; + T_KCF_Header header1; T_CEL_Header2 header2; byte bytes[3]; int pal_index; @@ -1063,11 +1065,16 @@ void Load_KCF(T_IO_Context * context) if ((file=fopen(filename, "rb"))) { file_size=File_length_file(file); - if (file_size==sizeof(T_KCF_Header)) + if (file_size==320) { // Fichier KCF à l'ancien format + for (pal_index=0;pal_index<10 && !File_error;pal_index++) + for (color_index=0;color_index<16 && !File_error;color_index++) + if (!Read_byte(file,&header1.Palette[pal_index].color[color_index].Byte1) || + !Read_byte(file,&header1.Palette[pal_index].color[color_index].Byte2)) + File_error=1; - if (Read_bytes(file,&buffer,sizeof(T_KCF_Header))) + if (!File_error) { // Pre_load(context, ?); // Pas possible... pas d'image... @@ -1079,9 +1086,9 @@ void Load_KCF(T_IO_Context * context) for (color_index=0;color_index<16;color_index++) { index=16+(pal_index*16)+color_index; - context->Palette[index].R=((buffer.Palette[pal_index].color[color_index].Byte1 >> 4) << 4); - context->Palette[index].B=((buffer.Palette[pal_index].color[color_index].Byte1 & 15) << 4); - context->Palette[index].G=((buffer.Palette[pal_index].color[color_index].Byte2 & 15) << 4); + context->Palette[index].R=((header1.Palette[pal_index].color[color_index].Byte1 >> 4) << 4); + context->Palette[index].B=((header1.Palette[pal_index].color[color_index].Byte1 & 15) << 4); + context->Palette[index].G=((header1.Palette[pal_index].color[color_index].Byte2 & 15) << 4); } for (index=0;index<16;index++) @@ -1100,7 +1107,7 @@ void Load_KCF(T_IO_Context * context) { // Fichier KCF au nouveau format - if (Read_bytes(file,header2.Signature,sizeof(header2.Signature)) + if (Read_bytes(file,header2.Signature,4) && Read_byte(file,&(header2.Kind)) && Read_byte(file,&(header2.Nb_bits)) && Read_word_le(file,&(header2.Filler1)) @@ -1108,7 +1115,7 @@ void Load_KCF(T_IO_Context * context) && Read_word_le(file,&(header2.Height)) && Read_word_le(file,&(header2.X_offset)) && Read_word_le(file,&(header2.Y_offset)) - && Read_bytes(file,header2.Filler2,sizeof(header2.Filler2)) + && Read_bytes(file,header2.Filler2,14) ) { // Pre_load(context, ?); // Pas possible... pas d'image... @@ -1168,7 +1175,7 @@ void Save_KCF(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; - T_KCF_Header buffer; + T_KCF_Header header1; T_CEL_Header2 header2; byte bytes[3]; int pal_index; @@ -1196,12 +1203,16 @@ void Save_KCF(T_IO_Context * context) for (color_index=0;color_index<16;color_index++) { index=16+(pal_index*16)+color_index; - buffer.Palette[pal_index].color[color_index].Byte1=((context->Palette[index].R>>4)<<4) | (context->Palette[index].B>>4); - buffer.Palette[pal_index].color[color_index].Byte2=context->Palette[index].G>>4; + header1.Palette[pal_index].color[color_index].Byte1=((context->Palette[index].R>>4)<<4) | (context->Palette[index].B>>4); + header1.Palette[pal_index].color[color_index].Byte2=context->Palette[index].G>>4; } - if (! Write_bytes(file,&buffer,sizeof(T_KCF_Header))) - File_error=1; + // Write all + for (pal_index=0;pal_index<10 && !File_error;pal_index++) + for (color_index=0;color_index<16 && !File_error;color_index++) + if (!Write_byte(file,header1.Palette[pal_index].color[color_index].Byte1) || + !Write_byte(file,header1.Palette[pal_index].color[color_index].Byte2)) + File_error=1; } else { @@ -1218,7 +1229,7 @@ void Save_KCF(T_IO_Context * context) for (index=0;index<16;index++) // Initialisation du filler 2 (?) header2.Filler2[index]=0; - if (!Write_bytes(file,header2.Signature,sizeof(header2.Signature)) + if (!Write_bytes(file,header2.Signature,4) || !Write_byte(file,header2.Kind) || !Write_byte(file,header2.Nb_bits) || !Write_word_le(file,header2.Filler1) @@ -1226,7 +1237,7 @@ void Save_KCF(T_IO_Context * context) || !Write_word_le(file,header2.Height) || !Write_word_le(file,header2.X_offset) || !Write_word_le(file,header2.Y_offset) - || !Write_bytes(file,header2.Filler2,sizeof(header2.Filler2)) + || !Write_bytes(file,header2.Filler2,14) ) File_error=1; @@ -1322,17 +1333,29 @@ void PI1_decode_palette(byte * src,byte * palette) // Low High // VVVV RRRR | 0000 BBBB // 0321 0321 | 0321 - + ip=0; for (i=0;i<16;i++) { - w=((word)src[(i*2)+1]<<8) | src[(i*2)+0]; - - // Traitement des couleurs rouge, verte et bleue: - palette[ip++]=(((w & 0x0007) << 1) | ((w & 0x0008) >> 3)) << 4; - palette[ip++]=(((w & 0x7000) >> 11) | ((w & 0x8000) >> 15)) << 4; - palette[ip++]=(((w & 0x0700) >> 7) | ((w & 0x0800) >> 11)) << 4; - } + #if SDL_BYTEORDER == SDL_LIL_ENDIAN + + w=(((word)src[(i*2)+1]<<8) | (src[(i*2)+0])); + + // Traitement des couleurs rouge, verte et bleue: + palette[ip++]=(((w & 0x0007) << 1) | ((w & 0x0008) >> 3)) << 4; + palette[ip++]=(((w & 0x7000) >> 11) | ((w & 0x8000) >> 15)) << 4; + palette[ip++]=(((w & 0x0700) >> 7) | ((w & 0x0800) >> 11)) << 4; + + #else + w=(((word)src[(i*2+1)])|(((word)src[(i*2)])<<8)); + + palette[ip++] = (((w & 0x0700)>>7) | ((w & 0x0800) >> 7))<<4 ; + palette[ip++]=(((w & 0x0070)>>3) | ((w & 0x0080) >> 3))<<4 ; + palette[ip++] = (((w & 0x0007)<<1) | ((w & 0x0008)))<<4 ; + #endif + + + } } //// CODAGE de la PALETTE //// @@ -1345,20 +1368,31 @@ void PI1_code_palette(byte * palette,byte * dest) // Schéma d'un word = // - // Low High + // Low High // VVVV RRRR | 0000 BBBB // 0321 0321 | 0321 - + ip=0; for (i=0;i<16;i++) { + #if SDL_BYTEORDER == SDL_LIL_ENDIAN + // Traitement des couleurs rouge, verte et bleue: w =(((word)(palette[ip]>>2) & 0x38) >> 3) | (((word)(palette[ip]>>2) & 0x04) << 1); ip++; w|=(((word)(palette[ip]>>2) & 0x38) << 9) | (((word)(palette[ip]>>2) & 0x04) << 13); ip++; w|=(((word)(palette[ip]>>2) & 0x38) << 5) | (((word)(palette[ip]>>2) & 0x04) << 9); ip++; - + dest[(i*2)+0]=w & 0x00FF; dest[(i*2)+1]=(w>>8); + #else + + w=(((word)(palette[ip]<<3))&0x0700);ip++; + w|=(((word)(palette[ip]>>1))&0x0070);ip++; + w|=(((word)(palette[ip]>>5))&0x0007);ip++; + + dest[(i*2)+1]=w & 0x00FF; + dest[(i*2)+0]=(w>>8); + #endif } } @@ -2472,13 +2506,13 @@ int Save_C64_window(byte *saveWhat, byte *loadAddr) Print_in_window(13,18,"Data:",MC_Dark,MC_Light); what=Window_set_dropdown_button(10,28,90,15,70,what_label[*saveWhat],1, 0, 1, LEFT_SIDE,0); // 3 Window_dropdown_clear_items(what); - for (i=0; iR*26*color->R + + 55*color->G*55*color->G + + 19*color->B*19*color->B; +} + // Conversion table handlers // The conversion table is built after a run of the median cut algorithm and is // used to find the best color index for a given (RGB) color. GIMP avoids @@ -1342,6 +1355,10 @@ static const byte precision_24b[]= // Give this one a 24b source, get back the 256c bitmap and its palette int Convert_24b_bitmap_to_256(T_Bitmap256 dest,T_Bitmap24B source,int width,int height,T_Components * palette) { + #if defined(__GP2X__) || defined(__gp2x__) || defined(__WIZ__) || defined(__CAANOO__) + return Convert_24b_bitmap_to_256_fast(dest, source, width, height, palette); + + #else T_Conversion_table * table; // table de conversion int ip; // index de précision pour la conversion @@ -1363,7 +1380,36 @@ int Convert_24b_bitmap_to_256(T_Bitmap256 dest,T_Bitmap24B source,int width,int } else return 1; + + #endif } +//Really small, fast and ugly converter(just for handhelds) +#include "global.h" +#include "limits.h" +#include "engine.h" +#include "windows.h" +extern void Set_palette_fake_24b(T_Palette palette); + +/// Really small, fast and dirty convertor(just for handhelds) +int Convert_24b_bitmap_to_256_fast(T_Bitmap256 dest,T_Bitmap24B source,int width,int height,T_Components * palette) +{ + int size; + + Set_palette_fake_24b(palette); + + size = width*height; + + while(size--) + { + //Set palette color index to destination bitmap + *dest = ((source->R >> 5) << 5) | + ((source->G >> 5) << 2) | + ((source->B >> 6)); + source++; + dest++; + } + return 0; +} diff --git a/src/op_c.h b/src/op_c.h index ead494db..76b544a2 100644 --- a/src/op_c.h +++ b/src/op_c.h @@ -160,6 +160,7 @@ void CT_set(T_Conversion_table * t,int r,int g,int b,byte i); void RGB_to_HSL(int r, int g,int b, byte* h, byte*s, byte* l); void HSL_to_RGB(byte h, byte s, byte l, byte* r, byte* g, byte* b); +long Perceptual_lightness(T_Components *color); ///////////////////////////////////////////////////////////////////////////// /////////////////////////////// Méthodes de gestion des tables d'occurence // diff --git a/src/operatio.c b/src/operatio.c index 2c2bf4a1..d822fe29 100644 --- a/src/operatio.c +++ b/src/operatio.c @@ -36,6 +36,7 @@ #include "sdlscreen.h" #include "brush.h" #include "windows.h" +#include "input.h" // PI is NOT part of math.h according to C standards... #if defined(__GP2X__) || defined(__VBCC__) @@ -53,11 +54,12 @@ void Start_operation_stack(word new_operation) // On mémorise l'opération précédente si on démarre une interruption switch(new_operation) { - case OPERATION_MAGNIFY : - case OPERATION_COLORPICK : - case OPERATION_GRAB_BRUSH : - case OPERATION_POLYBRUSH : - case OPERATION_STRETCH_BRUSH : + case OPERATION_MAGNIFY: + case OPERATION_COLORPICK: + case OPERATION_RMB_COLORPICK: + case OPERATION_GRAB_BRUSH: + case OPERATION_POLYBRUSH: + case OPERATION_STRETCH_BRUSH: case OPERATION_ROTATE_BRUSH: Operation_before_interrupt=Current_operation; // On passe à l'operation demandée @@ -226,6 +228,9 @@ void Freehand_mode1_2_0(void) // // Souris effacée: Oui { + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); Backup(); Shade_table=Shade_table_right; @@ -322,6 +327,9 @@ void Freehand_mode2_2_0(void) // // Souris effacée: Oui { + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); Backup(); Shade_table=Shade_table_right; @@ -390,6 +398,9 @@ void Freehand_Mode3_2_0(void) // // Souris effacée: Oui { + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); Backup(); Shade_table=Shade_table_right; @@ -422,6 +433,9 @@ void Line_12_0(void) // Début du tracé d'une ligne (premier clic) { + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); Backup(); Paintbrush_shape_before_operation=Paintbrush_shape; @@ -480,9 +494,7 @@ void Line_12_5(void) // On corrige les coordonnées de la ligne si la touche shift est appuyée... if(SDL_GetModState() & KMOD_SHIFT) - { Clamp_coordinates_regular_angle(start_x,start_y,&cursor_x,&cursor_y); - } // On vient de bouger if ((cursor_x!=end_x) || (cursor_y!=end_y)) @@ -557,11 +569,11 @@ void Line_0_5(void) } -/////////////////////////////////////////////////////////// OPERATION_K_LIGNE +/////////////////////////////////////////////////////////// OPERATION_K_LINE void K_line_12_0(void) -// Opération : OPERATION_K_LIGNE +// Opération : OPERATION_K_LINE // Click Souris: 1 ou 2 // Taille_Pile : 0 // @@ -569,6 +581,9 @@ void K_line_12_0(void) { byte color; + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); Backup(); Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; @@ -594,7 +609,7 @@ void K_line_12_0(void) void K_line_12_6(void) -// Opération : OPERATION_K_LIGNE +// Opération : OPERATION_K_LINE // Click Souris: 1 ou 2 | 0 // Taille_Pile : 6 | 7 // @@ -634,7 +649,7 @@ void K_line_12_6(void) void K_line_0_6(void) -// Opération : OPERATION_K_LIGNE +// Opération : OPERATION_K_LINE // Click Souris: 0 // Taille_Pile : 6 // @@ -684,7 +699,7 @@ void K_line_0_6(void) void K_line_12_7(void) -// Opération : OPERATION_K_LIGNE +// Opération : OPERATION_K_LINE // Click Souris: 1 ou 2 // Taille_Pile : 7 // @@ -745,6 +760,9 @@ void Rectangle_12_0(void) // // Souris effacée: Oui { + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); if ((Config.Coords_rel) && (Menu_is_visible)) @@ -916,6 +934,9 @@ void Circle_12_0(void) // // Souris effacée: Oui { + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); Backup(); @@ -1090,6 +1111,9 @@ void Ellipse_12_0(void) // // Souris effacée: Oui { + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); Backup(); @@ -1284,9 +1308,12 @@ void Fill_2_0(void) // Click Souris: 2 // Taille_Pile : 0 // -// Souris effacée: Oui +// Souris effacée: Non // { + if (Rightclick_colorpick(1)) + return; + Hide_cursor(); // Pas besoin d'initialiser le début d'opération car le Smear n'affecte pas // le Fill, et on se fout de savoir si on est dans la partie gauche ou @@ -1309,7 +1336,7 @@ void Replace_1_0(void) // Click Souris: 1 // Taille_Pile : 0 // -// Souris effacée: Oui +// Souris effacée: Non // { Hide_cursor(); @@ -1331,9 +1358,12 @@ void Replace_2_0(void) // Click Souris: 2 // Taille_Pile : 0 // -// Souris effacée: Oui +// Souris effacée: Non // { + if (Rightclick_colorpick(1)) + return; + Hide_cursor(); // Pas besoin d'initialiser le début d'opération car le Smear n'affecte pas // le Replace, et on se fout de savoir si on est dans la partie gauche ou @@ -1433,6 +1463,9 @@ void Curve_34_points_2_0(void) // Souris effacée: Oui // { + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); Backup(); Shade_table=Shade_table_right; @@ -1711,17 +1744,17 @@ void Compute_3_point_curve(short x1, short y1, short x4, short y4, float cx,cy; // Centre de (x1,y1) et (x4,y4) float bx,by; // Intersect. des dtes ((x1,y1),(x2,y2)) et ((x3,y3),(x4,y4)) - cx=(float)(x1+x4)/2.0; // P1*--_ Légende: - cy=(float)(y1+y4)/2.0; // · \·· P2 -_\|/ : courbe - // · \ ·*· * : point important - bx=cx+((8.0/3.0)*(Paintbrush_X-cx));// · | ·· · : pointillÚ + cx=(float)(x1+x4)/2.0; // P1*--_ Legend: + cy=(float)(y1+y4)/2.0; // · \·· P2 -_\|/ : curve + // · \ ·*· * : important point + bx=cx+((8.0/3.0)*(Paintbrush_X-cx));// · | ·· · : dotted line by=cy+((8.0/3.0)*(Paintbrush_Y-cy));// · |P ·· B - // C *·····*·········* P=Pos. du pinceau - *x2=Round((bx+x1)/2.0); // · | ·· C=milieu de [P1,P4] - *y2=Round((by+y1)/2.0); // · | ·· B=point tel que - // · / ·*· C->B=(8/3) * C->P - *x3=Round((bx+x4)/2.0); // · _/·· P3 P2=milieu de [P1,B] - *y3=Round((by+y4)/2.0); // P4*-- P3=milieu de [P4,B] + // C *·····*·········* P=Pencil position + *x2=Round((bx+x1)/2.0); // · | ·· C=middle of [P1,P4] + *y2=Round((by+y1)/2.0); // · | ·· B=point computed as + // · / ·*· C->B=(8/3) * C->P + *x3=Round((bx+x4)/2.0); // · _/·· P3 P2=middle of [P1,B] + *y3=Round((by+y4)/2.0); // P4*-- P3=middle of [P4,B] } @@ -1745,8 +1778,11 @@ void Curve_3_points_0_5(void) Compute_3_point_curve(x1,y1,x4,y4,&x2,&y2,&x3,&y3); - Hide_line_preview(x1,y1,x4,y4); - Draw_curve_preview(x1,y1,x2,y2,x3,y3,x4,y4,color); + if (!Config.Stylus_mode) + { + Hide_line_preview(x1,y1,x4,y4); + Draw_curve_preview(x1,y1,x2,y2,x3,y3,x4,y4,color); + } if ( (Config.Coords_rel) && (Menu_is_visible) ) { @@ -1765,17 +1801,19 @@ void Curve_3_points_0_5(void) Operation_push(y4); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); + + if (Config.Stylus_mode) + { + Display_cursor(); + while(!Mouse_K) + Get_input(20); + Hide_cursor(); + + Hide_line_preview(x1,y1,x4,y4); + } } - -void Curve_3_points_0_11(void) -// -// Opération : OPERATION_3_POINTS_CURVE -// Click Souris: 0 -// Taille_Pile : 11 -// -// Souris effacée: Non -// +void Curve_drag(void) { short x1,y1,x2,y2,x3,y3,x4,y4; short old_x,old_y; @@ -1817,16 +1855,7 @@ void Curve_3_points_0_11(void) Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } - - -void Curve_3_points_12_11(void) -// -// Opération : OPERATION_3_POINTS_CURVE -// Click Souris: 1 ou 2 -// Taille_Pile : 11 -// -// Souris effacée: Oui -// +void Curve_finalize(void) { short x1,y1,x2,y2,x3,y3,x4,y4; short old_x,old_y; @@ -1857,6 +1886,37 @@ void Curve_3_points_12_11(void) Wait_end_of_click(); } +void Curve_3_points_0_11(void) +// +// Opération : OPERATION_3_POINTS_CURVE +// Click Souris: 0 +// Taille_Pile : 11 +// +// Souris effacée: Non +// +{ + if (!Config.Stylus_mode) + Curve_drag(); + else + Curve_finalize(); +} + + +void Curve_3_points_12_11(void) +// +// Opération : OPERATION_3_POINTS_CURVE +// Click Souris: 1 ou 2 +// Taille_Pile : 11 +// +// Souris effacée: Oui +// +{ + if (!Config.Stylus_mode) + Curve_finalize(); + else + Curve_drag(); +} + ///////////////////////////////////////////////////////////// OPERATION_AIRBRUSH @@ -1873,8 +1933,11 @@ void Airbrush_1_0(void) Backup(); Shade_table=Shade_table_left; - Airbrush_next_time = SDL_GetTicks()+Airbrush_delay*10; - Airbrush(LEFT_SIDE); + if (SDL_GetTicks()>Airbrush_next_time) + { + Airbrush(LEFT_SIDE); + Airbrush_next_time = SDL_GetTicks()+Airbrush_delay*10; + } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); @@ -1889,11 +1952,17 @@ void Airbrush_2_0(void) // Souris effacée: Non // { + if (Rightclick_colorpick(1)) + return; + Init_start_operation(); Backup(); Shade_table=Shade_table_right; - Airbrush_next_time = SDL_GetTicks()+Airbrush_delay*10; - Airbrush(RIGHT_SIDE); + if (SDL_GetTicks()>Airbrush_next_time) + { + Airbrush(RIGHT_SIDE); + Airbrush_next_time = SDL_GetTicks()+Airbrush_delay*10; + } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); @@ -1909,6 +1978,7 @@ void Airbrush_12_2(void) // { short old_x,old_y; + Uint32 now; Operation_pop(&old_y); Operation_pop(&old_x); @@ -1920,9 +1990,13 @@ void Airbrush_12_2(void) Display_cursor(); } - if (SDL_GetTicks()>Airbrush_next_time) + now=SDL_GetTicks(); + if (now>Airbrush_next_time) { - Airbrush_next_time+=Airbrush_delay*10; + //Airbrush_next_time+=Airbrush_delay*10; + // Time is now reset, because the += was death spiral + // if drawing took more time than the frequency. + Airbrush_next_time=now+Airbrush_delay*10; Airbrush(Mouse_K_unique); } @@ -1956,6 +2030,9 @@ void Polygon_12_0(void) { byte color; + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); Backup(); Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; @@ -2057,6 +2134,9 @@ void Polyfill_12_0(void) { byte color; + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); Backup(); Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; @@ -2255,6 +2335,9 @@ void Polyform_12_0(void) { short color; + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); Backup(); Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; @@ -2413,6 +2496,9 @@ void Filled_polyform_12_0(void) { short color; + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); // Cette opération étant également utilisée pour le lasso, on ne fait pas de @@ -2825,6 +2911,7 @@ void Grad_circle_12_0(void) Init_start_operation(); Backup(); + Load_gradient_data(Current_gradient); Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; @@ -3082,6 +3169,8 @@ void Grad_ellipse_12_0(void) Init_start_operation(); Backup(); + Load_gradient_data(Current_gradient); + Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; @@ -3306,6 +3395,7 @@ void Grad_rectangle_12_0(void) { Init_start_operation(); Backup(); + Load_gradient_data(Current_gradient); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("\035: 1 \022: 1",0); @@ -3712,6 +3802,9 @@ void Centered_lines_12_0(void) // // Souris effacée: Oui { + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); Backup(); Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; diff --git a/src/operatio.h b/src/operatio.h index a228c582..62002a59 100644 --- a/src/operatio.h +++ b/src/operatio.h @@ -225,3 +225,8 @@ void Centered_lines_0_3(void); void Centered_lines_12_7(void); void Centered_lines_0_7(void); +/////////////////////////////////////////////////// OPERATION_RMB_COLORPICK + +byte Rightclick_colorpick(byte cursor_visible); +void Rightclick_colorpick_2_1(void); +void Rightclick_colorpick_0_1(void); diff --git a/src/pages.c b/src/pages.c index 4b3c5ee0..0669e963 100644 --- a/src/pages.c +++ b/src/pages.c @@ -75,6 +75,7 @@ T_Page * New_page(byte nb_layers) page->Filename[0]='\0'; page->File_format=DEFAULT_FILEFORMAT; page->Nb_layers=nb_layers; + page->Gradients=NULL; page->Transparent_color=0; // Default transparent color page->Background_transparent=0; page->Next = page->Prev = NULL; @@ -141,6 +142,24 @@ byte * Dup_layer(byte * layer) // ============================================================== +/// Adds a shared reference to the gradient data of another page. Pass NULL for new. +T_Gradient_array *Dup_gradient(T_Page * page) +{ + // new + if (page==NULL || page->Gradients==NULL) + { + T_Gradient_array *array; + array=(T_Gradient_array *)calloc(1, sizeof(T_Gradient_array)); + if (!array) + return NULL; + array->Used=1; + return array; + } + // shared + page->Gradients->Used++; + return page->Gradients; +} + void Download_infos_page_main(T_Page * page) // Affiche la page à l'écran { @@ -418,6 +437,16 @@ void Clear_page(T_Page * page) Free_layer(page, i); page->Image[i]=NULL; } + + // Free_gradient() : This data is reference-counted + if (page->Gradients) + { + page->Gradients->Used--; + if (page->Gradients->Used==0) + free(page->Gradients); + page->Gradients=NULL; + } + page->Width=0; page->Height=0; // On ne se préoccupe pas de ce que deviens le reste des infos de l'image. @@ -426,6 +455,7 @@ void Clear_page(T_Page * page) void Copy_S_page(T_Page * dest,T_Page * source) { *dest=*source; + dest->Gradients=NULL; } @@ -460,6 +490,10 @@ int Allocate_list_of_pages(T_List_of_pages * list) list->List_size=1; + page->Gradients=Dup_gradient(NULL); + if (!page->Gradients) + return 0; + return 1; // Succès } @@ -799,19 +833,10 @@ void Set_number_of_backups(int nb_backups) // (nb_backups = Nombre de backups, sans compter les pages courantes) } -int Backup_with_new_dimensions(int upload,byte layers,int width,int height) +int Backup_new_image(byte layers,int width,int height) { - // Retourne 1 si une nouvelle page est disponible (alors pleine de 0) et - // 0 sinon. - - T_Page * new_page; - int return_code=0; - int i; - - if (upload) - // On remet à jour l'état des infos de la page courante (pour pouvoir les - // retrouver plus tard) - Upload_infos_page_main(Main_backups->Pages); + // Retourne 1 si une nouvelle page est disponible et 0 sinon + T_Page * new_page; // On crée un descripteur pour la nouvelle page courante new_page=New_page(layers); @@ -820,36 +845,161 @@ int Backup_with_new_dimensions(int upload,byte layers,int width,int height) Error(0); return 0; } - Upload_infos_page_main(new_page); new_page->Width=width; new_page->Height=height; - strcpy(new_page->Filename, Main_backups->Pages->Filename); - strcpy(new_page->File_directory, Main_backups->Pages->File_directory); - if (Create_new_page(new_page,Main_backups,0xFFFFFFFF)) + new_page->Transparent_color=0; + new_page->Gradients=Dup_gradient(NULL); + if (!Create_new_page(new_page,Main_backups,0xFFFFFFFF)) { - for (i=0; iPages->Image[i], Main_backups->Pages->Transparent_color, width*height); - } - - Update_buffers(width, height); - - Download_infos_page_main(Main_backups->Pages); - - // Same code as in End_of_modification(): - #ifndef NOLAYERS - memcpy(Main_visible_image_backup.Image, - Main_visible_image.Image, - Main_image_width*Main_image_height); - #else - Update_screen_targets(); - #endif - Update_FX_feedback(Config.FX_Feedback); - // -- - - return_code=1; + Error(0); + return 0; } - return return_code; + + Update_buffers(width, height); + + Download_infos_page_main(Main_backups->Pages); + + return 1; +} + + +int Backup_with_new_dimensions(int width,int height) +{ + // Retourne 1 si une nouvelle page est disponible (alors pleine de 0) et + // 0 sinon. + + T_Page * new_page; + int i; + + // On crée un descripteur pour la nouvelle page courante + new_page=New_page(Main_backups->Pages->Nb_layers); + if (!new_page) + { + Error(0); + return 0; + } + new_page->Width=width; + new_page->Height=height; + new_page->Transparent_color=0; + if (!Create_new_page(new_page,Main_backups,0xFFFFFFFF)) + { + Error(0); + return 0; + } + + // Copy data from previous history step + memcpy(Main_backups->Pages->Palette,Main_backups->Pages->Next->Palette,sizeof(T_Palette)); + strcpy(Main_backups->Pages->Comment,Main_backups->Pages->Next->Comment); + Main_backups->Pages->File_format=Main_backups->Pages->Next->File_format; + strcpy(Main_backups->Pages->Filename, Main_backups->Pages->Next->Filename); + strcpy(Main_backups->Pages->File_directory, Main_backups->Pages->Next->File_directory); + Main_backups->Pages->Gradients=Dup_gradient(Main_backups->Pages->Next); + Main_backups->Pages->Background_transparent=Main_backups->Pages->Next->Background_transparent; + Main_backups->Pages->Transparent_color=Main_backups->Pages->Next->Transparent_color; + + // Fill with transparent color + for (i=0; iPages->Nb_layers;i++) + { + memset(Main_backups->Pages->Image[i], Main_backups->Pages->Transparent_color, width*height); + } + + Update_buffers(width, height); + + Download_infos_page_main(Main_backups->Pages); + + // Same code as in End_of_modification(), + // Without saving a safety backup: + #ifndef NOLAYERS + memcpy(Main_visible_image_backup.Image, + Main_visible_image.Image, + Main_image_width*Main_image_height); + #else + Update_screen_targets(); + #endif + Update_FX_feedback(Config.FX_Feedback); + // -- + + return 1; +} + +/// +/// Resizes a backup step in-place (doesn't add a Undo/Redo step). +/// Should only be called after an actual backup, because it loses the current. +/// pixels. This function is meant to be used from within Lua scripts. +int Backup_in_place(int width,int height) +{ + // Retourne 1 si une nouvelle page est disponible (alors pleine de 0) et + // 0 sinon. + + int i; + byte ** new_layer; + + // Perform all allocations first + + new_layer=calloc(Main_backups->Pages->Nb_layers,1); + if (!new_layer) + return 0; + + for (i=0; iPages->Nb_layers; i++) + { + new_layer[i]=New_layer(height*width); + if (!new_layer[i]) + { + // Allocation error + for (; i>0; i--) + free(new_layer[i]); + free(new_layer); + return 0; + } + } + + // Now ok to proceed + + for (i=0; iPages->Nb_layers; i++) + { + // Replace layers + Free_layer(Main_backups->Pages,i); + Main_backups->Pages->Image[i]=new_layer[i]; + + // Fill with transparency + memset(Main_backups->Pages->Image[i], Main_backups->Pages->Transparent_color, width*height); + } + + Main_backups->Pages->Width=width; + Main_backups->Pages->Height=height; + + Download_infos_page_main(Main_backups->Pages); + + // The following is part of Update_buffers() + // (without changing the backup buffer) + #ifndef NOLAYERS + // At least one dimension is different + if (Main_visible_image.Width*Main_visible_image.Height != width*height) + { + // Current image + free(Main_visible_image.Image); + Main_visible_image.Image = (byte *)malloc(width * height); + if (Main_visible_image.Image == NULL) + return 0; + } + Main_visible_image.Width = width; + Main_visible_image.Height = height; + + if (Main_visible_image_depth_buffer.Width*Main_visible_image_depth_buffer.Height != width*height) + { + // Depth buffer + free(Main_visible_image_depth_buffer.Image); + Main_visible_image_depth_buffer.Image = (byte *)malloc(width * height); + if (Main_visible_image_depth_buffer.Image == NULL) + return 0; + } + Main_visible_image_depth_buffer.Width = width; + Main_visible_image_depth_buffer.Height = height; + +#endif + Update_screen_targets(); + + return 1; } int Backup_and_resize_the_spare(int width,int height) @@ -872,6 +1022,7 @@ int Backup_and_resize_the_spare(int width,int height) // Fill it with a copy of the latest history Copy_S_page(new_page,Spare_backups->Pages); + new_page->Gradients=Dup_gradient(Spare_backups->Pages); new_page->Width=width; new_page->Height=height; @@ -927,6 +1078,7 @@ void Backup_layers(dword layer_mask) // Fill it with a copy of the latest history Copy_S_page(new_page,Main_backups->Pages); + new_page->Gradients=Dup_gradient(Main_backups->Pages); Create_new_page(new_page,Main_backups,layer_mask); Download_infos_page_main(new_page); @@ -963,6 +1115,7 @@ void Backup_the_spare(dword layer_mask) // Fill it with a copy of the latest history Copy_S_page(new_page,Spare_backups->Pages); + new_page->Gradients=Dup_gradient(Spare_backups->Pages); Create_new_page(new_page,Spare_backups,layer_mask); // Copy the actual pixels from the backup to the latest page @@ -1099,6 +1252,11 @@ void End_of_modification(void) //Update_buffers(Main_image_width, Main_image_height); #ifndef NOLAYERS + // Backup buffer can have "wrong" size if a Lua script + // performs a resize. + Update_buffers(Main_image_width, Main_image_height); + // + memcpy(Main_visible_image_backup.Image, Main_visible_image.Image, Main_image_width*Main_image_height); diff --git a/src/pages.h b/src/pages.h index d6f44ebe..31a514c5 100644 --- a/src/pages.h +++ b/src/pages.h @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) @@ -39,13 +40,14 @@ extern byte * FX_feedback_screen; /////////////////////////// BACKUP /////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// +#ifndef NOLAYERS /// The pixels of visible layers, flattened copy. extern T_Bitmap Main_visible_image; /// The pixels of visible layers, flattened copy, used for no-feedback effects. extern T_Bitmap Main_visible_image_backup; /// The index of visible pixels from ::Visible image. Points to the right layer. extern T_Bitmap Main_visible_image_depth_buffer; - +#endif /// The pixels of visible layers for the spare page, flattened copy. extern T_Bitmap Spare_visible_image; @@ -93,7 +95,13 @@ void Free_page_of_a_list(T_List_of_pages * list); int Init_all_backup_lists(int width,int height); void Set_number_of_backups(int nb_backups); -int Backup_with_new_dimensions(int upload,byte layers,int width,int height); +int Backup_new_image(byte layers,int width,int height); +int Backup_with_new_dimensions(int width,int height); +/// +/// Resizes a backup step in-place (doesn't add a Undo/Redo step). +/// Should only be called after an actual backup, because it loses the current. +/// pixels. This function is meant to be used from within Lua scripts. +int Backup_in_place(int width,int height); /// Backup the spare image, the one you don't see. void Backup_the_spare(dword layer_mask); int Backup_and_resize_the_spare(int width,int height); diff --git a/src/palette.c b/src/palette.c index 3086727a..91bad838 100644 --- a/src/palette.c +++ b/src/palette.c @@ -40,11 +40,10 @@ byte Palette_view_is_RGB = 1; // Indique si on est en HSL ou en RGB -// --------------------------- Menu des palettes ----------------------------- -char * Palette_reduce_label[7]= -{ - "128"," 64"," 32"," 16"," 8"," 4"," 2" -}; +// Coordinates of the color count (on histogram button) +static const int COUNT_X = 258; +static const int COUNT_Y = 49; + // Nombre de graduations pour une composante RGB int RGB_scale = 256; // 24bit @@ -68,13 +67,41 @@ void Set_palette_RGB_scale(int scale) RGB_scale = scale; } +int Get_palette_RGB_scale(void) +{ + return RGB_scale; +} + +/// +/// Round a 0-255 RGB component according to the RGB_scale. +/// The result is also in the 0-255 range. byte Round_palette_component(byte comp) { return ((comp+128/RGB_scale)*(RGB_scale-1)/255*255+(RGB_scale&1?1:0))/(RGB_scale-1); } +/// +/// Turns a RGB component from 0-255 scale to 0-(RGB_scale-1). +/// The passed value should come from Round_palette_component(), +/// otherwise the rounding will be "down". +int Reduce_component(int comp) +{ + return (comp)*255/Color_max; +} + +/// +/// Turns a RGB component from 0-(RGB_scale-1) to 0-255. +int Expand_component(int comp) +{ + if (Color_max==255) + return comp; + return (comp+1)*Color_max/255; + // The +1 cancel any rounding down, the above test prevents + // the only case where it would be too much. +} + // Définir les unités pour les graduations R G B ou H S V -void Componant_unit(int count) +void Component_unit(int count) { Color_count = count; Color_max = count-1; @@ -138,7 +165,7 @@ void Set_blue(byte color, short new_color, T_Palette palette) palette[color].B=new_color; } -void Format_componant(byte value, char *str) +void Format_component(byte value, char *str) // Formate une chaine de 4 caractères+\0 : "nnn " { Num2str(value,str,3); @@ -183,38 +210,19 @@ void Spread_colors(short start,short end,T_Palette palette) void Update_color_count(short * used_colors, dword * color_usage) { - char str[10]; + char str[4]; Hide_cursor(); Cursor_shape=CURSOR_SHAPE_HOURGLASS; Display_cursor(); *used_colors=Count_used_colors(color_usage); - strcpy(str,"Used: "); - Num2str(*used_colors,str+6,3); + Num2str(*used_colors,str,3); Hide_cursor(); - Print_in_window(132,20,str,MC_Black,MC_Light); + Print_in_window(COUNT_X,COUNT_Y,str,MC_Black,MC_Light); Cursor_shape=CURSOR_SHAPE_ARROW; Display_cursor(); } -void Update_pixel_count(byte block_start, byte block_end, dword color_usage[]) -{ - int i; - int pixel_count = 0; - char str[10]; - - if (block_start<=block_end) - for (i = block_start; i <= block_end; i++) - pixel_count += color_usage[i]; - else - for (i = block_end; i <= block_start; i++) - pixel_count += color_usage[i]; - - Num2str(pixel_count, str, 7); - Print_in_window(230,50, str, MC_Black, MC_Light); - -} - void Remap_zone_highlevel(short x1, short y1, short x2, short y2, byte * conversion_table) // Attention: Remappe une zone de coins x1,y1 et x2-1,y2-1 !!! @@ -242,12 +250,12 @@ void Remap_image_highlevel(byte * conversion_table) int layer; // Remap the flatenned image view - Remap_general_lowlevel(conversion_table,Main_screen, + Remap_general_lowlevel(conversion_table,Main_screen,Main_screen, Main_image_width,Main_image_height,Main_image_width); // Remap all layers for (layer=0; layerPages->Nb_layers; layer++) - Remap_general_lowlevel(conversion_table,Main_backups->Pages->Image[layer],Main_image_width,Main_image_height,Main_image_width); + Remap_general_lowlevel(conversion_table,Main_backups->Pages->Image[layer],Main_backups->Pages->Image[layer],Main_image_width,Main_image_height,Main_image_width); // Remap transparent color Main_backups->Pages->Transparent_color = @@ -316,7 +324,7 @@ void Swap(int with_remap,short block_1_start,short block_2_start,short block_siz // On fait une copie de la palette memcpy(temp_palette, palette, sizeof(T_Palette)); - // On fait une copie de la table d'utilisation des couleurs + // On fait une copie de la table d'used des couleurs memcpy(temp_usage, color_usage, sizeof(dword) * 256); // On commence à initialiser la table de conversion à un état où elle ne @@ -381,7 +389,7 @@ void Swap(int with_remap,short block_1_start,short block_2_start,short block_siz conversion_table[pos_1]=pos_2; conversion_table[pos_2]=pos_1; - // On intervertit le nombre d'utilisation des couleurs pour garder une + // On intervertit le nombre d'used des couleurs pour garder une // cohérence lors d'un éventuel "Zap unused". SWAP_DWORDS(color_usage[pos_1], color_usage[pos_2]) @@ -449,14 +457,16 @@ void Set_nice_menu_colors(dword * color_usage,int not_picture) // couleurs du menu par défaut for (index=0; index<4; index++) { + const T_Components * target_rgb; + + target_rgb=Favorite_GUI_color(index); color=new_colors[index]; rgb[index].R=Main_palette[color].R; rgb[index].G=Main_palette[color].G; rgb[index].B=Main_palette[color].B; - // Should be Config.Fav_menu_colors[index] if using user colors - Main_palette[color].R=Gfx->Default_palette[Gfx->Color[index]].R; - Main_palette[color].G=Gfx->Default_palette[Gfx->Color[index]].G; - Main_palette[color].B=Gfx->Default_palette[Gfx->Color[index]].B; + Main_palette[color].R=Round_palette_component(target_rgb->R); + Main_palette[color].G=Round_palette_component(target_rgb->G); + Main_palette[color].B=Round_palette_component(target_rgb->B); } // Maintenant qu'on a placé notre nouvelle palette, on va chercher quelles @@ -491,8 +501,8 @@ void Reduce_palette(short * used_colors,int nb_colors_asked,T_Palette palette,dw int best_color_2=0; int difference; int best_difference; - dword Utilisation; - dword Meilleure_utilisation; + dword used; + dword best_used; // On commence par initialiser la table de conversion dans un état où // aucune conversion ne sera effectuée. @@ -543,7 +553,8 @@ void Reduce_palette(short * used_colors,int nb_colors_asked,T_Palette palette,dw // Maintenant qu'on a une palette clean, on va boucler en réduisant // le nombre de couleurs jusqu'à ce qu'on atteigne le nombre désiré. - while ((*used_colors)>nb_colors_asked) + // (The stop condition is further down) + while (1) { // Il s'agit de trouver les 2 couleurs qui se ressemblent le plus // parmis celles qui sont utilisées (bien sûr) et de les remplacer par @@ -551,7 +562,7 @@ void Reduce_palette(short * used_colors,int nb_colors_asked,T_Palette palette,dw // en fonction de leur utilisation dans l'image. best_difference =0x7FFF; - Meilleure_utilisation=0x7FFFFFFF; + best_used=0x7FFFFFFF; for (color_1=0;color_1<(*used_colors);color_1++) for (color_2=color_1+1;color_2<(*used_colors);color_2++) @@ -563,16 +574,21 @@ void Reduce_palette(short * used_colors,int nb_colors_asked,T_Palette palette,dw if (difference<=best_difference) { - Utilisation=color_usage[color_1]+color_usage[color_2]; - if ((differenceNb_elements=nb_elements; slider->Position=position; - Compute_slider_cursor_height(slider); + Compute_slider_cursor_length(slider); Window_draw_slider(slider); - Print_counter(x_pos,172,value,MC_Black,MC_Light); + Print_counter(x_pos,NUMERIC_Y,value,MC_Black,MC_Light); } @@ -691,9 +717,9 @@ void Display_sliders(T_Scroller_button * red_slider, if (block_is_selected) { - Set_palette_slider(red_slider,Color_max*2+1,Color_max,"± 0",176); - Set_palette_slider(green_slider,Color_max*2+1,Color_max,"± 0",203); - Set_palette_slider(blue_slider,Color_max*2+1,Color_max,"± 0",230); + Set_palette_slider(red_slider,Color_max*2+1,Color_max,"± 0",NUMERIC_R_X); + Set_palette_slider(green_slider,Color_max*2+1,Color_max,"± 0",NUMERIC_G_X); + Set_palette_slider(blue_slider,Color_max*2+1,Color_max,"± 0",NUMERIC_B_X); } else { @@ -706,17 +732,15 @@ void Display_sliders(T_Scroller_button * red_slider, RGB_to_HSL(j1,j2,j3,&j1,&j2,&j3); } - Format_componant(j1*Color_count/256,str); - Set_palette_slider(red_slider,Color_count,Color_max-j1*Color_max/255,str,176); - Format_componant(j2*Color_count/256,str); - Set_palette_slider(green_slider,Color_count,Color_max-j2*Color_max/255,str,203); - Format_componant(j3*Color_count/256,str); - Set_palette_slider(blue_slider,Color_count,Color_max-j3*Color_max/255,str,230); + Format_component(j1*Color_count/256,str); + Set_palette_slider(red_slider,Color_count,Color_max-Expand_component(j1),str,NUMERIC_R_X); + Format_component(j2*Color_count/256,str); + Set_palette_slider(green_slider,Color_count,Color_max-Expand_component(j2),str,NUMERIC_G_X); + Format_component(j3*Color_count/256,str); + Set_palette_slider(blue_slider,Color_count,Color_max-Expand_component(j3),str,NUMERIC_B_X); } } - - void Draw_all_palette_sliders(T_Scroller_button * red_slider, T_Scroller_button * green_slider, T_Scroller_button * blue_slider, @@ -731,15 +755,15 @@ void Draw_all_palette_sliders(T_Scroller_button * red_slider, // Dans le cas d'un bloc, tout à 0. red_slider->Position =Color_max; Window_draw_slider(red_slider); - Print_counter(176,172,"± 0",MC_Black,MC_Light); + Print_counter(NUMERIC_R_X,NUMERIC_Y,"± 0",MC_Black,MC_Light); green_slider->Position =Color_max; Window_draw_slider(green_slider); - Print_counter(203,172,"± 0",MC_Black,MC_Light); + Print_counter(NUMERIC_G_X,NUMERIC_Y,"± 0",MC_Black,MC_Light); blue_slider->Position =Color_max; Window_draw_slider(blue_slider); - Print_counter(230,172,"± 0",MC_Black,MC_Light); + Print_counter(NUMERIC_B_X,NUMERIC_Y,"± 0",MC_Black,MC_Light); } else { @@ -753,30 +777,35 @@ void Draw_all_palette_sliders(T_Scroller_button * red_slider, RGB_to_HSL(j1,j2,j3,&j1,&j2,&j3); } DEBUG("j1",j1); - Format_componant(j1*Color_count/256,str); - red_slider->Position=Color_max-j1*Color_max/255; + Format_component(j1*Color_count/256,str); + red_slider->Position=Color_max-Expand_component(j1); Window_draw_slider(red_slider); - Print_counter(176,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); - Format_componant(j2*Color_count/256,str); - green_slider->Position=Color_max-j2*Color_max/255; + Format_component(j2*Color_count/256,str); + green_slider->Position=Color_max-Expand_component(j2); Window_draw_slider(green_slider); - Print_counter(203,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); - Format_componant(j3*Color_count/256,str); - blue_slider->Position=Color_max-j3*Color_max/255; + Format_component(j3*Color_count/256,str); + blue_slider->Position=Color_max-Expand_component(j3); Window_draw_slider(blue_slider); - Print_counter(230,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } Display_cursor(); } -void Window_Histogram(unsigned char block_start, unsigned char block_end, dword* color_usage) +int Window_Histogram(unsigned char block_start, unsigned char block_end, dword* color_usage) { int i, j; unsigned int max_count = 0; int old_height=0; + int hovered_color=-1; + int new_hovered_color; + int bar_width; + T_Special_button *histo; + int clicked_button; /* Draws an histogram of the selected range in a separate window */ @@ -796,15 +825,21 @@ void Window_Histogram(unsigned char block_start, unsigned char block_end, dword* if(color_usage[i] > max_count) max_count = color_usage[i]; } - if (max_count == 0) { + if (max_count == 0) + { Warning_message("All these colors are unused!"); - return; + Hide_cursor(); + return -1; } + + Open_window(263, 150, "Histogram"); + Window_set_normal_button(120, 130, 42, 14, "Close",-1,1,SDLK_RETURN); - Open_window(263, 140, "Histogram"); - Window_set_normal_button(120, 120, 42, 14, "Close",-1,1,SDLK_RETURN); + Print_in_window(6, 17, "Color:", MC_Dark, MC_Light); + Print_in_window(110+12*8, 17, "Pixels", MC_Dark, MC_Light); // Step 2 : draw bars + bar_width=256/(block_end-block_start+1); j = 0; for(i=block_start; i<= block_end; i++) { int height = 100*color_usage[i]/max_count; @@ -816,30 +851,30 @@ void Window_Histogram(unsigned char block_start, unsigned char block_end, dword* height=1; Window_rectangle( - 3+j*(256/(block_end-block_start+1)), - 117-height, - 256/(block_end-block_start+1), + 3+j*bar_width, + 127-height, + bar_width, height, i); //if (i == MC_Light) { Window_rectangle( - 3+j*(256/(block_end-block_start+1)), - 116-height, - 256/(block_end-block_start+1), + 3+j*bar_width, + 126-height, + bar_width, 1,MC_Black); //} } // vertical outline if (height>old_height) Window_rectangle( - 2+j*(256/(block_end-block_start+1)), - 116-height, + 2+j*bar_width, + 126-height, 1, height-old_height+1,MC_Black); else if (old_height>height) Window_rectangle( - 3+j*(256/(block_end-block_start+1)), - 116-old_height, + 3+j*bar_width, + 126-old_height, 1, old_height-height+1,MC_Black); @@ -850,20 +885,121 @@ void Window_Histogram(unsigned char block_start, unsigned char block_end, dword* if (old_height!=0) Window_rectangle( 3+j*(256/(block_end-block_start+1)), - 116-old_height, + 126-old_height, 1, old_height+1,MC_Black); - Update_window_area(0,0,263,140); - Display_cursor(); + histo = Window_set_special_button(3, 27, j*bar_width, 100); // 2 - while(Window_clicked_button() != 1); - Close_window(); + Update_window_area(0,0,263,150); Display_cursor(); + do + { + // Find hovered area + if (Window_click_in_rectangle(histo->Pos_X,histo->Pos_Y,histo->Pos_X+histo->Width-1,histo->Pos_Y+histo->Height-1)) + { + short x_pos; + x_pos=((short)Mouse_X-Window_pos_X)/Menu_factor_X; + new_hovered_color=block_start+(x_pos-histo->Pos_X)/bar_width; + } + else + new_hovered_color=-1; + + // When changing hovered color, update the info area + if (new_hovered_color!=hovered_color) + { + char str[12]; + + hovered_color=new_hovered_color; + Hide_cursor(); + if (hovered_color==-1) + { + Window_rectangle(6+6*8,17,3*8,7,MC_Light); + Update_window_area(6+6*8,17,3*8,7); + Window_rectangle(86,17,2*8,8,MC_Light); + Update_window_area(86,17,2*8,8); + Window_rectangle(110,17,11*8,7,MC_Light); + Update_window_area(110,17,11*8,7); + } + else + { + Num2str(hovered_color,str ,3); + Print_in_window(6+6*8,17,str,MC_Black,MC_Light); + Window_rectangle(86,17,2*8,8,hovered_color); + Update_window_area(86,17,2*8,8); + Num2str(color_usage[hovered_color],str ,11); + Print_in_window(110,17,str,MC_Black,MC_Light); + } + Display_cursor(); + } + clicked_button=Window_clicked_button(); + if (Key == KEY_ESC) + clicked_button=1; + + } while( clicked_button < 1); + Close_window(); + + if (clicked_button==2) + { + // This is a counter-hack. Close_window() sets Mouse_K to zero + // on exit, I don't know why (It will become 1 again if you move + // the mouse slightly) + // Here I force it back to 1, so that the Wait_end_of_click() + // will really wait for a release of mouse button. + Mouse_K=1; + return hovered_color; + } + return -1; +} + +void Print_RGB_or_HSL(byte mode) +{ + Print_in_window(184,68,mode?"H":"R",MC_Dark,MC_Light); + Print_in_window(211,68,mode?"S":"G",MC_Dark,MC_Light); + Print_in_window(238,68,mode?"L":"B",MC_Dark,MC_Light); +} + +void Tag_used_colors(byte color, dword color_usage[]) +{ + word index; + + for (index=0;index<=255;index++) + { + short x_pos=Window_palette_button_list->Pos_X+6+((index>>4)*10); + short y_pos=Window_palette_button_list->Pos_Y+3+((index&15)* 5); + byte col; + + col=(color&&color_usage[index])?MC_White:MC_Light; + Window_rectangle(x_pos+5,y_pos+0,1,5,col); + } + + Update_window_area(Window_palette_button_list->Pos_X+3,Window_palette_button_list->Pos_Y+3,12*16,5*16); } void Button_Palette(void) { + static const int BUTTON_PLUS_X = 268; + static const int BUTTON_PLUS_Y = 74; + static const int BUTTON_MINUS_X = 268; + static const int BUTTON_MINUS_Y = 165; + + // Coordinates of the block that displays Backcolor + static const int BGCOLOR_DISPLAY_X = 262; + static const int BGCOLOR_DISPLAY_Y = 89; + static const int BGCOLOR_DISPLAY_W = 24; + static const int BGCOLOR_DISPLAY_H = 72; + + // Coordinates of the block that displays Forecolor + static const int FGCOLOR_DISPLAY_X = 266; + static const int FGCOLOR_DISPLAY_Y = 93; + static const int FGCOLOR_DISPLAY_W = 16; + static const int FGCOLOR_DISPLAY_H = 64; + + // Coordinates of the Color# + static const int COLOR_X = 111; + static const int COLOR_Y = 69; + + static short reduce_colors_number = 256; short temp_color; // Variable pouvant reservir pour différents calculs intermédiaires dword temp; @@ -883,6 +1019,7 @@ void Button_Palette(void) T_Scroller_button * green_slider; T_Scroller_button * blue_slider; T_Dropdown_button * reduce_dropdown; + T_Dropdown_button * sort_dropdown; byte image_is_backed_up = 0; byte need_to_remap = 0; @@ -893,12 +1030,14 @@ void Button_Palette(void) T_Components * backup_palette; T_Components * temp_palette; T_Components * working_palette; + + static byte show_used_colors=0; backup_palette =(T_Components *)malloc(sizeof(T_Palette)); temp_palette=(T_Components *)malloc(sizeof(T_Palette)); working_palette=(T_Components *)malloc(sizeof(T_Palette)); - Componant_unit(RGB_scale); + Component_unit(RGB_scale); Open_window(299, 188,"Palette"); @@ -908,102 +1047,105 @@ void Button_Palette(void) Window_set_palette_button(5, 79); // 1 - Window_display_frame (173, 67, 121, 116); + Window_display_frame (172, 63, 122, 121); // Graduation des jauges de couleur - Window_rectangle(179,109,17,1,MC_Dark); - Window_rectangle(206,109,17,1,MC_Dark); - Window_rectangle(233,109,17,1,MC_Dark); - Window_rectangle(179,125,17,1,MC_Dark); - Window_rectangle(206,125,17,1,MC_Dark); - Window_rectangle(233,125,17,1,MC_Dark); - Window_rectangle(179,141,17,1,MC_Dark); - Window_rectangle(206,141,17,1,MC_Dark); - Window_rectangle(233,141,17,1,MC_Dark); + Window_rectangle(180,106,17,1,MC_Dark); + Window_rectangle(207,106,17,1,MC_Dark); + Window_rectangle(234,106,17,1,MC_Dark); + Window_rectangle(180,122,17,1,MC_Dark); + Window_rectangle(207,122,17,1,MC_Dark); + Window_rectangle(234,122,17,1,MC_Dark); + Window_rectangle(180,138,17,1,MC_Dark); + Window_rectangle(207,138,17,1,MC_Dark); + Window_rectangle(234,138,17,1,MC_Dark); // Jauges de couleur - red_slider = Window_set_scroller_button(182, 81, 88,Color_count,1,Color_max-working_palette[Fore_color].R*Color_max/255);// 2 - green_slider = Window_set_scroller_button(209, 81, 88,Color_count,1,Color_max-working_palette[Fore_color].G*Color_max/255);// 3 - blue_slider = Window_set_scroller_button(236, 81, 88,Color_count,1,Color_max-working_palette[Fore_color].B*Color_max/255);// 4 + red_slider = Window_set_scroller_button(183, 79, 88,Color_count,1,Color_max-Reduce_component(working_palette[Fore_color].R));// 2 + green_slider = Window_set_scroller_button(210, 79, 88,Color_count,1,Color_max-Reduce_component(working_palette[Fore_color].G));// 3 + blue_slider = Window_set_scroller_button(237, 79, 88,Color_count,1,Color_max-Reduce_component(working_palette[Fore_color].B));// 4 if(Palette_view_is_RGB==1) { - Print_in_window(184,71,"R",MC_Dark,MC_Light); - Print_in_window(211,71,"G",MC_Dark,MC_Light); - Print_in_window(238,71,"B",MC_Dark,MC_Light); - Componant_unit(RGB_scale); + Print_RGB_or_HSL(0); + Component_unit(RGB_scale); } else { - Print_in_window(184,71,"H",MC_Dark,MC_Light); - Print_in_window(211,71,"S",MC_Dark,MC_Light); - Print_in_window(238,71,"L",MC_Dark,MC_Light); - Componant_unit(256); + Print_RGB_or_HSL(1); + Component_unit(256); } first_color=last_color=block_start=block_end=Fore_color; Tag_color_range(block_start,block_end); // Affichage dans le block de visu de la couleur en cours - Window_rectangle(260,89,24,72,Back_color); - Window_rectangle(264,93,16,64,Fore_color); + Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H,Back_color); + Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); // Affichage des valeurs de la couleur courante (pour 1 couleur) Display_sliders(red_slider,green_slider,blue_slider,(block_start!=block_end),working_palette); - Print_in_window(129, 36, "Color number:", MC_Dark, MC_Light); + Print_in_window(7, 69, "Color number:", MC_Dark, MC_Light); Num2str(Fore_color, str, 3); - Print_in_window(237, 36, str, MC_Black, MC_Light); + Print_in_window(COLOR_X, COLOR_Y, str, MC_Black, MC_Light); - Window_set_normal_button( 6,17,59,14,"Default",3,1,SDLK_f); // 5 - Window_set_normal_button(66,17,29,14,"Gry" ,1,1,SDLK_g); // 6 - Window_set_normal_button(66,47,29,14,"Swp" ,0,1,KEY_NONE); // 7 - Window_set_normal_button( 6,47,59,14,"X-Swap" ,1,1,SDLK_x); // 8 - Window_set_normal_button(66,32,29,14,"Cpy" ,1,1,SDLK_c); // 9 - Window_set_normal_button( 6,32,59,14,"Spread" ,4,1,SDLK_e); // 10 + Window_set_normal_button( 7,16,55,14,"Merge" ,0,1,SDLK_m); // 5 + Window_set_normal_button( 63,16,36,14,"Gray" ,1,1,SDLK_g); // 6 + Window_set_normal_button( 7,46,55,14,"Swap" ,0,1,KEY_NONE); // 7 + Window_set_normal_button( 63,46,72,14,"X-Swap" ,1,1,SDLK_x); // 8 + Window_set_normal_button(136,31,54,14,"Copy" ,1,1,SDLK_c); // 9 + Window_set_normal_button(136,46,54,14,"Spread" ,4,1,SDLK_e); // 10 - reduce_dropdown = Window_set_dropdown_button(96, 62, 60, 14, 60, "Reduce", 0, - 0, 1, LEFT_SIDE, 0); // 11 - Window_dropdown_add_item(reduce_dropdown, 0, "to 128"); - Window_dropdown_add_item(reduce_dropdown, 1, "to 64"); - Window_dropdown_add_item(reduce_dropdown, 2, "to 32"); - Window_dropdown_add_item(reduce_dropdown, 3, "to 16"); - Window_dropdown_add_item(reduce_dropdown, 4, "to 8"); - Window_dropdown_add_item(reduce_dropdown, 5, "to 4"); - Window_dropdown_add_item(reduce_dropdown, 6, "to 2"); - Window_dropdown_add_item(reduce_dropdown, 7, "Other"); + reduce_dropdown = Window_set_dropdown_button(209, 46, 83, 14, 84, "Reduce", 0, + 0, 1, RIGHT_SIDE|LEFT_SIDE, 0); // 11 + Window_dropdown_add_item(reduce_dropdown, 256, "to uniques"); + Window_dropdown_add_item(reduce_dropdown, 128, "to 128"); + Window_dropdown_add_item(reduce_dropdown, 64, "to 64"); + Window_dropdown_add_item(reduce_dropdown, 32, "to 32"); + Window_dropdown_add_item(reduce_dropdown, 16, "to 16"); + Window_dropdown_add_item(reduce_dropdown, 8, "to 8"); + Window_dropdown_add_item(reduce_dropdown, 4, "to 4"); + Window_dropdown_add_item(reduce_dropdown, 2, "to 2"); + Window_dropdown_add_item(reduce_dropdown, 0, "Other"); Window_set_normal_button( 6,168,35,14,"Undo" ,1,1,SDLK_u); // 12 Window_set_normal_button( 62,168,51,14,"Cancel",0,1,KEY_ESC); // 13 Window_set_normal_button(117,168,51,14,"OK" ,0,1,SDLK_RETURN); // 14 - // histogram button - button_used = Window_set_normal_button(228,47,64,14,"000000",0,1,SDLK_d);// 15 - Window_set_normal_button(209,17,83,14,"Zap unused",0,1,SDLK_DELETE);//16 + Window_set_normal_button(209,16,37,14,"Used",0,1,SDLK_d); // 15 + Window_set_normal_button(209,31,83,14,"Zap unused",0,1,SDLK_DELETE);//16 + + Window_set_repeatable_button(BUTTON_PLUS_X, BUTTON_PLUS_Y,12,11,"+",0,1,SDLK_KP_PLUS); // 17 + Window_set_repeatable_button(BUTTON_MINUS_X,BUTTON_MINUS_Y,12,11,"-",0,1,SDLK_KP_MINUS); // 18 - Window_set_repeatable_button(266, 74,12,11,"+",0,1,SDLK_KP_PLUS); // 17 - Window_set_repeatable_button(266,165,12,11,"-",0,1,SDLK_KP_MINUS); // 18 + Window_set_normal_button(100,16,35,14,"Neg" ,1,1,SDLK_n); // 19 + Window_set_normal_button(7,31,55,14,"Invert" ,1,1,SDLK_i); // 20 + Window_set_normal_button(63,31,72,14,"X-Invert" ,5,1,SDLK_v); // 21 - Window_set_normal_button(96,17,29,14,"Neg" ,1,1,SDLK_n); // 19 - Window_set_normal_button(66,62,29,14,"Inv" ,1,1,SDLK_i); // 20 - Window_set_normal_button( 6,62,59,14,"X-Inv." ,5,1,SDLK_v); // 21 + // Button without outline + Window_set_normal_button(175,66,81,11,"" ,0,1,SDLK_h); // 22 + Window_display_frame_mono(175-1,66-1,81+2,11+2,MC_Light); - Window_set_normal_button(96,32,29,14,"HSL" ,1,1,SDLK_h); // 22 - Window_set_normal_button(96,47,29,14,"Srt" ,1,1,SDLK_s); // 23 + sort_dropdown = Window_set_dropdown_button(136, 16, 54, 14, 80, " Sort", 0, + 1, 1, RIGHT_SIDE|LEFT_SIDE, 0); // 23 + Window_dropdown_add_item(sort_dropdown, 0, "Hue/Light"); + Window_dropdown_add_item(sort_dropdown, 1, "Lightness"); + + Window_set_normal_button(NUMERIC_BOX_X,NUMERIC_BOX_Y,NUMERIC_BOX_W,NUMERIC_BOX_H,"" ,0,1,KEY_NONE); // 24 + // Button without outline + Window_display_frame_mono(NUMERIC_BOX_X-1,NUMERIC_BOX_Y-1,NUMERIC_BOX_W+2,NUMERIC_BOX_H+2,MC_Light); + button_used = Window_set_normal_button(247,16,45,14,"Histo",0,1,KEY_NONE);// 25 + // Dessin des petits effets spéciaux pour les boutons [+] et [-] - Draw_thingumajig(263, 74,MC_White,-1); - Draw_thingumajig(280, 74,MC_White,+1); - Draw_thingumajig(263,165,MC_Dark,-1); - Draw_thingumajig(280,165,MC_Dark,+1); + Draw_thingumajig(265, 74,MC_White,-1); + Draw_thingumajig(282, 74,MC_White,+1); + Draw_thingumajig(265,165,MC_Dark,-1); + Draw_thingumajig(282,165,MC_Dark,+1); Display_cursor(); Update_color_count(&used_colors,color_usage); + if (show_used_colors) + Tag_used_colors(1, color_usage); - Hide_cursor(); - Print_in_window(130, 49, "Pixel count:", MC_Dark, MC_Light); - - Update_pixel_count(Fore_color, Fore_color, color_usage); - - Display_cursor(); - Update_window_area(0,0,299,188); do @@ -1012,7 +1154,7 @@ void Button_Palette(void) old_mouse_y=Mouse_Y; old_mouse_k=Mouse_K; clicked_button=Window_clicked_button(); - + switch (clicked_button) { case 0 : // Nulle part @@ -1025,16 +1167,71 @@ void Button_Palette(void) temp_color=(clicked_button==1) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y); if (Mouse_K==RIGHT_SIDE) { - if (Back_color!=temp_color) + // Contextual menu + T_Dropdown_button dropdown; + T_Dropdown_choice *item; + + dropdown.Pos_X =0; + dropdown.Pos_Y =0; + dropdown.Height =0; + dropdown.Dropdown_width=48; + dropdown.First_item =NULL; + dropdown.Bottom_up =1; + + Window_dropdown_add_item(&dropdown, 1, "Copy"); + Window_dropdown_add_item(&dropdown, 2, "Paste"); + + item=Dropdown_activate(&dropdown,Mouse_X,Mouse_Y); + + if (item && item->Number == 1) { + // Copy + Set_clipboard_colors(block_end+1-block_start,working_palette + block_start); + Display_cursor(); + } + else if (item && item->Number == 2) + { + // Paste + int nb_colors; + + // Backup + memcpy(backup_palette,working_palette,sizeof(T_Palette)); + + nb_colors = Get_clipboard_colors(working_palette, block_start); + if (nb_colors>0) + { + memcpy(temp_palette,working_palette,sizeof(T_Palette)); + Set_palette(working_palette); + need_to_remap=1; + Display_cursor(); + Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); + } + else + { + Display_cursor(); + } + } + else if (Back_color!=temp_color) + { + // Just select back color + Back_color=temp_color; // 4 blocks de back_color entourant la fore_color - Window_rectangle(260,89,24,4,Back_color); - Window_rectangle(260,157,24,4,Back_color); - Window_rectangle(260,93,4,64,Back_color); - Window_rectangle(280,93,4,64,Back_color); - Update_window_area(260,89,32,72); + Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color); + Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color); + Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color); + Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color); + Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); + + Display_cursor(); } + else + { + Display_cursor(); + } + + + Window_dropdown_clear_items(&dropdown); } else { @@ -1051,21 +1248,18 @@ void Button_Palette(void) Tag_color_range(block_start,block_end); // Affichage du n° de la couleur sélectionnée - Window_rectangle(237,36,56,7,MC_Light); + Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light); Num2str(Fore_color,str,3); - Print_in_window(237, 36, str,MC_Black,MC_Light); - Update_window_area(237,36,56,7); - - // Pixel count - Update_pixel_count(Fore_color, Fore_color, color_usage); + Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); + Update_window_area(COLOR_X,COLOR_Y,56,7); // Affichage des jauges - Window_rectangle(176,172,84,7,MC_Light); + Window_rectangle(NUMERIC_R_X,NUMERIC_Y,72,7,MC_Light); Display_sliders(red_slider,green_slider,blue_slider,0,working_palette); // Affichage dans le block de visu de la couleur en cours - Window_rectangle(264,93,16,64,Fore_color); - Update_window_area(264,93,16,64); + Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); + Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); memcpy(backup_palette ,working_palette,sizeof(T_Palette)); memcpy(temp_palette,working_palette,sizeof(T_Palette)); @@ -1086,16 +1280,13 @@ void Button_Palette(void) Num2str(block_start,str ,3); Num2str(block_end ,str+4,3); str[3]=26; // Flèche vers la droite - Print_in_window(237, 36, str,MC_Black,MC_Light); + Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); - // Pixel count - Update_pixel_count(block_start, block_end, color_usage); - // Affichage des jauges Display_sliders(red_slider,green_slider,blue_slider,1,NULL); // Affichage dans le block de visu du bloc (dégradé) en cours - Display_grad_block_in_window(264,93,block_start,block_end); + Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,block_start,block_end); } else if (first_color>temp_color) { @@ -1106,37 +1297,31 @@ void Button_Palette(void) Num2str(block_start,str ,3); Num2str(block_end ,str+4,3); str[3]=26; // Flèche vers la droite - Print_in_window(237, 36, str,MC_Black,MC_Light); + Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); - // Pixel count - Update_pixel_count(block_start, block_end, color_usage); - // Affichage des jauges Display_sliders(red_slider,green_slider,blue_slider,1,NULL); // Affichage dans le block de visu du bloc (dégradé) en cours - Display_grad_block_in_window(264,93,block_start,block_end); + Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,block_start,block_end); } else { block_start=block_end=first_color; - Window_rectangle(176,172,84,7,MC_Light); + Window_rectangle(NUMERIC_R_X,NUMERIC_Y,72,7,MC_Light); // Affichage du n° de la couleur sélectionnée - Window_rectangle(261,36,32,7,MC_Light); - Update_window_area(261,36,32,7); + Window_rectangle(COLOR_X+24,COLOR_Y,32,7,MC_Light); + Update_window_area(COLOR_X+24,COLOR_Y,32,7); Num2str(Fore_color,str,3); - Print_in_window(237, 36, str,MC_Black,MC_Light); + Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); - // Pixel count - Update_pixel_count(Fore_color, Fore_color, color_usage); - // Affichage des jauges Display_sliders(red_slider,green_slider,blue_slider,0,working_palette); // Affichage dans le block de visu de la couleur en cours - Window_rectangle(264,93,16,64,Fore_color); - Update_window_area(264,93,16,64); + Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); + Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); } // On tagge le bloc (ou la couleur) @@ -1145,8 +1330,9 @@ void Button_Palette(void) last_color=temp_color; } + Display_cursor(); } - Display_cursor(); + } break; case 2 : // Jauge rouge @@ -1155,8 +1341,8 @@ void Button_Palette(void) { if(Palette_view_is_RGB) { - Set_red(Fore_color,(Color_max-red_slider->Position)*255/Color_max,working_palette); - Format_componant((working_palette[Fore_color].R)*Color_count/256,str); + Set_red(Fore_color,Reduce_component(Color_max-red_slider->Position),working_palette); + Format_component((working_palette[Fore_color].R)*Color_count/256,str); } else { @@ -1167,28 +1353,40 @@ void Button_Palette(void) &working_palette[Fore_color].R, &working_palette[Fore_color].G, &working_palette[Fore_color].B); - Format_componant((int)255-red_slider->Position,str); + Format_component((int)255-red_slider->Position,str); } - Print_counter(176,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); } else { if(Palette_view_is_RGB) { for (i=block_start; i<=block_end; i++) - Set_red(i,temp_palette[i].R+(Color_max-red_slider->Position)*255/Color_max,working_palette); + Set_red(i,temp_palette[i].R+Reduce_component(Color_max-red_slider->Position),working_palette); } else { + byte greys=0; + byte non_greys=0; + // Check if the range contains both greys and non-greys for (i=block_start; i<=block_end; i++) + if (temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B) + non_greys=1; + else + greys=1; + + for (i=block_start; i<=block_end; i++) + { + byte is_grey = temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B; Set_HSL( temp_palette, working_palette, i, - Color_max-red_slider->Position, - Color_max-green_slider->Position, + is_grey && greys && non_greys ? 0 : Color_max-red_slider->Position, + is_grey && greys && non_greys ? 0 : Color_max-green_slider->Position, Color_max-blue_slider->Position ); + } } if (red_slider->Position>Color_max) @@ -1208,7 +1406,7 @@ void Button_Palette(void) // Jauge nulle: strcpy(str,"± 0"); } - Print_counter(176,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); } @@ -1223,8 +1421,8 @@ void Button_Palette(void) { if(Palette_view_is_RGB) { - Set_green (Fore_color,(Color_max-green_slider->Position)*255/Color_max,working_palette); - Format_componant(working_palette[Fore_color].G*Color_count/256,str); + Set_green (Fore_color,Reduce_component(Color_max-green_slider->Position),working_palette); + Format_component(working_palette[Fore_color].G*Color_count/256,str); } else { @@ -1235,28 +1433,40 @@ void Button_Palette(void) &working_palette[Fore_color].R, &working_palette[Fore_color].G, &working_palette[Fore_color].B); - Format_componant((int)255-green_slider->Position,str); + Format_component((int)255-green_slider->Position,str); } - Print_counter(203,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); } else { if(Palette_view_is_RGB) { for (i=block_start; i<=block_end; i++) - Set_green (i,temp_palette[i].G+(Color_max-green_slider->Position)*255/Color_max,working_palette); + Set_green (i,temp_palette[i].G+Reduce_component(Color_max-green_slider->Position),working_palette); } else { - for (i=block_start; i<=block_end; i++) + byte greys=0; + byte non_greys=0; + // Check if the range contains both greys and non-greys + for (i=block_start; i<=block_end; i++) + if (temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B) + non_greys=1; + else + greys=1; + + for (i=block_start; i<=block_end; i++) + { + byte is_grey = temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B; Set_HSL( temp_palette, working_palette, i, - Color_max-red_slider->Position, - Color_max-green_slider->Position, + is_grey && greys && non_greys ? 0 : Color_max-red_slider->Position, + is_grey && greys && non_greys ? 0 : Color_max-green_slider->Position, Color_max-blue_slider->Position ); + } } if (green_slider->Position>Color_max) @@ -1276,7 +1486,7 @@ void Button_Palette(void) // Jauge nulle: strcpy(str,"± 0"); } - Print_counter(203,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); } need_to_remap=1; @@ -1291,8 +1501,8 @@ void Button_Palette(void) { if(Palette_view_is_RGB) { - Set_blue (Fore_color,(Color_max-blue_slider->Position)*255/Color_max,working_palette); - Format_componant(working_palette[Fore_color].B*Color_count/256,str); + Set_blue (Fore_color,Reduce_component(Color_max-blue_slider->Position),working_palette); + Format_component(working_palette[Fore_color].B*Color_count/256,str); } else { @@ -1303,28 +1513,40 @@ void Button_Palette(void) &working_palette[Fore_color].R, &working_palette[Fore_color].G, &working_palette[Fore_color].B); - Format_componant((int)255-blue_slider->Position,str); + Format_component((int)255-blue_slider->Position,str); } - Print_counter(230,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } else { if(Palette_view_is_RGB) { for (i=block_start; i<=block_end; i++) - Set_blue(i,temp_palette[i].B+(Color_max-blue_slider->Position)*255/Color_max,working_palette); + Set_blue(i,temp_palette[i].B+Reduce_component(Color_max-blue_slider->Position),working_palette); } else { + byte greys=0; + byte non_greys=0; + // Check if the range contains both greys and non-greys for (i=block_start; i<=block_end; i++) + if (temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B) + non_greys=1; + else + greys=1; + + for (i=block_start; i<=block_end; i++) + { + byte is_grey = temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B; Set_HSL( temp_palette, working_palette, i, - Color_max-red_slider->Position, - Color_max-green_slider->Position, + is_grey && greys && non_greys ? 0 : Color_max-red_slider->Position, + is_grey && greys && non_greys ? 0 : Color_max-green_slider->Position, Color_max-blue_slider->Position ); + } } if (blue_slider->Position>Color_max) @@ -1344,7 +1566,7 @@ void Button_Palette(void) // Jauge nulle: strcpy(str,"± 0"); } - Print_counter(230,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } need_to_remap=1; @@ -1353,16 +1575,83 @@ void Button_Palette(void) Set_palette(working_palette); break; - case 5 : // Default - memcpy(backup_palette,working_palette,sizeof(T_Palette)); - memcpy(working_palette,Gfx->Default_palette,sizeof(T_Palette)); - memcpy(temp_palette,Gfx->Default_palette,sizeof(T_Palette)); - Set_palette(Gfx->Default_palette); + case 5 : // Merge + if (block_start!=block_end) + { + dword sum_r=0, sum_g=0, sum_b=0, used=0; + + memcpy(backup_palette,working_palette,sizeof(T_Palette)); + // Compute weighted average + for (i=block_start; i<=block_end; i++) + { + used+=color_usage[i]; + sum_r+=working_palette[i].R * color_usage[i]; + sum_g+=working_palette[i].G * color_usage[i]; + sum_b+=working_palette[i].B * color_usage[i]; + } + // Do normal average if no pixels used + if (used==0) + { + sum_r=sum_g=sum_b=used=0; + for (i=block_start; i<=block_end; i++) + { + used+=1; + sum_r+=working_palette[i].R; + sum_g+=working_palette[i].G; + sum_b+=working_palette[i].B; + } + } + for (i=block_start; i<=block_end; i++) + { + Set_red (i,sum_r/used,working_palette); + Set_green(i,sum_g/used,working_palette); + Set_blue (i,sum_b/used,working_palette); + } + } + else + { + temp_color=Wait_click_in_palette(Window_palette_button_list); + if (temp_color>=0) + { + dword sum_r=0, sum_g=0, sum_b=0, used; + memcpy(backup_palette,working_palette,sizeof(T_Palette)); + + // Compute weighted average + used=color_usage[temp_color]+color_usage[Fore_color]; + if (used) + { + sum_r=(working_palette[temp_color].R * color_usage[temp_color] + + working_palette[Fore_color].R * color_usage[Fore_color]) + / used; + sum_g=(working_palette[temp_color].G * color_usage[temp_color] + + working_palette[Fore_color].G * color_usage[Fore_color]) + / used; + sum_b=(working_palette[temp_color].B * color_usage[temp_color] + + working_palette[Fore_color].B * color_usage[Fore_color]) + / used; + } + else // Normal average + { + sum_r=(working_palette[temp_color].R+working_palette[Fore_color].R)/2; + sum_g=(working_palette[temp_color].G+working_palette[Fore_color].G)/2; + sum_b=(working_palette[temp_color].B+working_palette[Fore_color].B)/2; + } + Set_red (temp_color,sum_r,working_palette); + Set_green(temp_color,sum_g,working_palette); + Set_blue (temp_color,sum_b,working_palette); + Set_red (Fore_color,sum_r,working_palette); + Set_green(Fore_color,sum_g,working_palette); + Set_blue (Fore_color,sum_b,working_palette); + + Wait_end_of_click(); + } + } Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); // On prépare la "modifiabilité" des nouvelles couleurs + Set_palette(working_palette); memcpy(temp_palette,working_palette,sizeof(T_Palette)); - need_to_remap=1; + break; case 6 : // Grey scale @@ -1420,22 +1709,22 @@ void Button_Palette(void) Num2str(block_end ,str+4,3); str[3]=26; // Flèche vers la droite // Affichage dans le block de visu du bloc (dégradé) en cours - Display_grad_block_in_window(264,93,block_start,block_end); + Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,block_start,block_end); } else { // Cas d'une seule couleur Num2str(Fore_color,str,3); - Window_rectangle(237,36,56,7,MC_Light); + Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light); // Affichage dans le block de visu de la couleur en cours - Window_rectangle(264,93,16,64,Fore_color); + Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); } - Print_in_window(237, 36, str,MC_Black,MC_Light); + Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // On tag le bloc (ou la couleur) Tag_color_range(block_start,block_end); + if (show_used_colors) + Tag_used_colors(1, color_usage); - Update_pixel_count(block_start, block_end, color_usage); - need_to_remap=1; Set_palette(working_palette); @@ -1474,20 +1763,19 @@ void Button_Palette(void) Num2str(block_end ,str+4,3); str[3]=26; // Flèche vers la droite // Affichage dans le block de visu du bloc (dégradé) en cours - Display_grad_block_in_window(264,93,block_start,block_end); + Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,block_start,block_end); } else { // Cas d'une seule couleur Num2str(Fore_color,str,3); - Window_rectangle(237,36,56,7,MC_Light); + Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light); // Affichage dans le block de visu de la couleur en cours - Window_rectangle(264,93,16,64,Fore_color); + Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); } - Print_in_window(237, 36, str,MC_Black,MC_Light); + Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // On tag le bloc (ou la couleur) Tag_color_range(block_start,block_end); - Update_pixel_count(block_start, block_end, color_usage); need_to_remap=1; @@ -1529,38 +1817,23 @@ void Button_Palette(void) case 11: // Reduce memcpy(backup_palette, working_palette, sizeof(T_Palette)); - switch(Window_attribute2) // Get the dropdown value + if (Window_attribute2==0) // User picked "other" choice { - case 0: // 128 - reduce_colors_number = 128; - break; - case 1: // 64 - reduce_colors_number = 64; - break; - case 2: // 32 - reduce_colors_number = 32; - break; - case 3: // 16 - reduce_colors_number = 16; - break; - case 4: // 8 - reduce_colors_number = 8; - break; - case 5: // 4 - reduce_colors_number = 4; - break; - case 6: // 2 - reduce_colors_number = 2; - break; - case 7: // other - reduce_colors_number - = Requester_window("Enter the max. number of colors", + int choice; + + choice=Requester_window("Enter the max. number of colors", reduce_colors_number); - if (reduce_colors_number < 2 || reduce_colors_number >= 256) - reduce_colors_number = -1; - break; + + if (choice < 2 || choice > 256) + break; // Cancel + + reduce_colors_number = choice; } - if (reduce_colors_number > 0) + else + // Each other dropdown item has a number of colors as id. + reduce_colors_number = Window_attribute2; + + if (reduce_colors_number >= 2) { if (!image_is_backed_up) { @@ -1600,8 +1873,9 @@ void Button_Palette(void) need_to_remap=1; break; - case 15 : // Used > open histogram - Window_Histogram(block_start, block_end, color_usage); + case 15 : // Used : show usage tags + show_used_colors = !show_used_colors; + Tag_used_colors(show_used_colors, color_usage); break; case 16 : // Zap unused @@ -1644,25 +1918,25 @@ void Button_Palette(void) { (red_slider->Position)--; Window_draw_slider(red_slider); - Set_red(Fore_color,(Color_max-red_slider->Position)*255/Color_max,working_palette); - Format_componant(working_palette[Fore_color].R*Color_count/256,str); - Print_counter(176,172,str,MC_Black,MC_Light); + Set_red(Fore_color,Reduce_component(Color_max-red_slider->Position),working_palette); + Format_component(working_palette[Fore_color].R*Color_count/256,str); + Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); } if (green_slider->Position) { (green_slider->Position)--; Window_draw_slider(green_slider); - Set_green (Fore_color,(Color_max-green_slider->Position)*255/Color_max,working_palette); - Format_componant(working_palette[Fore_color].G*Color_count/256,str); - Print_counter(203,172,str,MC_Black,MC_Light); + Set_green (Fore_color,Reduce_component(Color_max-green_slider->Position),working_palette); + Format_component(working_palette[Fore_color].G*Color_count/256,str); + Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); } if (blue_slider->Position) { (blue_slider->Position)--; Window_draw_slider(blue_slider); - Set_blue (Fore_color,(Color_max-blue_slider->Position)*255/Color_max,working_palette); - Format_componant(working_palette[Fore_color].B*Color_count/256,str); - Print_counter(230,172,str,MC_Black,MC_Light); + Set_blue (Fore_color,Reduce_component(Color_max-blue_slider->Position),working_palette); + Format_component(working_palette[Fore_color].B*Color_count/256,str); + Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } } else @@ -1685,9 +1959,9 @@ void Button_Palette(void) for (i=block_start; i<=block_end; i++) { - Set_red(i,temp_palette[i].R+(Color_max-red_slider->Position)*255/Color_max,working_palette); - Set_green (i,temp_palette[i].G+(Color_max-green_slider->Position)*255/Color_max,working_palette); - Set_blue (i,temp_palette[i].B+(Color_max-blue_slider->Position)*255/Color_max,working_palette); + Set_red(i,temp_palette[i].R+Reduce_component(Color_max-red_slider->Position),working_palette); + Set_green (i,temp_palette[i].G+Reduce_component(Color_max-green_slider->Position),working_palette); + Set_blue (i,temp_palette[i].B+Reduce_component(Color_max-blue_slider->Position),working_palette); } // -- red -- @@ -1708,7 +1982,7 @@ void Button_Palette(void) // Jauge nulle: strcpy(str,"± 0"); } - Print_counter(176,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); // -- green -- @@ -1729,7 +2003,7 @@ void Button_Palette(void) // Jauge nulle: strcpy(str,"± 0"); } - Print_counter(203,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); // -- blue -- @@ -1750,7 +2024,7 @@ void Button_Palette(void) // Jauge nulle: strcpy(str,"± 0"); } - Print_counter(230,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } need_to_remap=1; @@ -1769,25 +2043,25 @@ void Button_Palette(void) { (red_slider->Position)++; Window_draw_slider(red_slider); - Set_red(Fore_color,(Color_max-red_slider->Position)*255/Color_max,working_palette); - Format_componant(working_palette[Fore_color].R*Color_count/256,str); - Print_counter(176,172,str,MC_Black,MC_Light); + Set_red(Fore_color,Reduce_component(Color_max-red_slider->Position),working_palette); + Format_component(working_palette[Fore_color].R*Color_count/256,str); + Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); } if (green_slider->PositionPosition)++; Window_draw_slider(green_slider); - Set_green (Fore_color,(Color_max-green_slider->Position)*255/Color_max,working_palette); - Format_componant(working_palette[Fore_color].G*Color_count/256,str); - Print_counter(203,172,str,MC_Black,MC_Light); + Set_green (Fore_color,Reduce_component(Color_max-green_slider->Position),working_palette); + Format_component(working_palette[Fore_color].G*Color_count/256,str); + Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); } if (blue_slider->PositionPosition)++; Window_draw_slider(blue_slider); - Set_blue (Fore_color,(Color_max-blue_slider->Position)*255/Color_max,working_palette); - Format_componant(working_palette[Fore_color].B*Color_count/256,str); - Print_counter(230,172,str,MC_Black,MC_Light); + Set_blue (Fore_color,Reduce_component(Color_max-blue_slider->Position),working_palette); + Format_component(working_palette[Fore_color].B*Color_count/256,str); + Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } } else @@ -1810,9 +2084,9 @@ void Button_Palette(void) for (i=block_start; i<=block_end; i++) { - Set_red(i,temp_palette[i].R+(Color_max-red_slider->Position)*255/Color_max,working_palette); - Set_green (i,temp_palette[i].G+(Color_max-green_slider->Position)*255/Color_max,working_palette); - Set_blue (i,temp_palette[i].B+(Color_max-blue_slider->Position)*255/Color_max,working_palette); + Set_red(i,temp_palette[i].R+Reduce_component(Color_max-red_slider->Position),working_palette); + Set_green (i,temp_palette[i].G+Reduce_component(Color_max-green_slider->Position),working_palette); + Set_blue (i,temp_palette[i].B+Reduce_component(Color_max-blue_slider->Position),working_palette); } // -- red -- @@ -1833,7 +2107,7 @@ void Button_Palette(void) // Jauge nulle: strcpy(str,"± 0"); } - Print_counter(176,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); // -- green -- @@ -1854,7 +2128,7 @@ void Button_Palette(void) // Jauge nulle: strcpy(str,"± 0"); } - Print_counter(203,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); // -- blue -- @@ -1875,7 +2149,7 @@ void Button_Palette(void) // Jauge nulle: strcpy(str,"± 0"); } - Print_counter(230,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } need_to_remap=1; @@ -1958,34 +2232,35 @@ void Button_Palette(void) memcpy(temp_palette,working_palette,sizeof(T_Palette)); memcpy(backup_palette, working_palette,sizeof(T_Palette)); + Hide_cursor(); + Palette_view_is_RGB = !Palette_view_is_RGB; - if(! Palette_view_is_RGB) { // On passe en HSL - Print_in_window(184,71,"H",MC_Dark,MC_Light); - Print_in_window(211,71,"S",MC_Dark,MC_Light); - Print_in_window(238,71,"L",MC_Dark,MC_Light); - Componant_unit(256); + Print_RGB_or_HSL(1); + Component_unit(256); // Display the + and - button as disabled - Window_draw_normal_bouton(266, 74,12,11,"+",0,0); - Window_draw_normal_bouton(266,165,12,11,"-",0,0); + Window_draw_normal_bouton(BUTTON_PLUS_X, BUTTON_PLUS_Y,12,11,"+",0,0); + Window_draw_normal_bouton(BUTTON_MINUS_X,BUTTON_MINUS_Y,12,11,"-",0,0); } else { // On passe en RGB - Print_in_window(184,71,"R",MC_Dark,MC_Light); - Print_in_window(211,71,"G",MC_Dark,MC_Light); - Print_in_window(238,71,"B",MC_Dark,MC_Light); - Componant_unit(RGB_scale); + Print_RGB_or_HSL(0); + Component_unit(RGB_scale); // Display the + and - button as enabled - Window_draw_normal_bouton(266, 74,12,11,"+",0,1); - Window_draw_normal_bouton(266,165,12,11,"-",0,1); + Window_draw_normal_bouton(BUTTON_PLUS_X, BUTTON_PLUS_Y,12,11,"+",0,1); + Window_draw_normal_bouton(BUTTON_MINUS_X,BUTTON_MINUS_Y,12,11,"-",0,1); } Display_sliders(red_slider,green_slider,blue_slider,(block_start!=block_end),working_palette); - Update_window_area(265,73,14,103); + + Display_cursor(); + + Update_window_area(BUTTON_PLUS_X-1,BUTTON_PLUS_Y-1,14,14); + Update_window_area(BUTTON_MINUS_X-1,BUTTON_MINUS_Y-1,14,14); break; case 23 : // Sort palette @@ -1996,6 +2271,9 @@ void Button_Palette(void) byte remap_table[256]; byte inverted_table[256]; byte begin, end; + long lightness; + long old_lightness; + if(block_start==block_end) { @@ -2018,8 +2296,8 @@ void Button_Palette(void) image_is_backed_up=1; } - if(Window_attribute1==LEFT_SIDE) - // Laft click on button: Sort by Hue (H) and Lightness (L) + if(Window_attribute2==0) + // Sort by Hue (H) and Lightness (L) while(swap==1) { swap=0; @@ -2050,19 +2328,17 @@ void Button_Palette(void) } } - else // Right click > Sort only on L + else // Sort only on perceived lightness while(swap==1) { swap=0; - l=255; - for(temp_color=begin;temp_color<=end;temp_color++) + lightness=Perceptual_lightness(working_palette+begin); + for(temp_color=begin+1;temp_color<=end;temp_color++) { - ol=l; - RGB_to_HSL(working_palette[temp_color].R, - working_palette[temp_color].G, - working_palette[temp_color].B,&h,&s,&l); + old_lightness=lightness; + lightness=Perceptual_lightness(working_palette+temp_color); - if(l>ol) + if(lightness>old_lightness) { // Swap color with the previous one SWAP_BYTES(working_palette[temp_color].R, working_palette[temp_color-1].R) @@ -2089,6 +2365,95 @@ void Button_Palette(void) need_to_remap=1; } break; + case 24: // R G B value: Hex entry + { + char str[7]; + unsigned int new_color; + + Hide_cursor(); + Print_in_window(NUMERIC_BOX_X+2,NUMERIC_BOX_Y+2,"Hex",MC_Black,MC_Light); + // Clear out remaining area + Window_rectangle(NUMERIC_BOX_X+1+3*8,NUMERIC_BOX_Y+1,NUMERIC_BOX_W-3-3*8, NUMERIC_BOX_H-3,MC_Light); + Update_window_area(NUMERIC_BOX_X+1+3*8,NUMERIC_BOX_Y+1,NUMERIC_BOX_W-3-3*8, NUMERIC_BOX_H-3); + + str[0]='\0'; + Display_cursor(); + if (Readline(NUMERIC_BOX_X+NUMERIC_BOX_W-2-6*8, NUMERIC_BOX_Y+2, str, 6, INPUT_TYPE_HEXA)) + { + int length = strlen(str); + short new_red, new_blue, new_green; + + if (length==3 || length==6) + { + sscanf(str, "%x", &new_color); + if (length==3) + { + new_color = + ((new_color&0xF00)*0x1100) | + ((new_color&0x0F0)*0x110) | + ((new_color&0x00F)*0x11); + } + new_red=(new_color&0xFF0000) >> 16; + new_green=(new_color&0x00FF00) >> 8; + new_blue=(new_color&0x0000FF); + + // Backup + memcpy(backup_palette,working_palette,sizeof(T_Palette)); + // Assign color + for (i=block_start;i<=block_end;i++) + { + Set_red(i,new_red,working_palette); + Set_green (i,new_green,working_palette); + Set_blue (i,new_blue,working_palette); + } + // On prépare la "modifiabilité" des nouvelles couleurs + Set_palette(working_palette); + memcpy(temp_palette,working_palette,sizeof(T_Palette)); + need_to_remap=1; + } + } + // Clear out numeric area + Window_rectangle(NUMERIC_BOX_X+1,NUMERIC_BOX_Y+1,NUMERIC_BOX_W-2, NUMERIC_BOX_H-2,MC_Light); + Update_window_area(NUMERIC_BOX_X+1,NUMERIC_BOX_Y+1,NUMERIC_BOX_W-2, NUMERIC_BOX_H-2); + Display_cursor(); + Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); + } + break; + + case 25: // Number of colors used: Open histogram + { + int selected_col; + + selected_col=Window_Histogram(block_start, block_end, color_usage); + if (selected_col!=-1) + { + // Tag selected color + Fore_color=first_color=last_color=block_start=block_end=selected_col; + Tag_color_range(block_start,block_end); + + // Affichage du n° de la couleur sélectionnée + Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light); + Num2str(Fore_color,str,3); + Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); + Update_window_area(COLOR_X,COLOR_Y,56,7); + + // Affichage des jauges + Window_rectangle(NUMERIC_R_X,NUMERIC_Y,72,7,MC_Light); + Display_sliders(red_slider,green_slider,blue_slider,0,working_palette); + + // Affichage dans le block de visu de la couleur en cours + Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); + Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); + + memcpy(backup_palette ,working_palette,sizeof(T_Palette)); + memcpy(temp_palette,working_palette,sizeof(T_Palette)); + + } + Display_cursor(); + Input_sticky_control=0; + Wait_end_of_click(); + break; + } } @@ -2110,12 +2475,10 @@ void Button_Palette(void) Tag_color_range(block_start,block_end); // Affichage du n° de la couleur sélectionnée Num2str(Fore_color,str,3); - Print_in_window(237, 36, str,MC_Black,MC_Light); + Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // Affichage dans le block de visu de la couleur en cours - Window_rectangle(264,93,16,64,Fore_color); - Update_window_area(264,93,16,64); - // Pixel count - Update_pixel_count(Fore_color, Fore_color, color_usage); + Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); + Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); Display_cursor(); } Key=0; @@ -2134,12 +2497,10 @@ void Button_Palette(void) Tag_color_range(block_start,block_end); // Affichage du n° de la couleur sélectionnée Num2str(Fore_color,str,3); - Print_in_window(237, 36, str,MC_Black,MC_Light); + Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // Affichage dans le block de visu de la couleur en cours - Window_rectangle(264,93,16,64,Fore_color); - Update_window_area(264,93,16,64); - // Pixel count - Update_pixel_count(Fore_color, Fore_color, color_usage); + Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); + Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); Display_cursor(); } Key=0; @@ -2148,11 +2509,11 @@ void Button_Palette(void) { Back_color--; Hide_cursor(); - Window_rectangle(260,89,24,4,Back_color); - Window_rectangle(260,157,24,4,Back_color); - Window_rectangle(260,93,4,64,Back_color); - Window_rectangle(280,93,4,64,Back_color); - Update_window_area(260,89,32,72); + Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color); + Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color); + Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color); + Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color); + Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); Display_cursor(); Key=0; } @@ -2160,11 +2521,11 @@ void Button_Palette(void) { Back_color++; Hide_cursor(); - Window_rectangle(260,89,24,4,Back_color); - Window_rectangle(260,157,24,4,Back_color); - Window_rectangle(260,93,4,64,Back_color); - Window_rectangle(280,93,4,64,Back_color); - Update_window_area(260,89,32,72); + Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color); + Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color); + Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color); + Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color); + Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); Display_cursor(); Key=0; } @@ -2208,11 +2569,11 @@ void Button_Palette(void) { Back_color=color; // 4 blocks de back_color entourant la fore_color - Window_rectangle(260,89,24,4,Back_color); - Window_rectangle(260,157,24,4,Back_color); - Window_rectangle(260,93,4,64,Back_color); - Window_rectangle(280,93,4,64,Back_color); - Update_window_area(260,89,32,72); + Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color); + Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color); + Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color); + Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color); + Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); } } else @@ -2221,20 +2582,17 @@ void Button_Palette(void) Tag_color_range(block_start,block_end); // Affichage du n° de la couleur sélectionnée - Window_rectangle(261,36,32,7,MC_Light); - Update_window_area(261,36,32,7); + Window_rectangle(COLOR_X+24,COLOR_Y,32,7,MC_Light); + Update_window_area(COLOR_X+24,COLOR_Y,32,7); Num2str(Fore_color,str,3); - Print_in_window(237, 36, str,MC_Black,MC_Light); + Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); - // Pixel count - Update_pixel_count(Fore_color, Fore_color, color_usage); - // Affichage des jauges Display_sliders(red_slider,green_slider,blue_slider,0,working_palette); // Affichage dans le block de visu de la couleur en cours - Window_rectangle(264,93,16,64,Fore_color); - Update_window_area(264,93,16,64); + Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); + Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); memcpy(backup_palette ,working_palette,sizeof(T_Palette)); memcpy(temp_palette,working_palette,sizeof(T_Palette)); @@ -2254,6 +2612,28 @@ void Button_Palette(void) // Close (confirm) clicked_button=14; } + else if (Key == (SDLK_c|MOD_CTRL)) // Ctrl-C + { + Set_clipboard_colors(block_end+1-block_start,working_palette + block_start); + } + else if (Key == (SDLK_v|MOD_CTRL)) // Ctrl-V + { + int nb_colors; + + Hide_cursor(); + // Backup + memcpy(backup_palette,working_palette,sizeof(T_Palette)); + + nb_colors = Get_clipboard_colors(working_palette, block_start); + if (nb_colors>0) + { + memcpy(temp_palette,working_palette,sizeof(T_Palette)); + Set_palette(working_palette); + need_to_remap=1; + Display_cursor(); + Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); + } + } } if (need_to_remap) @@ -2265,8 +2645,12 @@ void Button_Palette(void) Remap_screen_after_menu_colors_change(); // Puis on remet les trucs qui ne devaient pas changer Window_draw_palette_bouton(5,79); - Window_rectangle(260,89,24,72,Back_color); - Display_grad_block_in_window(264,93,block_start,block_end); + if (show_used_colors) + Tag_used_colors(1, color_usage); + Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H,Back_color); + Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); + + Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,block_start,block_end); Update_window_area(8,82,16*10,5*16); @@ -2319,8 +2703,6 @@ void Button_Palette(void) } - - //---------------------- Menu de palettes secondaires ------------------------ void Button_Secondary_palette(void) @@ -2456,6 +2838,7 @@ void Button_Secondary_palette(void) { Set_palette_RGB_scale(rgb_scale); Set_palette(Main_palette); + Compute_optimal_menu_colors(Main_palette); } if (clicked_button==1) @@ -2473,6 +2856,76 @@ void Button_Secondary_palette(void) { Change_palette_cells(); Display_menu(); - Display_sprite_in_menu(BUTTON_PAL_LEFT,18+(Config.Palette_vertical!=0)); + Display_sprite_in_menu(BUTTON_PAL_LEFT,Config.Palette_vertical?MENU_SPRITE_VERTICAL_PALETTE_SCROLL:-1); + Draw_menu_button(BUTTON_PAL_LEFT,BUTTON_RELEASED); + Draw_menu_button(BUTTON_PAL_RIGHT,BUTTON_RELEASED); } } + +// ========= Clipboard management ============== + +int Palette_clipboard_count=0; +T_Palette Palette_clipboard; + +/// Put some colors in the clipboard. +/// @param nb_colors Number of colors to push +/// @param colors First color of the input array +void Set_clipboard_colors(int nb_colors, T_Components *colors) +{ + Palette_clipboard_count=nb_colors; + if (nb_colors) + { + memcpy(Palette_clipboard, colors, nb_colors*sizeof(T_Components)); + } +} + +/// Get some RGB colors from clipboard. +/// @param palette Target palette +/// @param start_color Index of first color to replace +/// @return Number of colors retrieved (0-256) +int Get_clipboard_colors(T_Palette palette, byte start_color) +{ + int nb_colors = Palette_clipboard_count; + + if (nb_colors==0) + return 0; + + if (start_color+nb_colors > 256) + { + nb_colors=256-start_color; + } + memcpy(palette+start_color, Palette_clipboard, nb_colors*sizeof(T_Components)); + return nb_colors; +} + +/// Get the favorite color to use for GUI's black,dark,light or white. +const T_Components * Favorite_GUI_color(byte color_index) +{ + static const T_Components cpc_colors[4] = { + { 0, 0, 0}, + { 0, 0,128}, // Dark blue + {128,128,128}, // Grey + {255,255,255} + }; + + if (RGB_scale==3) + { + // Check if ALL GUI colors are compatible with /rgb 3 + int i; + for (i=0; i<4; i++) + { + T_Components col; + col=Gfx->Default_palette[Gfx->Color[i]]; + if ((col.R!=255 && col.R!=128 && col.R!=0) + ||(col.G!=255 && col.G!=128 && col.G!=0) + ||(col.B!=255 && col.B!=128 && col.B!=0)) + // Specialized colors for CPC palette + return &cpc_colors[color_index]; + } + // Skin has suitable colors + return &(Gfx->Default_palette[Gfx->Color[color_index]]); + } + else + // Should be Config.Fav_menu_colors[index] if using user colors + return &(Gfx->Default_palette[Gfx->Color[color_index]]); +} diff --git a/src/palette.h b/src/palette.h index 65d3e2e7..5b68e1d4 100644 --- a/src/palette.h +++ b/src/palette.h @@ -31,6 +31,8 @@ void Button_Secondary_palette(void); /// Choose the number of graduations for RGB components, from 2 to 256. void Set_palette_RGB_scale(int); +int Get_palette_RGB_scale(void); + /// /// Scale a component (R, G or B) according to the current RGB graduations. /// Returns the resulting value, in the [0-255] range. @@ -42,3 +44,17 @@ byte Round_palette_component(byte comp); @param not_picture 0 if the caller is the palette screen, 1 if it's a preview in the file selector. */ void Set_nice_menu_colors(dword * color_usage,int not_picture); + +/// Put some colors in the clipboard. +/// @param nb_colors Number of colors to push +/// @param colors First color of the input array +void Set_clipboard_colors(int nb_colors, T_Components *colors); + +/// Get some RGB colors from clipboard. +/// @param palette Target palette +/// @param start_color Index of first color to replace +/// @return Number of colors retrieved (0-256) +int Get_clipboard_colors(T_Palette palette, byte start_color); + +/// Get the favorite color to use for GUI's black,dark,light or white. +const T_Components * Favorite_GUI_color(byte color_index); diff --git a/src/readini.c b/src/readini.c index 9dbd91a0..15473878 100644 --- a/src/readini.c +++ b/src/readini.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Peter Gordon Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues @@ -32,6 +33,7 @@ #include "global.h" #include "misc.h" #include "readini.h" +#include "setup.h" void Load_INI_clear_string(char * str, byte keep_comments) { @@ -432,6 +434,13 @@ int Load_INI(T_Config * conf) char value_label[1024]; Line_number_in_INI_file=0; + +#if defined(__WIZ__) || defined(__CAANOO__) + conf->Stylus_mode = 1; +#else + conf->Stylus_mode = 0; +#endif + // On alloue les zones de mémoire: buffer=(char *)malloc(1024); @@ -439,14 +448,14 @@ int Load_INI(T_Config * conf) // On calcule le nom du fichier qu'on manipule: strcpy(filename,Config_directory); - strcat(filename,"gfx2.ini"); + strcat(filename,INI_FILENAME); file=fopen(filename,"r"); if (file==0) { // Si le fichier ini est absent on le relit depuis gfx2def.ini strcpy(filename,Data_directory); - strcat(filename,"gfx2def.ini"); + strcat(filename,INIDEF_FILENAME); file=fopen(filename,"r"); if (file == 0) { @@ -894,6 +903,39 @@ int Load_INI(T_Config * conf) Menu_bars[index].Visible = (values[0] & (1<Right_click_colorpick=0; + // Optional, right mouse button to pick colors (>=2.3) + if (!Load_INI_get_values (file,buffer,"Right_click_colorpick",1,values)) + { + conf->Right_click_colorpick=(values[0]!=0); + } + + conf->Sync_views=1; + // Optional, synced view of main and spare (>=2.3) + if (!Load_INI_get_values (file,buffer,"Sync_views",1,values)) + { + conf->Sync_views=(values[0]!=0); + } + + conf->Swap_buttons=0; + // Optional, key for swap buttons (>=2.3) + if (!Load_INI_get_values (file,buffer,"Swap_buttons",1,values)) + { + switch(values[0]) + { + case 1: + conf->Swap_buttons=MOD_CTRL; + break; + case 2: + conf->Swap_buttons=MOD_ALT; + break; + } + } + + + + // Insert new values here fclose(file); diff --git a/src/readline.c b/src/readline.c index d0292ca6..ce153024 100644 --- a/src/readline.c +++ b/src/readline.c @@ -40,6 +40,13 @@ #include "windows.h" #include "input.h" +// Virtual keyboard is mandatory on these platforms: +#if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) + #ifndef VIRT_KEY + #define VIRT_KEY 1 + #endif +#endif + #define TEXT_COLOR MC_Black #define BACKGROUND_COLOR MC_Light #define CURSOR_COLOR MC_Black @@ -98,8 +105,41 @@ int Valid_character(int c) void Display_whole_string(word x_pos,word y_pos,char * str,byte position) { - Print_in_window(x_pos,y_pos,str,TEXT_COLOR,BACKGROUND_COLOR); - Print_char_in_window(x_pos+(position<<3),y_pos,str[position],CURSOR_COLOR,CURSOR_BACKGROUND_COLOR); + char cursor[2]; + Print_general(x_pos,y_pos,str,TEXT_COLOR,BACKGROUND_COLOR); + + cursor[0]=str[position] ? str[position] : ' '; + cursor[1]='\0'; + Print_general(x_pos+(position<<3)*Menu_factor_X,y_pos,cursor,CURSOR_COLOR,CURSOR_BACKGROUND_COLOR); +} + +void Init_virtual_keyboard(word y_pos, word keyboard_width, word keyboard_height) +{ + int h_pos; + int v_pos; + int parent_window_x=Window_pos_X+2; + + h_pos= Window_pos_X+(keyboard_width-Window_width)*Menu_factor_X/-2; + if (h_pos<0) + h_pos=0; + else if (h_pos+keyboard_width*Menu_factor_X>Screen_width) + h_pos=Screen_width-keyboard_width*Menu_factor_X; + v_pos=Window_pos_Y+(y_pos+9)*Menu_factor_Y; + if (v_pos+(keyboard_height*Menu_factor_Y)>Screen_height) + v_pos=Window_pos_Y+(y_pos-keyboard_height-4)*Menu_factor_Y; + + Hide_cursor(); + Open_popup(h_pos,v_pos,keyboard_width,keyboard_height); + Window_rectangle(1,0,Window_width-1, Window_height-1, MC_Light); + Window_rectangle(0,0,1,Window_height-2, MC_White); + // white border on top left angle, when it exceeds border. + if (parent_window_x>Window_pos_X) + Window_rectangle(0,0,(parent_window_x-Window_pos_X)/Menu_factor_X, 1, MC_White); + Window_rectangle(2,Window_height-2,Window_width-2, 2, MC_Black); + if(keyboard_width<320) + { + Window_rectangle(Window_width-2,2,2,Window_height-2, MC_Black); + } } /**************************************************************************** @@ -143,28 +183,156 @@ byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_siz byte size; word input_key=0; byte is_authorized; - + word window_x=Window_pos_X; + word window_y=Window_pos_Y; byte offset=0; // index du premier caractère affiché + +#ifdef VIRT_KEY + // Virtual keyboard + byte use_virtual_keyboard=0; + static byte caps_lock=0; + word keymapping[] = + { + SDLK_CLEAR,SDLK_BACKSPACE,SDLK_RETURN,KEY_ESC, + '0','1','2','3','4','5','6','7','8','9','.',',', + 'Q','W','E','R','T','Y','U','I','O','P', + 'A','S','D','F','G','H','J','K','L', + SDLK_CAPSLOCK,'Z','X','C','V','B','N','M',' ', + '-','+','*','/','|','\\', + '(',')','{','}','[',']', + '_','=','<','>','%','@', + ':',';','`','\'','"','~', + '!','?','^','&','#','$' + }; +#endif // Si on a commencé à editer par un clic-droit, on vide la chaine. if (Mouse_K==RIGHT_SIDE) str[0]='\0'; - else if (input_type==1 && str[0]!='\0') + else if (input_type==INPUT_TYPE_INTEGER && str[0]!='\0') snprintf(str,10,"%d",atoi(str)); // On tasse la chaine à gauche - else if (input_type==3) + else if (input_type==INPUT_TYPE_DECIMAL) { // Nothing. The caller should have used Sprint_double, with min_positions // at zero, so there's no spaces on the left and no useless 0s on the right. } + else if (input_type==INPUT_TYPE_HEXA) + { + // Nothing. The caller should have initialized a valid hexa number. + } + + // Virtual keyboards +#ifdef VIRT_KEY + if (input_type == INPUT_TYPE_STRING || input_type == INPUT_TYPE_FILENAME ) + { + int x,y; - Wait_end_of_click(); + Init_virtual_keyboard(y_pos, 320, 87); + + use_virtual_keyboard=1; + + // The order is important, see the array + + Window_set_normal_button( 7,67,43,15,"Clr", 0,1,KEY_NONE); + Window_set_normal_button( 51,67,43,15,"Del", 0,1,KEY_NONE); + Window_set_normal_button( 95,67,43,15,"OK", 0,1,KEY_NONE); + Window_set_normal_button(139,67,43,15,"Esc", 0,1,KEY_NONE); + Window_display_frame_in(5,65,179,19); + + Window_set_normal_button(193,63,17,19,"0", 0,1,KEY_NONE); + Window_set_normal_button(193,43,17,19,"1", 0,1,KEY_NONE); + Window_set_normal_button(211,43,17,19,"2", 0,1,KEY_NONE); + Window_set_normal_button(229,43,17,19,"3", 0,1,KEY_NONE); + Window_set_normal_button(193,23,17,19,"4", 0,1,KEY_NONE); + Window_set_normal_button(211,23,17,19,"5", 0,1,KEY_NONE); + Window_set_normal_button(229,23,17,19,"6", 0,1,KEY_NONE); + Window_set_normal_button(193, 3,17,19,"7", 0,1,KEY_NONE); + Window_set_normal_button(211, 3,17,19,"8", 0,1,KEY_NONE); + Window_set_normal_button(229, 3,17,19,"9", 0,1,KEY_NONE); + Window_set_normal_button(211,63,17,19,".", 0,1,KEY_NONE); + Window_set_normal_button(229,63,17,19,",", 0,1,KEY_NONE); + + Window_set_normal_button( 3, 3,18,19,"Q", 0,1,KEY_NONE); + Window_set_normal_button( 22, 3,18,19,"W", 0,1,KEY_NONE); + Window_set_normal_button( 41, 3,18,19,"E", 0,1,KEY_NONE); + Window_set_normal_button( 60, 3,18,19,"R", 0,1,KEY_NONE); + Window_set_normal_button( 79, 3,18,19,"T", 0,1,KEY_NONE); + Window_set_normal_button( 98, 3,18,19,"Y", 0,1,KEY_NONE); + Window_set_normal_button(117, 3,18,19,"U", 0,1,KEY_NONE); + Window_set_normal_button(136, 3,18,19,"I", 0,1,KEY_NONE); + Window_set_normal_button(155, 3,18,19,"O", 0,1,KEY_NONE); + Window_set_normal_button(174, 3,18,19,"P", 0,1,KEY_NONE); + + Window_set_normal_button( 12,23,18,19,"A", 0,1,KEY_NONE); + Window_set_normal_button( 31,23,18,19,"S", 0,1,KEY_NONE); + Window_set_normal_button( 50,23,18,19,"D", 0,1,KEY_NONE); + Window_set_normal_button( 69,23,18,19,"F", 0,1,KEY_NONE); + Window_set_normal_button( 88,23,18,19,"G", 0,1,KEY_NONE); + Window_set_normal_button(107,23,18,19,"H", 0,1,KEY_NONE); + Window_set_normal_button(126,23,18,19,"J", 0,1,KEY_NONE); + Window_set_normal_button(145,23,18,19,"K", 0,1,KEY_NONE); + Window_set_normal_button(164,23,18,19,"L", 0,1,KEY_NONE); + + Window_set_normal_button( 3,43,18,19,caps_lock?"\036":"\037", 0,1,KEY_NONE); + Window_set_normal_button( 22,43,18,19,"Z", 0,1,KEY_NONE); + Window_set_normal_button( 41,43,18,19,"X", 0,1,KEY_NONE); + Window_set_normal_button( 60,43,18,19,"C", 0,1,KEY_NONE); + Window_set_normal_button( 79,43,18,19,"V", 0,1,KEY_NONE); + Window_set_normal_button( 98,43,18,19,"B", 0,1,KEY_NONE); + Window_set_normal_button(117,43,18,19,"N", 0,1,KEY_NONE); + Window_set_normal_button(136,43,18,19,"M", 0,1,KEY_NONE); + Window_set_normal_button(155,43,18,19," ", 0,1,KEY_NONE); + + for (y=0; y<5; y++) + { + for (x=0; x<6; x++) + { + char label[2]=" "; + label[0]=keymapping[x+y*6+44]; + Window_set_normal_button(247+x*12, 3+y*16,11,15,label, 0,1,KEY_NONE); + } + } + + Update_window_area(0,0,Window_width, Window_height); + Display_cursor(); + } + else if (input_type == INPUT_TYPE_INTEGER || input_type == INPUT_TYPE_DECIMAL ) + { + Init_virtual_keyboard(y_pos, 215, 47); + + use_virtual_keyboard=1; + + // The order is important, see the array + + Window_set_normal_button( 7,27,43,15,"Clr", 0,1,KEY_NONE); + Window_set_normal_button( 51,27,43,15,"Del", 0,1,KEY_NONE); + Window_set_normal_button( 95,27,43,15,"OK", 0,1,KEY_NONE); + Window_set_normal_button(139,27,43,15,"Esc", 0,1,KEY_NONE); + Window_display_frame_in(5,25,179,19); + + Window_set_normal_button(174, 3,18,19,"0", 0,1,KEY_NONE); + Window_set_normal_button( 3, 3,18,19,"1", 0,1,KEY_NONE); + Window_set_normal_button( 22, 3,18,19,"2", 0,1,KEY_NONE); + Window_set_normal_button( 41, 3,18,19,"3", 0,1,KEY_NONE); + Window_set_normal_button( 60, 3,18,19,"4", 0,1,KEY_NONE); + Window_set_normal_button( 79, 3,18,19,"5", 0,1,KEY_NONE); + Window_set_normal_button( 98, 3,18,19,"6", 0,1,KEY_NONE); + Window_set_normal_button(117, 3,18,19,"7", 0,1,KEY_NONE); + Window_set_normal_button(136, 3,18,19,"8", 0,1,KEY_NONE); + Window_set_normal_button(155, 3,18,19,"9", 0,1,KEY_NONE); + Window_set_normal_button(193, 3,18,19,".", 0,1,KEY_NONE); + + Update_window_area(0,0,Window_width, Window_height); + Display_cursor(); + } +#endif Keyboard_click_allowed = 0; Hide_cursor(); // Effacement de la chaîne - Block(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_Y+(y_pos*Menu_factor_Y), + Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); - Update_rect(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_Y+(y_pos*Menu_factor_Y), + Update_rect(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3)); // Mise à jour des variables se rapportant à la chaîne en fonction de la chaîne initiale @@ -182,19 +350,67 @@ byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_siz if (visible_size + offset + 1 < size ) display_string[visible_size-1]=RIGHT_TRIANGLE_CHARACTER; - Display_whole_string(x_pos,y_pos,display_string,position - offset); - Update_rect(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_Y+(y_pos*Menu_factor_Y), + Display_whole_string(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y),display_string,position - offset); + Update_rect(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3)); Flush_update(); - - while ((input_key!=SDLK_RETURN) && (input_key!=KEY_ESC) && Mouse_K == 0) + if (Mouse_K) { Display_cursor(); - do + Wait_end_of_click(); + Hide_cursor(); + } + + while ((input_key!=SDLK_RETURN) && (input_key!=KEY_ESC)) + { + Display_cursor(); +#ifdef VIRT_KEY + if (use_virtual_keyboard) { - if(!Get_input()) SDL_Delay(20); + int clicked_button; + + clicked_button=Window_clicked_button(); input_key=Key_ANSI; - } while(input_key==0 && Mouse_K == 0); + + if (clicked_button==-1) + input_key=SDLK_RETURN; + else if (clicked_button>0) + { + input_key=keymapping[clicked_button-1]; + if (input_key==SDLK_CAPSLOCK) + { + // toggle uppercase + caps_lock=!caps_lock; + Hide_cursor(); + Print_in_window(8, 49,caps_lock?"\036":"\037", MC_Black,MC_Light); + Display_cursor(); + } + else if (input_key==SDLK_BACKSPACE) + { + // A little hack: the button for backspace will: + // - backspace if the cursor is at end of string + // - delete otherwise + // It's needed for those input boxes that are completely full. + if (position='A' && input_key<='Z' && !caps_lock) + { + input_key+='a'-'A'; + } + } + } + else +#endif + { + do + { + Get_input(20); + input_key=Key_ANSI; + if (Mouse_K) + input_key=SDLK_RETURN; + } while(input_key==0); + } Hide_cursor(); switch (input_key) { @@ -205,7 +421,7 @@ byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_siz size--; // Effacement de la chaîne - Block(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_Y+(y_pos*Menu_factor_Y), + Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); goto affichage; } @@ -215,7 +431,7 @@ byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_siz { // Effacement de la chaîne if (position==size) - Block(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_Y+(y_pos*Menu_factor_Y), + Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); position--; if (offset > 0 && (position == 0 || position < (offset + 1))) @@ -239,7 +455,7 @@ byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_siz { // Effacement de la chaîne if (position==size) - Block(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_Y+(y_pos*Menu_factor_Y), + Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); position = 0; offset = 0; @@ -265,11 +481,18 @@ byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_siz Remove_character(str,position); size--; // Effacement de la chaîne - Block(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_Y+(y_pos*Menu_factor_Y), + Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); goto affichage; } break; + case SDLK_CLEAR : // Clear + str[0]='\0'; + position=offset=0; + // Effacement de la chaîne + Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), + visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); + goto affichage; case SDLK_RETURN : break; @@ -285,15 +508,15 @@ byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_siz is_authorized=0; // On commence par supposer qu'elle est interdite switch(input_type) { - case 0 : // N'importe quelle chaîne: + case INPUT_TYPE_STRING : if (input_key>=' ' && input_key<= 255) is_authorized=1; break; - case 1 : // Nombre + case INPUT_TYPE_INTEGER : if ( (input_key>='0') && (input_key<='9') ) is_authorized=1; break; - case 3: // Decimal number + case INPUT_TYPE_DECIMAL: if ( (input_key>='0') && (input_key<='9') ) is_authorized=1; else if (input_key=='-' && position==0 && str[0]!='-') @@ -301,10 +524,18 @@ byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_siz else if (input_key=='.') is_authorized=1; break; - default : // Nom de fichier + case INPUT_TYPE_FILENAME: // On regarde si la touche est autorisée if ( Valid_character(input_key)) is_authorized=1; + case INPUT_TYPE_HEXA: + if ( (input_key>='0') && (input_key<='9') ) + is_authorized=1; + else if ( (input_key>='A') && (input_key<='F') ) + is_authorized=1; + else if ( (input_key>='a') && (input_key<='f') ) + is_authorized=1; + break; } // End du "switch(input_type)" // Si la touche était autorisée... @@ -337,20 +568,29 @@ affichage: if (visible_size + offset + 0 < size ) display_string[visible_size-1]=RIGHT_TRIANGLE_CHARACTER; - Display_whole_string(x_pos,y_pos,display_string,position - offset); - Update_rect(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_Y+(y_pos*Menu_factor_Y), + Display_whole_string(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y),display_string,position - offset); + Update_rect(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3)); } // End du "switch(input_key)" Flush_update(); } // End du "while" Keyboard_click_allowed = 1; - + #ifdef VIRT_KEY + if (use_virtual_keyboard) + { + byte old_mouse_k = Mouse_K; + Close_popup(); + Mouse_K=old_mouse_k; + Input_sticky_control=0; + } + #endif + // Effacement de la chaîne - Block(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_Y+(y_pos*Menu_factor_Y), + Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); // On raffiche la chaine correctement - if (input_type==1) + if (input_type==INPUT_TYPE_INTEGER) { if (str[0]=='\0') { @@ -359,7 +599,7 @@ affichage: } Print_in_window(x_pos+((max_size-size)<<3),y_pos,str,TEXT_COLOR,BACKGROUND_COLOR); } - else if (input_type==3) + else if (input_type==INPUT_TYPE_DECIMAL) { double value; // Discard extra digits @@ -377,10 +617,10 @@ affichage: { Print_in_window_limited(x_pos,y_pos,str,visible_size,TEXT_COLOR,BACKGROUND_COLOR); } - Update_rect(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_Y+(y_pos*Menu_factor_Y), + Update_rect(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3)); - return (input_key==SDLK_RETURN || Mouse_K != 0); + return (input_key==SDLK_RETURN); } void Sprint_double(char *str, double value, byte decimal_places, byte min_positions) diff --git a/src/readline.h b/src/readline.h index af7e1e62..99e6a2f2 100644 --- a/src/readline.h +++ b/src/readline.h @@ -24,13 +24,22 @@ /// Text input functions. ////////////////////////////////////////////////////////////////////////////// +enum INPUT_TYPE +{ + INPUT_TYPE_STRING=0, ///< Any string + INPUT_TYPE_INTEGER=1, ///< Decimal integer + INPUT_TYPE_FILENAME=2,///< Filename + INPUT_TYPE_DECIMAL=3, ///< Decimal value + INPUT_TYPE_HEXA=4, ///< Hexadecimal integer +}; + /// /// Lets the user input a line of text, exit by Esc or Return. /// @param x_pos Coordinates of input, in window coordinates before scaling. /// @param y_pos Coordinates of input, in window coordinates before scaling. /// @param str The original string value (will be modified, unless user cancels. /// @param visible_size Number of characters visible and editable. -/// @param input_type 0=string, 1=number, 2=filename (255 editable characters) +/// @param input_type one of enum ::INPUT_TYPE /// @return 0 if user cancelled (esc), 1 if accepted (return) byte Readline(word x_pos,word y_pos,char * str,byte visible_size,byte input_type); @@ -41,7 +50,7 @@ byte Readline(word x_pos,word y_pos,char * str,byte visible_size,byte input_type /// @param str The original string value (will be modified, unless user cancels. /// @param visible_size Number of characters visible. /// @param max_size Number of characters editable. -/// @param input_type 0=string, 1=integer, 2=filename (255 editable characters) 3=decimal +/// @param input_type one of enum ::INPUT_TYPE /// @param decimal_places Number of decimal places (used only with decimal type) /// @return 0 if user cancelled (esc), 1 if accepted (return) byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_size, byte input_type, byte decimal_places); diff --git a/src/realpath.c b/src/realpath.c index 34668c08..1a916e72 100644 --- a/src/realpath.c +++ b/src/realpath.c @@ -6,8 +6,11 @@ #include #include #include +#if defined(__AROS__) +#include +#endif -#if defined(__AROS__) || defined(__BEOS__) || defined(__MORPHOS__) || defined(__GP2X__) || defined(__amigaos__) +#if defined(__AROS__) || defined(__BEOS__) || defined(__MORPHOS__) || defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) || defined(__amigaos__) // These platforms don't have realpath(). // We use the following implementation, found in: // http://amiga.sourceforge.net/amigadevhelp/FUNCTIONS/GeekGadgets/realpath/ex02_realpath.c @@ -17,7 +20,7 @@ // the path. So this implementation is limited, it's really better to // use realpath() if your platform has it. - #if defined(__GP2X__) || defined(__amigaos__) + #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) || defined(__amigaos__) // This is a random default value ... #define PATH_MAX 32768 #endif diff --git a/src/saveini.c b/src/saveini.c index ad3930cf..b512b7ac 100644 --- a/src/saveini.c +++ b/src/saveini.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Peter Gordon Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues @@ -30,6 +31,7 @@ #include "errors.h" #include "misc.h" #include "saveini.h" +#include "setup.h" int Save_INI_reach_group(FILE * old_file,FILE * new_file,char * buffer,char * group) { @@ -393,8 +395,8 @@ void Save_INI_flush(FILE * old_file,FILE * new_file,char * buffer) int Save_INI(T_Config * conf) { - FILE * Ancien_fichier; - FILE * Nouveau_fichier; + FILE * old_file; + FILE * new_file; char * buffer; int values[3]; char filename[MAX_PATH_CHARACTERS]; @@ -409,13 +411,13 @@ int Save_INI(T_Config * conf) // On calcule les noms des fichiers qu'on manipule: strcpy(filename,Config_directory); - strcat(filename,"gfx2.ini"); + strcat(filename,INI_FILENAME); // On vérifie si le fichier INI existe if ((ini_file_exists = File_exists(filename))) { strcpy(temp_filename,Config_directory); - strcat(temp_filename,"gfx2.$$$"); + strcat(temp_filename,INISAVE_FILENAME); // On renome l'ancienne version du fichier INI vers un fichier temporaire: if (rename(filename,temp_filename)!=0) @@ -425,237 +427,237 @@ int Save_INI(T_Config * conf) } // On récupère un fichier INI "propre" à partir de gfx2def.ini strcpy(ref_ini_file,Data_directory); - strcat(ref_ini_file,"gfx2def.ini"); - Ancien_fichier=fopen(ref_ini_file,"rb"); - if (Ancien_fichier==0) + strcat(ref_ini_file,INIDEF_FILENAME); + old_file=fopen(ref_ini_file,"rb"); + if (old_file==0) { - fclose(Ancien_fichier); + fclose(old_file); free(buffer); return ERROR_INI_MISSING; } - Nouveau_fichier=fopen(filename,"wb"); - if (Nouveau_fichier==0) + new_file=fopen(filename,"wb"); + if (new_file==0) { free(buffer); return ERROR_SAVING_INI; } - if ((return_code=Save_INI_reach_group(Ancien_fichier,Nouveau_fichier,buffer,"[MOUSE]"))) + if ((return_code=Save_INI_reach_group(old_file,new_file,buffer,"[MOUSE]"))) goto Erreur_Retour; values[0]=conf->Mouse_sensitivity_index_x; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"X_sensitivity",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"X_sensitivity",1,values,0))) goto Erreur_Retour; values[0]=conf->Mouse_sensitivity_index_y; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Y_sensitivity",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Y_sensitivity",1,values,0))) goto Erreur_Retour; values[0]=0; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"X_correction_factor",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"X_correction_factor",1,values,0))) goto Erreur_Retour; values[0]=0; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Y_correction_factor",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Y_correction_factor",1,values,0))) goto Erreur_Retour; values[0]=(conf->Cursor)+1; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Cursor_aspect",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Cursor_aspect",1,values,0))) goto Erreur_Retour; - if ((return_code=Save_INI_reach_group(Ancien_fichier,Nouveau_fichier,buffer,"[MENU]"))) + if ((return_code=Save_INI_reach_group(old_file,new_file,buffer,"[MENU]"))) goto Erreur_Retour; values[0]=conf->Fav_menu_colors[2].R>>2; values[1]=conf->Fav_menu_colors[2].G>>2; values[2]=conf->Fav_menu_colors[2].B>>2; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Light_color",3,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Light_color",3,values,0))) goto Erreur_Retour; values[0]=conf->Fav_menu_colors[1].R>>2; values[1]=conf->Fav_menu_colors[1].G>>2; values[2]=conf->Fav_menu_colors[1].B>>2; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Dark_color",3,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Dark_color",3,values,0))) goto Erreur_Retour; values[0]=conf->Ratio; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Menu_ratio",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Menu_ratio",1,values,0))) goto Erreur_Retour; - if ((return_code=Save_INI_reach_group(Ancien_fichier,Nouveau_fichier,buffer,"[FILE_SELECTOR]"))) + if ((return_code=Save_INI_reach_group(old_file,new_file,buffer,"[FILE_SELECTOR]"))) goto Erreur_Retour; values[0]=conf->Show_hidden_files?1:0; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Show_hidden_files",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Show_hidden_files",1,values,1))) goto Erreur_Retour; values[0]=conf->Show_hidden_directories?1:0; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Show_hidden_directories",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Show_hidden_directories",1,values,1))) goto Erreur_Retour; /* values[0]=conf->Show_system_directories?1:0; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Show_system_directories",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Show_system_directories",1,values,1))) goto Erreur_Retour; */ values[0]=conf->Timer_delay; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Preview_delay",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Preview_delay",1,values,0))) goto Erreur_Retour; values[0]=conf->Maximize_preview; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Maximize_preview",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Maximize_preview",1,values,1))) goto Erreur_Retour; values[0]=conf->Find_file_fast; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Find_file_fast",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Find_file_fast",1,values,0))) goto Erreur_Retour; - if ((return_code=Save_INI_reach_group(Ancien_fichier,Nouveau_fichier,buffer,"[LOADING]"))) + if ((return_code=Save_INI_reach_group(old_file,new_file,buffer,"[LOADING]"))) goto Erreur_Retour; values[0]=conf->Auto_set_res; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Auto_set_resolution",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Auto_set_resolution",1,values,1))) goto Erreur_Retour; values[0]=conf->Set_resolution_according_to; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Set_resolution_according_to",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Set_resolution_according_to",1,values,0))) goto Erreur_Retour; values[0]=conf->Clear_palette; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Clear_palette",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Clear_palette",1,values,1))) goto Erreur_Retour; - if ((return_code=Save_INI_reach_group(Ancien_fichier,Nouveau_fichier,buffer,"[MISCELLANEOUS]"))) + if ((return_code=Save_INI_reach_group(old_file,new_file,buffer,"[MISCELLANEOUS]"))) goto Erreur_Retour; values[0]=conf->Display_image_limits; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Draw_limits",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Draw_limits",1,values,1))) goto Erreur_Retour; values[0]=conf->Adjust_brush_pick; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Adjust_brush_pick",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Adjust_brush_pick",1,values,1))) goto Erreur_Retour; values[0]=2-conf->Coords_rel; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Coordinates",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Coordinates",1,values,0))) goto Erreur_Retour; values[0]=conf->Backup; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Backup",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Backup",1,values,1))) goto Erreur_Retour; values[0]=conf->Max_undo_pages; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Undo_pages",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Undo_pages",1,values,0))) goto Erreur_Retour; values[0]=conf->Delay_left_click_on_slider; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Gauges_scrolling_speed_Left",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Gauges_scrolling_speed_Left",1,values,0))) goto Erreur_Retour; values[0]=conf->Delay_right_click_on_slider; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Gauges_scrolling_speed_Right",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Gauges_scrolling_speed_Right",1,values,0))) goto Erreur_Retour; values[0]=conf->Auto_save; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Auto_save",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Auto_save",1,values,1))) goto Erreur_Retour; values[0]=conf->Nb_max_vertices_per_polygon; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Vertices_per_polygon",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Vertices_per_polygon",1,values,0))) goto Erreur_Retour; values[0]=conf->Fast_zoom; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Fast_zoom",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Fast_zoom",1,values,1))) goto Erreur_Retour; values[0]=conf->Separate_colors; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Separate_colors",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Separate_colors",1,values,1))) goto Erreur_Retour; values[0]=conf->FX_Feedback; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"FX_feedback",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"FX_feedback",1,values,1))) goto Erreur_Retour; values[0]=conf->Safety_colors; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Safety_colors",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Safety_colors",1,values,1))) goto Erreur_Retour; values[0]=conf->Opening_message; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Opening_message",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Opening_message",1,values,1))) goto Erreur_Retour; values[0]=conf->Clear_with_stencil; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Clear_with_stencil",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Clear_with_stencil",1,values,1))) goto Erreur_Retour; values[0]=conf->Auto_discontinuous; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Auto_discontinuous",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Auto_discontinuous",1,values,1))) goto Erreur_Retour; values[0]=conf->Screen_size_in_GIF; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Save_screen_size_in_GIF",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Save_screen_size_in_GIF",1,values,1))) goto Erreur_Retour; values[0]=conf->Auto_nb_used; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Auto_nb_colors_used",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Auto_nb_colors_used",1,values,1))) goto Erreur_Retour; - if ((return_code=Save_INI_set_strings (Ancien_fichier,Nouveau_fichier,buffer,"Default_video_mode",Mode_label(conf->Default_resolution)))) + if ((return_code=Save_INI_set_strings (old_file,new_file,buffer,"Default_video_mode",Mode_label(conf->Default_resolution)))) goto Erreur_Retour; values[0]=Video_mode[0].Width; values[1]=Video_mode[0].Height; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Default_window_size",2,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Default_window_size",2,values,0))) goto Erreur_Retour; values[0]=(conf->Mouse_merge_movement); - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Merge_movement",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Merge_movement",1,values,0))) goto Erreur_Retour; values[0]=(conf->Palette_cells_X); - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Palette_cells_X",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Palette_cells_X",1,values,0))) goto Erreur_Retour; values[0]=(conf->Palette_cells_Y); - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Palette_cells_Y",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Palette_cells_Y",1,values,0))) goto Erreur_Retour; for (index=0;indexBookmark_label[index]))) + if ((return_code=Save_INI_set_strings (old_file,new_file,buffer,"Bookmark_label",conf->Bookmark_label[index]))) goto Erreur_Retour; - if ((return_code=Save_INI_set_strings (Ancien_fichier,Nouveau_fichier,buffer,"Bookmark_directory",conf->Bookmark_directory[index]))) + if ((return_code=Save_INI_set_strings (old_file,new_file,buffer,"Bookmark_directory",conf->Bookmark_directory[index]))) goto Erreur_Retour; } values[0]=(conf->Palette_vertical); - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Palette_vertical",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Palette_vertical",1,values,1))) goto Erreur_Retour; values[0]=conf->Window_pos_x; values[1]=conf->Window_pos_y; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Window_position",2,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Window_position",2,values,0))) goto Erreur_Retour; values[0]=(conf->Double_click_speed); - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Double_click_speed",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Double_click_speed",1,values,0))) goto Erreur_Retour; values[0]=(conf->Double_key_speed); - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Double_key_speed",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Double_key_speed",1,values,0))) goto Erreur_Retour; - if ((return_code=Save_INI_set_strings (Ancien_fichier,Nouveau_fichier,buffer,"Skin_file",conf->Skin_file))) + if ((return_code=Save_INI_set_strings (old_file,new_file,buffer,"Skin_file",conf->Skin_file))) goto Erreur_Retour; - if ((return_code=Save_INI_set_strings (Ancien_fichier,Nouveau_fichier,buffer,"Font_file",conf->Font_file))) + if ((return_code=Save_INI_set_strings (old_file,new_file,buffer,"Font_file",conf->Font_file))) goto Erreur_Retour; values[0]=(conf->Grid_XOR_color); - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Grid_XOR_color",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Grid_XOR_color",1,values,0))) goto Erreur_Retour; values[0]=(Pixel_ratio); - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Pixel_ratio",1,values,0))) { + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Pixel_ratio",1,values,0))) { DEBUG("saving pixel ratio",return_code); goto Erreur_Retour; } @@ -670,14 +672,37 @@ int Save_INI(T_Config * conf) for (; index<8;index++) values[0] |= (1<Right_click_colorpick); + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Right_click_colorpick",1,values,1))) + goto Erreur_Retour; + + values[0]=(conf->Sync_views); + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Sync_views",1,values,1))) + goto Erreur_Retour; + + switch(conf->Swap_buttons) + { + case MOD_CTRL: + values[0]=1; + break; + case MOD_ALT: + values[0]=2; + break; + default: + values[0]=0; + } + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Swap_buttons",1,values,0))) + goto Erreur_Retour; + + // Insert new values here + + Save_INI_flush(old_file,new_file,buffer); - Save_INI_flush(Ancien_fichier,Nouveau_fichier,buffer); - - fclose(Nouveau_fichier); - fclose(Ancien_fichier); + fclose(new_file); + fclose(old_file); // On efface le fichier temporaire <=> Ancienne version du .INI if (ini_file_exists) @@ -689,8 +714,8 @@ int Save_INI(T_Config * conf) Erreur_Retour: - fclose(Nouveau_fichier); - fclose(Ancien_fichier); + fclose(new_file); + fclose(old_file); free(buffer); return return_code; diff --git a/src/sdlscreen.c b/src/sdlscreen.c index 34ca890b..a8ef9476 100644 --- a/src/sdlscreen.c +++ b/src/sdlscreen.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2007 Adrien Destugues @@ -23,6 +24,15 @@ #include #include #include +#include +#if defined(__WIN32__) + #include +#endif +// There is no WM on the GP2X... +#ifndef __GP2X__ + #include +#endif + #include "global.h" #include "sdlscreen.h" #include "errors.h" @@ -42,14 +52,21 @@ #ifndef UPDATE_METHOD #if defined(__macosx__) #define UPDATE_METHOD UPDATE_METHOD_FULL_PAGE + #elif defined(__MINT__) + #define UPDATE_METHOD UPDATE_METHOD_CUMULATED #else #define UPDATE_METHOD UPDATE_METHOD_CUMULATED #endif #endif +volatile int Allow_colorcycling=1; + /// Sets the new screen/window dimensions. void Set_mode_SDL(int *width, int *height, int fullscreen) { + static SDL_Cursor* cur = NULL; + static byte cursorData = 0; + Screen_SDL=SDL_SetVideoMode(*width,*height,8,(fullscreen?SDL_FULLSCREEN:0)|SDL_RESIZABLE); if(Screen_SDL != NULL) { @@ -66,7 +83,15 @@ void Set_mode_SDL(int *width, int *height, int fullscreen) { DEBUG("Error: Unable to change video mode!",0); } - SDL_ShowCursor(0); // Hide the SDL mouse cursor, we use our own + + // Trick borrowed to Barrage (http://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg737265.html) : + // Showing the cursor but setting it to fully transparent allows us to get absolute mouse coordinates, + // this means we can use tablet in fullscreen mode. + SDL_ShowCursor(1); // Hide the SDL mouse cursor, we use our own + + SDL_FreeCursor(cur); + cur = SDL_CreateCursor(&cursorData, &cursorData, 1,1,0,0); + SDL_SetCursor(cur); } #if (UPDATE_METHOD == UPDATE_METHOD_CUMULATED) @@ -194,16 +219,36 @@ byte Get_SDL_pixel_8(SDL_Surface *bmp, int x, int y) return ((byte *)(bmp->pixels))[(y*bmp->pitch+x)]; } +/// Writes a pixel in a 8-bit SDL surface. +void Set_SDL_pixel_8(SDL_Surface *bmp, int x, int y, byte color) +{ + ((byte *)(bmp->pixels))[(y*bmp->pitch+x)]=color; +} + + /// Reads a pixel in a multi-byte SDL surface. dword Get_SDL_pixel_hicolor(SDL_Surface *bmp, int x, int y) { + byte * ptr; + switch(bmp->format->BytesPerPixel) { case 4: default: return *((dword *)((byte *)bmp->pixels+(y*bmp->pitch+x*4))); case 3: - return *(((dword *)((byte *)bmp->pixels+(y*bmp->pitch+x*3)))) & 0xFFFFFF; + // Reading a 4-byte number starting at an address that isn't a multiple + // of 2 (or 4?) is not supported on Caanoo console at least (ARM CPU) + // So instead, we will read the 3 individual bytes, and re-construct the + // "dword" expected by SDL. + ptr = ((byte *)bmp->pixels)+(y*bmp->pitch+x*3); + #ifdef SDL_LIL_ENDIAN + // Read ABC, output _CBA : Most Significant Byte is zero. + return (*ptr) | (*(ptr+1)<<8) | (*(ptr+2)<<16); + #else + // Read ABC, output ABC_ : Least Significant Byte is zero. + return ((*ptr)<<24) | (*(ptr+1)<<16) | (*(ptr+2)<<8); + #endif case 2: return *((word *)((byte *)bmp->pixels+(y*bmp->pitch+x*2))); } @@ -257,3 +302,18 @@ void Clear_border(byte color) } } +/// Activates or desactivates file drag-dropping in program window. +void Allow_drag_and_drop(int flag) +{ + // Inform Windows that we accept drag-n-drop events or not + #ifdef __WIN32__ + SDL_SysWMinfo wminfo; + HWND hwnd; + + SDL_VERSION(&wminfo.version); + SDL_GetWMInfo(&wminfo); + hwnd = wminfo.window; + DragAcceptFiles(hwnd,flag?TRUE:FALSE); + SDL_EventState (SDL_SYSWMEVENT,flag?SDL_ENABLE:SDL_DISABLE ); + #endif +} \ No newline at end of file diff --git a/src/sdlscreen.h b/src/sdlscreen.h index a7b83c2e..d0b7d004 100644 --- a/src/sdlscreen.h +++ b/src/sdlscreen.h @@ -56,6 +56,8 @@ SDL_Color Color_to_SDL_color(byte); byte Get_SDL_pixel_8(SDL_Surface *bmp, int x, int y); /// Reads a pixel in a multi-byte SDL surface. dword Get_SDL_pixel_hicolor(SDL_Surface *bmp, int x, int y); +/// Writes a pixel in a 8-bit SDL surface. +void Set_SDL_pixel_8(SDL_Surface *bmp, int x, int y, byte color); /// Convert a SDL Palette to a grafx2 palette void Get_SDL_Palette(const SDL_Palette * sdl_palette, T_Palette palette); @@ -65,4 +67,9 @@ void Get_SDL_Palette(const SDL_Palette * sdl_palette, T_Palette palette); /// size, eg: 3x3 pixels in 1024x768 leaves 1 column on the right, 0 rows on bottom. void Clear_border(byte color); +extern volatile int Allow_colorcycling; + +/// Activates or desactivates file drag-dropping in program window. +void Allow_drag_and_drop(int flag); + #endif // SDLSCREEN_H_INCLUDED diff --git a/src/setup.c b/src/setup.c index 898e2cd2..e1c18dfc 100644 --- a/src/setup.c +++ b/src/setup.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Peter Gordon Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet @@ -35,6 +36,9 @@ #import #elif defined(__FreeBSD__) #import +#elif defined(__MINT__) + #include + #include #elif defined(__linux__) #include #include @@ -44,7 +48,7 @@ #include "io.h" #include "setup.h" -#if defined(__GP2X__) +#if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) // This is a random default value ... #define PATH_MAX 32768 #endif @@ -84,7 +88,16 @@ void Set_program_directory(ARG_UNUSED const char * argv0,char * program_dir) // AmigaOS and alike: hard-coded volume name. #elif defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) strcpy(program_dir,"PROGDIR:"); + #elif defined(__MINT__) + static char path[1024]={0}; + char currentDrive='A'; + currentDrive=currentDrive+Dgetdrv(); + + Dgetpath(path,0); + sprintf(program_dir,"%c:\%s",currentDrive,path); + // Append trailing slash + strcat(program_dir,PATH_SEPARATOR); // Linux: argv[0] unreliable #elif defined(__linux__) if (argv0[0]!='/') @@ -115,9 +128,14 @@ void Set_data_directory(const char * program_dir, char * data_dir) #if defined(__macosx__) strcat(data_dir,"Contents/Resources/"); // On GP2X, executable is not in bin/ - #elif defined (__gp2x__) + #elif defined (__GP2X__) || defined (__gp2x__) || defined (__WIZ__) || defined (__CAANOO__) strcat(data_dir,"share/grafx2/"); + //on tos the same directory + #elif defined (__MINT__) + strcpy(data_dir, program_dir); // All other targets, program is in a "bin" subdirectory + #elif defined (__AROS__) + strcat(data_dir,"/share/grafx2/"); #else strcat(data_dir,"../share/grafx2/"); #endif @@ -140,21 +158,23 @@ void Set_config_directory(const char * program_dir, char * config_dir) #if defined(__amigaos4__) || defined(__AROS__) strcpy(config_dir,"PROGDIR:"); // GP2X - #elif defined(__GP2X__) + #elif defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) // On the GP2X, the program is installed to the sdcard, and we don't want to mess with the system tree which is // on an internal flash chip. So, keep these settings locals. strcpy(config_dir,program_dir); + #elif defined(__MINT__) + strcpy(config_dir,program_dir); #else char filename[MAX_PATH_CHARACTERS]; // In priority: check root directory strcpy(config_dir, program_dir); - // On all these targets except OSX and GP2X, the executable is in ./bin - #if !defined(__macosx__) && !defined(__gp2x__) - strcat(config_dir, "../"); + // On all the remaining targets except OSX, the executable is in ./bin + #if !defined(__macosx__) + strcat(config_dir, "../"); #endif strcpy(filename, config_dir); - strcat(filename, "gfx2.cfg"); + strcat(filename, CONFIG_FILENAME); if (!File_exists(filename)) { @@ -171,6 +191,10 @@ void Set_config_directory(const char * program_dir, char * config_dir) // "~/Library/Preferences/com.googlecode.grafx2" const char* Config_SubDir = "Library/Preferences/com.googlecode.grafx2"; config_parent_dir = getenv("HOME"); + #elif defined(__MINT__) + const char* Config_SubDir = ""; + printf("GFX2.CFG not found in %s\n",filename); + strcpy(config_parent_dir, config_dir); #else // "~/.grafx2" const char* Config_SubDir = ".grafx2"; @@ -203,7 +227,7 @@ void Set_config_directory(const char * program_dir, char * config_dir) { // Echec: on se rabat sur le repertoire de l'executable. strcpy(config_dir,program_dir); - #if !defined(__macosx__) && !defined(__gp2x__) + #if defined(__macosx__) strcat(config_dir, "../"); #endif } diff --git a/src/setup.h b/src/setup.h index 58a22b97..67869512 100644 --- a/src/setup.h +++ b/src/setup.h @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Peter Gordon Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet @@ -53,4 +54,104 @@ void Set_data_directory(const char * program_dir, char * data_dir); /// IN: The directory containing the executable /// OUT: Write into config_dir. Trailing / or \ is kept. void Set_config_directory(const char * program_dir, char * config_dir); - + + +/// Name of the subdirectory containing fonts, under the data directory (::Set_data_directory()) +#if defined (__MINT__) + #define FONTS_SUBDIRECTORY "FONTS" +#else + #define FONTS_SUBDIRECTORY "fonts" +#endif + +/// Name of the subdirectory containing fonts, under the data directory (::Set_data_directory()) +#if defined (__MINT__) + #define SKINS_SUBDIRECTORY "SKINS" +#else + #define SKINS_SUBDIRECTORY "skins" +#endif + +/// Name of the binary file containing some configuration settings. +#if defined (__MINT__) + #define CONFIG_FILENAME "GFX2.CFG" +#else + #define CONFIG_FILENAME "gfx2.cfg" +#endif + +/// Name of the text file containing some settings in INI format. +#if defined (__MINT__) + #define INI_FILENAME "GFX2.INI" +#else + #define INI_FILENAME "gfx2.ini" +#endif + +/// Name of the backup of the INI file. +#if defined (__MINT__) + #define INISAVE_FILENAME "GFX2.$$$" +#else + #define INISAVE_FILENAME "gfx2.$$$" +#endif + +/// Name of the default .INI file (read-only: gives .INI format and defaults) +#if defined (__MINT__) + #define INIDEF_FILENAME "GFX2DEF.INI" +#else + #define INIDEF_FILENAME "gfx2def.ini" +#endif + +/// Prefix for filenames of safety backups (main) +#if defined (__MINT__) + #define SAFETYBACKUP_PREFIX_A "A" +#else + #define SAFETYBACKUP_PREFIX_A "a" +#endif + +/// Prefix for filenames of safety backups (spare) +#if defined (__MINT__) + #define SAFETYBACKUP_PREFIX_B "B" +#else + #define SAFETYBACKUP_PREFIX_B "b" +#endif + +/// Name of the image file that serves as an application icon. +#if defined (__MINT__) + #define GFX2_ICON_FILENAME "GFX2.GIF" +#else + #define GFX2_ICON_FILENAME "gfx2.gif" +#endif + +/// Name of the image file for the default (and fallback) GUI skin. +#if defined (__MINT__) + #define DEFAULT_SKIN_FILENAME "SDPAINT.PNG" +#else + #define DEFAULT_SKIN_FILENAME "skin_DPaint.png" +#endif + +/// Name of the image file for the default (and fallback) 8x8 font. +#if defined (__MINT__) + #define DEFAULT_FONT_FILENAME "FDPAINT.PNG" +#else + #define DEFAULT_FONT_FILENAME "font_DPaint.png" +#endif + +/// File extension for safety backups +#if defined (__MINT__) + #define BACKUP_FILE_EXTENSION ".BKP" +#else + #define BACKUP_FILE_EXTENSION ".bkp" +#endif + +/// File prefix for fonts +#if defined (__MINT__) + #define FONT_PREFIX "F" +#else + #define FONT_PREFIX "font_" +#endif + +/// File prefix for skins +#if defined (__MINT__) + #define SKIN_PREFIX "S" +#else + #define SKIN_PREFIX "skin_" +#endif + + diff --git a/src/shade.c b/src/shade.c index 71579428..bab856db 100644 --- a/src/shade.c +++ b/src/shade.c @@ -348,7 +348,7 @@ short Wait_click_in_shade_table() while (selected_cell<0) { - Get_input(); + Get_input(20); if ( (Mouse_K==LEFT_SIDE) && ( ( (Window_click_in_rectangle(8,127,263,179)) && (((((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-127)%7)<4) ) @@ -837,7 +837,7 @@ int Menu_shade(void) case 15 : // Saisie du pas Num2str(Shade_list[Shade_current].Step,str,3); - Readline(276,176,str,3,1); + Readline(276,176,str,3,INPUT_TYPE_INTEGER); temp=atoi(str); // On corrige le pas if (!temp) @@ -1089,7 +1089,7 @@ void Button_Quick_shade_menu(void) case 4 : // Saisie du pas Num2str(Quick_shade_step,str,3); - Readline(42,21,str,3,1); + Readline(42,21,str,3,INPUT_TYPE_INTEGER); temp=atoi(str); // On corrige le pas if (!temp) diff --git a/src/special.c b/src/special.c index 4f7a60cc..6e3dc579 100644 --- a/src/special.c +++ b/src/special.c @@ -431,6 +431,9 @@ void Transparency_set(byte amount) break; case 2 : Effect_function=Effect_substractive_colorize; + break; + case 3 : + Effect_function=Effect_alpha_colorize; } Shade_mode=0; Quick_shade_mode=0; diff --git a/src/struct.h b/src/struct.h index f46c2560..e3888068 100644 --- a/src/struct.h +++ b/src/struct.h @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) @@ -73,14 +74,23 @@ typedef void (* Func_draw_brush) (byte *,word,word,word,word,word,word,byte,word typedef void (* Func_draw_list_item) (word,word,word,byte); ///< Draw an item inside a list button. This is done with a callback so it is possible to draw anything, as the list itself doesn't handle the content /// A set of RGB values. +#ifdef __GNUC__ +typedef struct +{ + byte R; ///< Red + byte G; ///< Green + byte B; ///< Blue +} __attribute__((__packed__)) T_Components, T_Palette[256] ; ///< A complete 256-entry RGB palette (768 bytes). +#else #pragma pack(1) typedef struct { byte R; ///< Red byte G; ///< Green byte B; ///< Blue -} T_Components, T_Palette[256]; ///< A complete 256-entry RGB palette (768 bytes). +} T_Components, T_Palette[256] ; ///< A complete 256-entry RGB palette (768 bytes). #pragma pack() +#endif /// A normal rectangular button in windows and menus. typedef struct T_Normal_button @@ -105,17 +115,18 @@ typedef struct T_Palette_button struct T_Palette_button * Next;///< Pointer to the next palette of current window. } T_Palette_button; -/// A window control that represents a vertical scrollbar, with a slider, and two arrow buttons. +/// A window control that represents a scrollbar, with a slider, and two arrow buttons. typedef struct T_Scroller_button { short Number; ///< Unique identifier for all controls + byte Is_horizontal; ///< Boolean: True if slider is horizontal instead of vertical. word Pos_X; ///< Coordinate for top of button, relative to the window, before scaling. word Pos_Y; ///< Coordinate for left of button, relative to the window, before scaling. - word Height; ///< Height before scaling. + word Length; ///< Length before scaling. word Nb_elements; ///< Number of distinct values it can take. word Nb_visibles; ///< If this slider is meant to show several elements of a collection, this is their number (otherwise, it's 1). word Position; ///< Current position of the slider: which item it's pointing. - word Cursor_height; ///< Vertical dimension of the slider, in pixels before scaling. + word Cursor_length; ///< Dimension of the slider, in pixels before scaling. struct T_Scroller_button * Next;///< Pointer to the next scroller of current window. } T_Scroller_button; @@ -162,12 +173,20 @@ typedef struct T_Dropdown_button /// Data for one item (file, directory) in a fileselector. typedef struct T_Fileselector_item { - char Short_name[19]; ///< Name to display. char Full_name[256]; ///< Filesystem value. byte Type; ///< Type of item: 0 = File, 1 = Directory, 2 = Drive + byte Icon; ///< One of ::ICON_TYPES, ICON_NONE for none. struct T_Fileselector_item * Next; ///< Pointer to next item of the current fileselector. struct T_Fileselector_item * Previous;///< Pointer to previous item of the current fileselector. + + word Length_short_name; ///< Number of bytes allocated for :Short_name + #if __GNUC__ < 3 + char Short_name[0]; ///< Name to display. +#else + char Short_name[]; ///< Name to display. +#endif + // No field after Short_name[] ! Dynamic allocation according to name length. } T_Fileselector_item; /// Data for a fileselector @@ -201,6 +220,25 @@ typedef struct T_List_button struct T_List_button * Next; ///< Pointer to the next list button of current window. } T_List_button; +/// A stackable window (editor screen) +typedef struct +{ + word Pos_X; + word Pos_Y; + word Width; + word Height; + word Nb_buttons; + T_Normal_button *Normal_button_list; + T_Palette_button *Palette_button_list; + T_Scroller_button *Scroller_button_list; + T_Special_button *Special_button_list; + T_Dropdown_button *Dropdown_button_list; + T_List_button *List_button_list; + int Attribute1; + int Attribute2; + byte Draggable; +} T_Window; + /// Data for one line of the "Help" screens. typedef struct { char Line_type; ///< Kind of line: 'N' for normal line, 'S' for a bold line, 'K' for a line with keyboard shortcut, 'T' and '-' for upper and lower titles. @@ -223,7 +261,15 @@ typedef struct dword Inverse; ///< Boolean, true if the gradient goes in descending order dword Mix; ///< Amount of randomness to add to the mix (0-255) dword Technique;///< Gradient technique: 0 (no pattern) 1 (dithering), or 2 (big dithering) -} T_Gradient_array; + byte Speed; ///< Speed of cycling. 0 for disabled, 1-64 otherwise. +} T_Gradient_range; + +/// Data for a full set of gradients. +typedef struct +{ + int Used; ///< Reference count + T_Gradient_range Range[16]; +} T_Gradient_array; /// Data for one setting of shade. Warning, this one is saved/loaded as binary. typedef struct @@ -233,7 +279,6 @@ typedef struct byte Mode; ///< Shade mode: Normal, Loop, or No-saturation see ::SHADE_MODES } T_Shade; -#pragma pack(1) // is it useful ? /// Data for one fullscreen video mode in configuration file. Warning, this one is saved/loaded as binary. typedef struct { @@ -242,8 +287,7 @@ typedef struct word Height;///< Videomode height in pixels. } T_Config_video_mode; - -/// Header for gfx2.cfg. Warning, this one is saved/loaded as binary. +/// Header for gfx2.cfg typedef struct { char Signature[3]; ///< Signature for the file format. "CFG". @@ -253,24 +297,22 @@ typedef struct byte Beta2; ///< Major beta version number (ex: 5) } T_Config_header; -#pragma pack() - -/// Header for a config chunk in for gfx2.cfg. Warning, this one is saved/loaded as binary. +/// Header for a config chunk in for gfx2.cfg typedef struct { byte Number; ///< Section identfier. Possible values are in enum ::CHUNKS_CFG word Size; ///< Size of the configuration block that follows, in bytes. } T_Config_chunk; -#pragma pack(1) -/// Configuration for one keyboard shortcut in gfx2.cfg. Warning, this one is saved/loaded as binary. + +/// Configuration for one keyboard shortcut in gfx2.cfg typedef struct { word Number; ///< Indicates the shortcut action. This is a number starting from 0, which matches ::T_Key_config.Number word Key; ///< Keyboard shortcut: SDLK_something, or -1 for none word Key2; ///< Alternate keyboard shortcut: SDLK_something, or -1 for none } T_Config_shortcut_info; -#pragma pack() + /// This structure holds all the settings saved and loaded as gfx2.ini. typedef struct @@ -321,6 +363,10 @@ typedef struct word Double_click_speed; ///< Maximum delay for double-click, in ms. word Double_key_speed; ///< Maximum delay for double-keypress, in ms. byte Grid_XOR_color; ///< XOR value to apply for grid color. + byte Right_click_colorpick; ///< Boolean, true to enable a "tablet" mode, where RMB acts as instant colorpicker + byte Sync_views; ///< Boolean, true when the Main and Spare should share their viewport settings. + byte Stylus_mode; ///< Boolean, true to tweak some tools (eg:Curve) for single-button stylus. + word Swap_buttons; ///< Sets which key swaps mouse buttons : 0=none, or MOD_CTRL, or MOD_ALT. } T_Config; // Structures utilisées pour les descriptions de pages et de liste de pages. @@ -347,6 +393,7 @@ typedef struct T_Page byte File_format; ///< File format, in enum ::FILE_FORMATS struct T_Page *Next; ///< Pointer to the next backup struct T_Page *Prev; ///< Pointer to the previous backup + T_Gradient_array *Gradients; ///< Pointer to the gradients used by the image. byte Background_transparent; ///< Boolean, true if Layer 0 should have transparent pixels byte Transparent_color; ///< Index of transparent color. 0 to 255. byte Nb_layers; ///< Number of layers @@ -381,6 +428,7 @@ typedef struct word Height; byte * Brush; /// < Color brush (if any) T_Palette Palette; + byte Colormap[256]; byte Transp_color; } T_Brush_template; @@ -396,21 +444,6 @@ typedef struct /// Graphic resources for the mouse cursor. byte Cursor_sprite[NB_CURSOR_SPRITES][CURSOR_SPRITE_HEIGHT][CURSOR_SPRITE_WIDTH]; - // Preset paintbrushes - - /// Graphic resources for the preset paintbrushes. - byte Paintbrush_sprite [NB_PAINTBRUSH_SPRITES][PAINTBRUSH_HEIGHT][PAINTBRUSH_WIDTH]; - /// Width of the preset paintbrushes. - word Preset_paintbrush_width[NB_PAINTBRUSH_SPRITES]; - /// Height of the preset paintbrushes. - word Preset_paintbrush_height[NB_PAINTBRUSH_SPRITES]; - /// Type of the preset paintbrush: index in enum PAINTBRUSH_SHAPES - byte Paintbrush_type[NB_PAINTBRUSH_SPRITES]; - /// Brush handle for the preset brushes. Generally ::Preset_paintbrush_width[]/2 - word Preset_paintbrush_offset_X[NB_PAINTBRUSH_SPRITES]; - /// Brush handle for the preset brushes. Generally ::Preset_paintbrush_height[]/2 - word Preset_paintbrush_offset_Y[NB_PAINTBRUSH_SPRITES]; - // Sieve patterns /// Preset sieve patterns, stored as binary (one word per line) @@ -419,13 +452,13 @@ typedef struct // Menu and other graphics /// Bitmap data for the menu, a single rectangle. - byte Menu_block[35][MENU_WIDTH]; - byte Layerbar_block[10][144]; - byte Statusbar_block[9][20]; + byte Menu_block[3][35][MENU_WIDTH]; + byte Layerbar_block[3][10][144]; + byte Statusbar_block[3][9][20]; /// Bitmap data for the icons that are displayed over the menu. - byte Menu_sprite[NB_MENU_SPRITES][MENU_SPRITE_HEIGHT][MENU_SPRITE_WIDTH]; + byte Menu_sprite[2][NB_MENU_SPRITES][MENU_SPRITE_HEIGHT][MENU_SPRITE_WIDTH]; /// Bitmap data for the different "effects" icons. - byte Effect_sprite[NB_EFFECTS_SPRITES][MENU_SPRITE_HEIGHT][MENU_SPRITE_WIDTH]; + byte Effect_sprite[NB_EFFECTS_SPRITES][EFFECT_SPRITE_HEIGHT][EFFECT_SPRITE_WIDTH]; /// Bitmap data for the different Layer icons. byte Layer_sprite[3][16][LAYER_SPRITE_HEIGHT][LAYER_SPRITE_WIDTH]; /// Bitmap data for the Grafx2 logo that appears on splash screen. All 256 colors allowed. @@ -458,16 +491,33 @@ typedef struct /// Transparent GUI color index in skin file byte Color_trans; - } T_Gui_skin; +typedef struct { + // Preset paintbrushes + + /// Graphic resources for the preset paintbrushes. + byte Sprite[PAINTBRUSH_HEIGHT][PAINTBRUSH_WIDTH]; + /// Width of the preset paintbrushes. + word Width; + /// Height of the preset paintbrushes. + word Height; + /// Type of the preset paintbrush: index in enum PAINTBRUSH_SHAPES + byte Shape; + /// Brush handle for the preset brushes. Generally ::Width[]/2 + word Offset_X; + /// Brush handle for the preset brushes. Generally ::Height[]/2 + word Offset_Y; + +} T_Paintbrush; + // A menubar. typedef struct { word Width; word Height; byte Visible; word Top; ///< Relative to the top line of the menu, hidden bars don't count. - byte* Skin; + byte* Skin[3]; ///< [0] has normal buttons, [1] has selected buttons, [2] is current. word Skin_width; byte Last_button_index; } T_Menu_Bar; diff --git a/src/text.c b/src/text.c index 1a6ce573..701ba06e 100644 --- a/src/text.c +++ b/src/text.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2008 Adrien Destugues @@ -36,19 +37,18 @@ #include #endif -#if defined(__linux__) -#if defined(__macosx__) +#if defined(__CAANOO__) || defined(__WIZ__) || defined(__GP2X__) +// No X11 +#elif defined(__macosx__) #include #import #import -#else +#elif defined(__linux__) #include #endif #endif -#endif #include -// SFont #include "SFont.h" #include "struct.h" @@ -56,6 +56,9 @@ #include "sdlscreen.h" #include "io.h" #include "errors.h" +#include "windows.h" +#include "misc.h" +#include "setup.h" typedef struct T_Font { @@ -282,7 +285,7 @@ void Init_text(void) Nb_fonts=0; // Parcours du répertoire "fonts" strcpy(directory_name, Data_directory); - strcat(directory_name, "fonts"); + strcat(directory_name, FONTS_SUBDIRECTORY); For_each_file(directory_name, Add_font); #if defined(__WIN32__) @@ -321,6 +324,8 @@ void Init_text(void) CFRelease(url); #endif + #elif defined(__CAANOO__) || defined(__WIZ__) || defined(__GP2X__) + // No X11 : Only use fonts from Grafx2 #elif defined(__linux__) #ifndef NOTTF #define USE_XLIB @@ -343,15 +348,22 @@ void Init_text(void) #ifndef NOTTF For_each_file( "FONTS:_TrueType", Add_font ); #endif - #elif defined(__BEOS__) || defined(__HAIKU__) + #elif defined(__BEOS__) #ifndef NOTTF For_each_file("/etc/fonts/ttfonts", Add_font); #endif - + #elif defined(__HAIKU__) + #ifndef NOTTF + For_each_file("/boot/system/data/fonts/ttfonts/", Add_font); + #endif #elif defined(__SKYOS__) #ifndef NOTTF For_each_file("/boot/system/fonts", Add_font); #endif + #elif defined(__MINT__) + #ifndef NOTTF + For_each_file("C:/BTFONTS", Add_font); + #endif #endif } @@ -368,17 +380,15 @@ int TrueType_is_supported() #ifndef NOTTF -byte *Render_text_TTF(const char *str, int font_number, int size, int antialias, int bold, int italic, int *width, int *height) +byte *Render_text_TTF(const char *str, int font_number, int size, int antialias, int bold, int italic, int *width, int *height, T_Palette palette) { - TTF_Font *font; - SDL_Surface * TexteColore; - SDL_Surface * Texte8Bit; + TTF_Font *font; + SDL_Surface * text_surface; byte * new_brush; - int index; int style; - SDL_Color Couleur_Avant; - SDL_Color Couleur_Arriere; + SDL_Color fg_color; + SDL_Color bg_color; // Chargement de la fonte font=TTF_OpenFont(Font_name(font_number), size); @@ -386,6 +396,7 @@ byte *Render_text_TTF(const char *str, int font_number, int size, int antialias, { return NULL; } + // Style style=0; if (italic) @@ -393,82 +404,170 @@ byte *Render_text_TTF(const char *str, int font_number, int size, int antialias, if (bold) style|=TTF_STYLE_BOLD; TTF_SetFontStyle(font, style); - // Couleurs - if (antialias) - { - Couleur_Avant = Color_to_SDL_color(Fore_color); - Couleur_Arriere = Color_to_SDL_color(Back_color); - } - else - { - Couleur_Avant = Color_to_SDL_color(MC_White); - Couleur_Arriere = Color_to_SDL_color(MC_Black); - } - - // Rendu du texte: crée une surface SDL RGB 24bits + // Colors: Text will be generated as white on black. + fg_color.r=fg_color.g=fg_color.b=255; + bg_color.r=bg_color.g=bg_color.b=0; + // The following is alpha, supposedly unused + bg_color.unused=fg_color.unused=255; + + // Text rendering: creates a 8bit surface with its dedicated palette if (antialias) - TexteColore=TTF_RenderText_Shaded(font, str, Couleur_Avant, Couleur_Arriere ); + text_surface=TTF_RenderText_Shaded(font, str, fg_color, bg_color ); else - TexteColore=TTF_RenderText_Solid(font, str, Couleur_Avant); - if (!TexteColore) + text_surface=TTF_RenderText_Solid(font, str, fg_color); + if (!text_surface) { TTF_CloseFont(font); return NULL; } - - Texte8Bit=SDL_DisplayFormat(TexteColore); - - SDL_FreeSurface(TexteColore); - new_brush=Surface_to_bytefield(Texte8Bit, NULL); + new_brush=Surface_to_bytefield(text_surface, NULL); if (!new_brush) { - SDL_FreeSurface(TexteColore); - SDL_FreeSurface(Texte8Bit); + SDL_FreeSurface(text_surface); TTF_CloseFont(font); return NULL; } - if (!antialias) + + // Import palette + Get_SDL_Palette(text_surface->format->palette, palette); + + if (antialias) { - // Mappage des couleurs - for (index=0; index < Texte8Bit->w * Texte8Bit->h; index++) + int black_col; + // Shaded text: X-Swap the color that is pure black with the BG color number, + // so that the brush is immediately 'transparent' + + // Find black (c) + for (black_col=0; black_col<256; black_col++) { - if (*(new_brush+index) == MC_Black) - *(new_brush+index)=Back_color; - else if (*(new_brush+index) == MC_White) - *(new_brush+index)=Fore_color; + if (palette[black_col].R==0 && palette[black_col].G==0 && palette[black_col].B==0) + break; + } // If not found: c = 256 = 0 (byte) + + if (black_col != Back_color) + { + int c; + byte colmap[256]; + // Swap palette entries + + SWAP_BYTES(palette[black_col].R, palette[Back_color].R) + SWAP_BYTES(palette[black_col].G, palette[Back_color].G) + SWAP_BYTES(palette[black_col].B, palette[Back_color].B) + + // Define a colormap + for (c=0; c<256; c++) + colmap[c]=c; + + // The swap + colmap[black_col]=Back_color; + colmap[Back_color]=black_col; + + Remap_general_lowlevel(colmap, new_brush, new_brush, text_surface->w,text_surface->h, text_surface->w); + + // Also, make the BG color in brush palette have same RGB values as + // the current BG color : this will help for remaps. + palette[Back_color].R=Main_palette[Back_color].R; + palette[Back_color].G=Main_palette[Back_color].G; + palette[Back_color].B=Main_palette[Back_color].B; } } - *width=Texte8Bit->w; - *height=Texte8Bit->h; - SDL_FreeSurface(Texte8Bit); + else + { + // Solid text: Was rendered as white on black. Now map colors: + // White becomes FG color, black becomes BG. 2-color palette. + // Exception: if BG==FG, FG will be set to black or white - any different color. + long index; + byte new_fore=Fore_color; + + if (Fore_color==Back_color) + { + if (Main_palette[Back_color].R+Main_palette[Back_color].G+Main_palette[Back_color].B > 128*3) + // Back color is rather light: + new_fore=MC_Black; + else + // Back color is rather dark: + new_fore=MC_White; + } + + for (index=0; index < text_surface->w * text_surface->h; index++) + { + if (palette[*(new_brush+index)].G < 128) + *(new_brush+index)=Back_color; + else + *(new_brush+index)=new_fore; + } + + // Now copy the current palette to brushe's, for consistency + // with the indices. + memcpy(palette, Main_palette, sizeof(T_Palette)); + + } + *width=text_surface->w; + *height=text_surface->h; + SDL_FreeSurface(text_surface); TTF_CloseFont(font); return new_brush; } #endif -byte *Render_text_SFont(const char *str, int font_number, int *width, int *height) +byte *Render_text_SFont(const char *str, int font_number, int *width, int *height, T_Palette palette) { SFont_Font *font; - SDL_Surface * TexteColore; - SDL_Surface * Texte8Bit; - SDL_Surface *Surface_fonte; + SDL_Surface * text_surface; + SDL_Surface *font_surface; byte * new_brush; SDL_Rect rectangle; // Chargement de la fonte - Surface_fonte=IMG_Load(Font_name(font_number)); - if (!Surface_fonte) + font_surface=IMG_Load(Font_name(font_number)); + if (!font_surface) { - DEBUG("Font loading failed",0); + Verbose_message("Warning","Error loading font.\nThe file may be corrupt."); return NULL; } - font=SFont_InitFont(Surface_fonte); + // Font is 24bit: Perform a color reduction + if (font_surface->format->BitsPerPixel>8) + { + SDL_Surface * reduced_surface; + int x,y,color; + SDL_Color rgb; + + reduced_surface=SDL_CreateRGBSurface(SDL_SWSURFACE, font_surface->w, font_surface->h, 8, 0, 0, 0, 0); + if (!reduced_surface) + { + SDL_FreeSurface(font_surface); + return NULL; + } + // Set the quick palette + for (color=0;color<256;color++) + { + rgb.r=((color & 0xE0)>>5)<<5; + rgb.g=((color & 0x1C)>>2)<<5; + rgb.b=((color & 0x03)>>0)<<6; + SDL_SetColors(reduced_surface, &rgb, color, 1); + } + // Perform reduction + for (y=0; yh; y++) + for (x=0; xw; x++) + { + SDL_GetRGB(Get_SDL_pixel_hicolor(font_surface, x, y), font_surface->format, &rgb.r, &rgb.g, &rgb.b); + color=((rgb.r >> 5) << 5) | + ((rgb.g >> 5) << 2) | + ((rgb.b >> 6)); + Set_SDL_pixel_8(reduced_surface, x, y, color); + } + + SDL_FreeSurface(font_surface); + font_surface=reduced_surface; + } + font=SFont_InitFont(font_surface); if (!font) { DEBUG("Font init failed",1); + SDL_FreeSurface(font_surface); return NULL; } @@ -476,40 +575,36 @@ byte *Render_text_SFont(const char *str, int font_number, int *width, int *heigh *height=SFont_TextHeight(font); *width=SFont_TextWidth(font, str); // Allocation d'une surface SDL - TexteColore=SDL_CreateRGBSurface(SDL_SWSURFACE, *width, *height, 24, 0, 0, 0, 0); + text_surface=SDL_CreateRGBSurface(SDL_SWSURFACE, *width, *height, 8, 0, 0, 0, 0); + // Copy palette + SDL_SetPalette(text_surface, SDL_LOGPAL, font_surface->format->palette->colors, 0, 256); // Fill with backcolor rectangle.x=0; rectangle.y=0; rectangle.w=*width; rectangle.h=*height; - SDL_FillRect(TexteColore, &rectangle, SDL_MapRGB( - TexteColore->format, - Main_palette[Back_color].R, - Main_palette[Back_color].G, - Main_palette[Back_color].B - )); + SDL_FillRect(text_surface, &rectangle, Back_color); // Rendu du texte - SFont_Write(TexteColore, font, 0, 0, str); - if (!TexteColore) + SFont_Write(text_surface, font, 0, 0, str); + if (!text_surface) { DEBUG("Rendering failed",2); SFont_FreeFont(font); return NULL; } - - Texte8Bit=SDL_DisplayFormat(TexteColore); - SDL_FreeSurface(TexteColore); - new_brush=Surface_to_bytefield(Texte8Bit, NULL); + new_brush=Surface_to_bytefield(text_surface, NULL); if (!new_brush) { DEBUG("Converting failed",3); - SDL_FreeSurface(TexteColore); - SDL_FreeSurface(Texte8Bit); + SDL_FreeSurface(text_surface); SFont_FreeFont(font); return NULL; } - SDL_FreeSurface(Texte8Bit); + + Get_SDL_Palette(font_surface->format->palette, palette); + + SDL_FreeSurface(text_surface); SFont_FreeFont(font); return new_brush; @@ -524,7 +619,7 @@ byte *Render_text_SFont(const char *str, int font_number, int *width, int *heigh // Crée une brosse à partir des paramètres de texte demandés. // Si cela réussit, la fonction place les dimensions dans width et height, // et retourne l'adresse du bloc d'octets. -byte *Render_text(const char *str, int font_number, TTFONLY int size, int TTFONLY antialias, TTFONLY int bold, TTFONLY int italic, int *width, int *height) +byte *Render_text(const char *str, int font_number, TTFONLY int size, int TTFONLY antialias, TTFONLY int bold, TTFONLY int italic, int *width, int *height, T_Palette palette) { T_Font *font = font_list_start; int index=font_number; @@ -538,14 +633,14 @@ byte *Render_text(const char *str, int font_number, TTFONLY int size, int TTFONL if (font->Is_truetype) { #ifndef NOTTF - return Render_text_TTF(str, font_number, size, antialias, bold, italic, width, height); + return Render_text_TTF(str, font_number, size, antialias, bold, italic, width, height, palette); #else return NULL; #endif } else { - return Render_text_SFont(str, font_number, width, height); + return Render_text_SFont(str, font_number, width, height, palette); } } diff --git a/src/text.h b/src/text.h index 48b3e20b..6d65b274 100644 --- a/src/text.h +++ b/src/text.h @@ -41,15 +41,16 @@ void Add_font(const char *name); /// @param italic Boolean, true to use italic rendering in TrueType /// @param width Returns the width of the created brush, in pixels. /// @param height Returns the height of the created brush, in pixels. +/// @param palette Returns the custom palette for the brush. /// Returns true on success. -byte *Render_text(const char *str, int font_number, int size, int antialias, int bold, int italic, int *width, int *height); +byte *Render_text(const char *str, int font_number, int size, int antialias, int bold, int italic, int *width, int *height, T_Palette palette); /// Finds a label to display for a font declared with ::Add_font(). char * Font_label(int index); /// Finds the filename of a font declared with ::Add_font(). char * Font_name(int index); /// Returns true if the font of this number is TrueType, false if it's a SFont bitmap. -char * TrueType_font(int index); +int TrueType_font(int index); /// /// Number of fonts declared with a series of ::Add_font(). This is public for /// convenience, but functionaly it is read-only. diff --git a/src/tiles.c b/src/tiles.c new file mode 100644 index 00000000..32078abc --- /dev/null +++ b/src/tiles.c @@ -0,0 +1,114 @@ +/* vim:expandtab:ts=2 sw=2: +*/ +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2010 Adrien Destugues + + Grafx2 is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 + of the License. + + Grafx2 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grafx2; if not, see +*/ + +/// \file Handle tiles. + +/// Build the tile-area from the current picture +void build_tile_area() +{ + word tileAreaWidth = Main_image_width / Snap_width + 1; + word tileAreaHeight = Main_image_height / Snap_height + 1; + + int* tileArea = malloc(tileAreaWidth*tileAreaHeight*sizeof(int)); + + word tile_x, tile_y, pixel_x, pixel_y; + + // For each tile, we have to crawl up to the top of the picture and + // find the first identical tile + for (tile_y = 0; tile_y < tileAreaWidth; tile_y++) + for(tile_x = 0; tile_x < tileAreaHeight; tile_x++) + { + // So, this is the "for each tile" + word ctx, cty; + // First we compare the tile with the others one in the same line at the left + for(ctx = tile_x - 1; ctx >= 0; ctx--) + if(compare_tiles(tile_x*Snap_width, tile_y*Snap_height, ctx*Snap_width, tile_y*Snap_height)) + { + // We found a match ! + tileArea[tile_y*tileAreaWidth+tile_x] = tile_y*tileAreaWidth+ctx; + goto found; + } + + // Then we look at all the lines above + for(cty = tile_y - 1; cty >= 0; cty--) + for(ctx = tileAreaWidth - 1; ctx >= 0; ctx--) + if(compare_tiles(tile_x*Snap_width, tile_y*Snap_height, ctx*Snap_width, cty*Snap_height)) + { + // We found a match ! + tileArea[tile_y*tileAreaWidth+tile_x] = cty*tileAreaWidth+ctx; + goto found; + } + + // Then we look at all the lines below + for(cty = tileAreaHeight - 1; cty >= tile_y; cty--) + for(ctx = tileAreaWidth - 1; ctx >= 0; ctx--) + if(compare_tiles(tile_x*Snap_width, tile_y*Snap_height, ctx*Snap_width, cty*Snap_height)) + { + // We found a match ! + tileArea[tile_y*tileAreaWidth+tile_x] = cty*tileAreaWidth+ctx; + goto found; + } + + // Then we look at the tiles at the right of this one + // (including the tile itself, so we are sure we match something this time) + for(ctx = tileAreaHeight; ctx >= tile_x; ctx--) + if(compare_tiles(tile_x*Snap_width, tile_y*Snap_height, ctx*Snap_width, tile_y*Snap_height)) + { + // We found a match ! + tileArea[tile_y*tileAreaWidth+tile_x] = tile_y*tileAreaWidth+ctx; + } + +found: + } +} + + +// Compare tiles +// The parameters are in pixel-space. +void compare_tiles(word x1, word y1, word x2, word y2) +{ + word pixel_x, pixel_y; + byte c1, c2; + + for (pixel_y = 0; pixel_y < Snap_width; pixel_y++) + for (pixel_x = 0; pixel_x < Snap_height; pixel_x++) + { + c1 = Main_screen + (y1+pixel_y) * Main_image_width + (x1+pixel_x); + c2 = Main_screen + (y2+pixel_y) * Main_image_width + (x2+pixel_x); + if (c1 != c2) return 0; + } + + return 1; +} + +/// Copy a tile pixeldata to all the identical ones +// Call this after the end of an operation +void update_tile(word pixel_x, word pixel_y) +{ + int tileOffset = (pixel_y/Snap_height)*tileAreaHeight + pixel_x/Snap_width; + int firstTileOffset = tileOffset + 1; // to make sure they are not equal + + while(firstTileOffset != tileOffset) + { + tileOffset = tileArea[tileOffset]; + + //do the copy of a block starting at (pixel_x, pixel_y) + } +} diff --git a/src/transform.c b/src/transform.c index a59963bc..f603fa4a 100644 --- a/src/transform.c +++ b/src/transform.c @@ -273,7 +273,7 @@ void Button_Transform_menu(void) input_button[clicked_button-10]->Pos_Y+2, buffer, 4, - 1)) + INPUT_TYPE_INTEGER)) { // Accept entered value *(input_value[clicked_button-10])=atoi(buffer); @@ -369,8 +369,9 @@ void Button_Transform_menu(void) old_width=Main_image_width; old_height=Main_image_height; + Upload_infos_page_main(Main_backups->Pages); // Allocate a new page - if (Backup_with_new_dimensions(1,Main_backups->Pages->Nb_layers,new_width,new_height)) + if (Backup_with_new_dimensions(new_width,new_height)) { // The new image is allocated, the new dimensions are already updated. diff --git a/src/windows.c b/src/windows.c index f3d28505..49c3d456 100644 --- a/src/windows.c +++ b/src/windows.c @@ -36,8 +36,11 @@ #include "graph.h" #include "input.h" #include "misc.h" +#include "op_c.h" #include "readline.h" #include "sdlscreen.h" +#include "palette.h" + /// Width of one layer button, in pixels before scaling word Layer_button_width = 1; @@ -67,7 +70,7 @@ void Pixel_in_menu(word bar, word x, word y, byte color) void Pixel_in_menu_and_skin(word bar, word x, word y, byte color) { Pixel_in_menu(bar, x, y, color); - Menu_bars[bar].Skin[y*Menu_bars[bar].Skin_width + x] = color; + Menu_bars[bar].Skin[2][y*Menu_bars[bar].Skin_width + x] = color; } // Affichage d'un pixel dans la fenêtre (la fenêtre doit être visible) @@ -454,7 +457,7 @@ void Draw_bar_remainder(word current_menu, word x_off) for (y_pos=0;y_pos=0) && (Paintbrush_Y>=0) @@ -1073,7 +1077,7 @@ int Requester_window(char* message, int initial_value) { clicked_button = Window_clicked_button(); if (clicked_button == 1) - Readline(11, 39, str, 4, 1); + Readline(11, 39, str, 4, INPUT_TYPE_INTEGER); if (Key == SDLK_ESCAPE) clicked_button = 2; } while (clicked_button <= 0); @@ -1179,90 +1183,34 @@ void Verbose_message(const char *caption, const char * message ) // -- Redessiner le sprite d'un bouton dans le menu -- -void Display_sprite_in_menu(int btn_number,int sprite_number) +void Display_sprite_in_menu(int btn_number,char sprite_number) { - word x_pos; - word y_pos; - word menu_x_pos; - word menu_y_pos; - byte color; + Buttons_Pool[btn_number].Icon=sprite_number; - menu_y_pos=Buttons_Pool[btn_number].Y_offset; - menu_x_pos=Buttons_Pool[btn_number].X_offset; - if (Buttons_Pool[btn_number].Shape != BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT) - { - menu_y_pos+=1; - menu_x_pos+=1; - } - - for (y_pos=0;y_posMenu_sprite[sprite_number][y_pos][x_pos]; - Pixel_in_menu_and_skin(MENUBAR_TOOLS, menu_x_pos+x_pos, menu_y_pos+y_pos, color); - } -if (Menu_is_visible && Menu_bars[MENUBAR_TOOLS].Visible) - Update_rect(Menu_factor_X*(Buttons_Pool[btn_number].X_offset+1), - (Buttons_Pool[btn_number].Y_offset+1+Menu_bars[MENUBAR_TOOLS].Top)*Menu_factor_Y+Menu_Y, - MENU_SPRITE_WIDTH*Menu_factor_X,MENU_SPRITE_HEIGHT*Menu_factor_Y); + if (Buttons_Pool[btn_number].Shape == BUTTON_SHAPE_TRIANGLE_TOP_LEFT) + Buttons_Pool[btn_number+1].Icon=sprite_number; + + else if (Buttons_Pool[btn_number].Shape == BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT) + Buttons_Pool[btn_number-1].Icon=sprite_number; } // -- Redessiner la forme du pinceau dans le menu -- void Display_paintbrush_in_menu(void) { - short x_pos,y_pos; - short start_x; - short menu_x_pos,menu_y_pos; - short menu_start_x; - byte color; - - switch (Paintbrush_shape) + switch(Paintbrush_shape) { - case PAINTBRUSH_SHAPE_COLOR_BRUSH : // Brush en couleur - case PAINTBRUSH_SHAPE_MONO_BRUSH : // Brush monochrome - for (menu_y_pos=2,y_pos=0;y_posMenu_sprite[4][y_pos][x_pos]; - Pixel_in_menu_and_skin(MENUBAR_TOOLS, menu_x_pos, menu_y_pos, color); - } + case PAINTBRUSH_SHAPE_COLOR_BRUSH: + Display_sprite_in_menu(BUTTON_PAINTBRUSHES, MENU_SPRITE_COLOR_BRUSH); + break; + case PAINTBRUSH_SHAPE_MONO_BRUSH: + Display_sprite_in_menu(BUTTON_PAINTBRUSHES, MENU_SPRITE_MONO_BRUSH); + break; + default: + Display_sprite_in_menu(BUTTON_PAINTBRUSHES, -1); break; - default : // Pinceau - // On efface le pinceau précédent - for (menu_y_pos=2,y_pos=0;y_posPreset_paintbrush_offset_X[number])*x_size+Window_pos_X; - origin_y = (y + 8)*Menu_factor_Y - (Gfx->Preset_paintbrush_offset_Y[number])*y_size+Window_pos_Y; + width=Min(Paintbrush[number].Width,PAINTBRUSH_WIDTH); + height=Min(Paintbrush[number].Height,PAINTBRUSH_WIDTH); + + origin_x = (x + 8)*Menu_factor_X - (width/2)*x_size+Window_pos_X; + origin_y = (y + 8)*Menu_factor_Y - (height/2)*y_size+Window_pos_Y; - for (window_y_pos=0,y_pos=0; y_posPreset_paintbrush_height[number]; window_y_pos++,y_pos++) - for (window_x_pos=0,x_pos=0; x_posPreset_paintbrush_width[number]; window_x_pos++,x_pos++) - Block(origin_x+window_x_pos*x_size,origin_y+window_y_pos*y_size,x_size,y_size,(Gfx->Paintbrush_sprite[number][y_pos][x_pos])?MC_Black:MC_Light); + for (window_y_pos=0,y_pos=0; y_posPreset_paintbrush_width[number]), - ToWinH(Gfx->Preset_paintbrush_height[number]) + ToWinL(Paintbrush[number].Width), + ToWinH(Paintbrush[number].Height) ); } @@ -1553,6 +1507,7 @@ void Compute_paintbrush_coordinates(void) { // Operations that don't implement it case OPERATION_LINE: + case OPERATION_ROTATE_BRUSH: Snap_axis=0; break; // Operations that implement it @@ -1857,7 +1812,36 @@ void Change_magnifier_factor(byte factor_index, byte point_at_mouse) Compute_paintbrush_coordinates(); } +void Copy_view_to_spare(void) +{ + + // Don't do anything if the pictures have different dimensions + if (Main_image_width!=Spare_image_width || Main_image_height!=Spare_image_height) + return; + + // Copie des décalages de la fenêtre principale (non zoomée) de l'image + Spare_offset_X=Main_offset_X; + Spare_offset_Y=Main_offset_Y; + // Copie du booléen "Mode loupe" de l'image + Spare_magnifier_mode=Main_magnifier_mode; + + // Copie du facteur de zoom du brouillon + Spare_magnifier_factor=Main_magnifier_factor; + + // Copie des dimensions de la fenêtre de zoom + Spare_magnifier_width=Main_magnifier_width; + Spare_magnifier_height=Main_magnifier_height; + + // Copie des décalages de la fenêtre de zoom + Spare_magnifier_offset_X=Main_magnifier_offset_X; + Spare_magnifier_offset_Y=Main_magnifier_offset_Y; + + // Copie des données du split du zoom + Spare_separator_position=Main_separator_position; + Spare_X_zoom=Main_X_zoom; + Spare_separator_proportion=Main_separator_proportion; +} // -- Afficher la barre de séparation entre les parties zoomées ou non en // mode Loupe -- @@ -2629,7 +2613,7 @@ void Display_all_screen(void) byte Best_color(byte r,byte g,byte b) { - short col; + int col; int delta_r,delta_g,delta_b; int dist; int best_dist=0x7FFFFFFF; @@ -2663,7 +2647,7 @@ byte Best_color(byte r,byte g,byte b) byte Best_color_nonexcluded(byte red,byte green,byte blue) { - short col; + int col; int delta_r,delta_g,delta_b; int dist; int best_dist=0x7FFFFFFF; @@ -2692,65 +2676,50 @@ byte Best_color_nonexcluded(byte red,byte green,byte blue) return best_color; } -void Compute_4_best_colors_for_1_menu_color - (byte red, byte green, byte blue, T_Components * palette, byte * table) + + +byte Best_color_perceptual(byte r,byte g,byte b) { - short col; - int delta_r,delta_g,delta_b; - int dist; - int best_dist[4]={0x7FFFFFFF,0x7FFFFFFF,0x7FFFFFFF,0x7FFFFFFF}; - + + int col; + float best_diff=255.0*1.56905; + byte best_color=0; + float target_bri; + float bri; + float diff_b, diff_c, diff; + // Similar to Perceptual_lightness(); + target_bri = sqrt(0.26*r*0.26*r + 0.55*g*0.55*g + 0.19*b*0.19*b); + for (col=0; col<256; col++) { - delta_r=(int)palette[col].R-red; - delta_g=(int)palette[col].G-green; - delta_b=(int)palette[col].B-blue; + if (Exclude_color[col]) + continue; - dist=(delta_r*delta_r*30)+(delta_g*delta_g*59)+(delta_b*delta_b*11); + diff_c = sqrt( + (0.26*(Main_palette[col].R-r))* + (0.26*(Main_palette[col].R-r))+ + (0.55*(Main_palette[col].G-g))* + (0.55*(Main_palette[col].G-g))+ + (0.19*(Main_palette[col].B-b))* + (0.19*(Main_palette[col].B-b))); + // Exact match + if (diff_c==0) + return col; - if (distDefault_palette[Gfx->Color[0]].R, Gfx->Default_palette[Gfx->Color[0]].G, Gfx->Default_palette[Gfx->Color[0]].B,palette,table); - MC_Black=table[0]; - - // Recherche du blanc - Compute_4_best_colors_for_1_menu_color - (Gfx->Default_palette[Gfx->Color[3]].R, Gfx->Default_palette[Gfx->Color[3]].G, Gfx->Default_palette[Gfx->Color[3]].B,palette,table); - if (MC_Black!=table[0]) - MC_White=table[0]; - else - MC_White=table[1]; - - // Recherche du gris clair - Compute_4_best_colors_for_1_menu_color - (Gfx->Default_palette[Gfx->Color[2]].R, Gfx->Default_palette[Gfx->Color[2]].G, Gfx->Default_palette[Gfx->Color[2]].B,palette,table); - if ( (MC_Black!=table[0]) && (MC_White!=table[0]) ) - MC_Light=table[0]; - else + // First method: + // If all close matches for the ideal colors exist, pick them. + for (i=255; i>=0; i--) { - if ( (MC_Black!=table[1]) && (MC_White!=table[1]) ) - MC_Light=table[1]; - else - MC_Light=table[2]; - } - - // Recherche du gris foncé - Compute_4_best_colors_for_1_menu_color - (Gfx->Default_palette[Gfx->Color[1]].R, Gfx->Default_palette[Gfx->Color[1]].G, Gfx->Default_palette[Gfx->Color[1]].B,palette,table); - if ( (MC_Black!=table[0]) && (MC_White!=table[0]) && (MC_Light!=table[0]) ) - MC_Dark=table[0]; - else - { - if ( (MC_Black!=table[1]) && (MC_White!=table[1]) && (MC_Light!=table[1]) ) - MC_Dark=table[1]; - else + + if (Round_palette_component(palette[i].R)/tolerence==Gfx->Default_palette[Gfx->Color[3]].R/tolerence + && Round_palette_component(palette[i].G)/tolerence==Gfx->Default_palette[Gfx->Color[3]].G/tolerence + && Round_palette_component(palette[i].B)/tolerence==Gfx->Default_palette[Gfx->Color[3]].B/tolerence) { - if ( (MC_Black!=table[2]) && (MC_White!=table[2]) && (MC_Light!=table[2]) ) - MC_Dark=table[2]; - else - MC_Dark=table[3]; + MC_White=i; + for (i=255; i>=0; i--) + { + if (Round_palette_component(palette[i].R)/tolerence==Gfx->Default_palette[Gfx->Color[2]].R/tolerence + && Round_palette_component(palette[i].G)/tolerence==Gfx->Default_palette[Gfx->Color[2]].G/tolerence + && Round_palette_component(palette[i].B)/tolerence==Gfx->Default_palette[Gfx->Color[2]].B/tolerence) + { + MC_Light=i; + for (i=255; i>=0; i--) + { + if (Round_palette_component(palette[i].R)/tolerence==Gfx->Default_palette[Gfx->Color[1]].R/tolerence + && Round_palette_component(palette[i].G)/tolerence==Gfx->Default_palette[Gfx->Color[1]].G/tolerence + && Round_palette_component(palette[i].B)/tolerence==Gfx->Default_palette[Gfx->Color[1]].B/tolerence) + { + MC_Dark=i; + for (i=255; i>=0; i--) + { + if (Round_palette_component(palette[i].R)/tolerence==Gfx->Default_palette[Gfx->Color[0]].R/tolerence + && Round_palette_component(palette[i].G)/tolerence==Gfx->Default_palette[Gfx->Color[0]].G/tolerence + && Round_palette_component(palette[i].B)/tolerence==Gfx->Default_palette[Gfx->Color[0]].B/tolerence) + { + MC_Black=i; + // On cherche une couleur de transparence différente des 4 autres. + for (MC_Trans=0; ((MC_Trans==MC_Black) || (MC_Trans==MC_Dark) || + (MC_Trans==MC_Light) || (MC_Trans==MC_White)); MC_Trans++); + // Easy case + MC_OnBlack=MC_Dark; + MC_Window=MC_Light; + MC_Lighter=MC_White; + MC_Darker=MC_Dark; + Remap_menu_sprites(); + return; + } + } + } + } + } + } } } - - // C'est peu probable mais il est possible que MC_Light soit plus foncée que - // MC_Dark. Dans ce cas, on les inverse. - if ( ((palette[MC_Light].R*30)+(palette[MC_Light].G*59)+(palette[MC_Light].B*11)) < - ((palette[MC_Dark].R*30)+(palette[MC_Dark].G*59)+(palette[MC_Dark].B*11)) ) + // Second method: For CPC 27-color modes only + // Try to find colors that just work + if (Get_palette_RGB_scale()==3) + for (i=255; i>=0; i--) { - SWAP_BYTES(MC_Light, MC_Dark); + + if (Round_palette_component(palette[i].R)/tolerence==cpc_colors[3].R/tolerence + && Round_palette_component(palette[i].G)/tolerence==cpc_colors[3].G/tolerence + && Round_palette_component(palette[i].B)/tolerence==cpc_colors[3].B/tolerence) + { + MC_White=i; + for (i=255; i>=0; i--) + { + if (Round_palette_component(palette[i].R)/tolerence==cpc_colors[2].R/tolerence + && Round_palette_component(palette[i].G)/tolerence==cpc_colors[2].G/tolerence + && Round_palette_component(palette[i].B)/tolerence==cpc_colors[2].B/tolerence) + { + MC_Light=i; + for (i=255; i>=0; i--) + { + if (Round_palette_component(palette[i].R)/tolerence==cpc_colors[1].R/tolerence + && Round_palette_component(palette[i].G)/tolerence==cpc_colors[1].G/tolerence + && Round_palette_component(palette[i].B)/tolerence==cpc_colors[1].B/tolerence) + { + MC_Dark=i; + for (i=255; i>=0; i--) + { + if (Round_palette_component(palette[i].R)/tolerence==cpc_colors[0].R/tolerence + && Round_palette_component(palette[i].G)/tolerence==cpc_colors[0].G/tolerence + && Round_palette_component(palette[i].B)/tolerence==cpc_colors[0].B/tolerence) + { + MC_Black=i; + // On cherche une couleur de transparence différente des 4 autres. + for (MC_Trans=0; ((MC_Trans==MC_Black) || (MC_Trans==MC_Dark) || + (MC_Trans==MC_Light) || (MC_Trans==MC_White)); MC_Trans++); + // Easy case + MC_OnBlack=MC_Dark; + MC_Window=MC_Light; + MC_Lighter=MC_White; + MC_Darker=MC_Dark; + Remap_menu_sprites(); + return; + } + } + } + } + } + } + } } + + // Third method: + + // Compute luminance for whole palette + // Take the darkest as black, the brightest white + for(i = 0; i < 256; i++) + { + RGB_to_HSL(palette[i].R, palette[i].G, palette[i].B, &h, &s[i], &l[i]); + // Another formula for lightness, in 0-255 range + //l[i]=Perceptual_lightness(&palette[i])/4062/255; + if (l[i] > max_l) + { + max_l = l[i]; + MC_White = i; + } + } + for(i = 0; i < 256; i++) + { + if (l[i] < min_l && i!=MC_White) + { + min_l = l[i]; + MC_Black = i; + } + } + // Alter the S values according to the L range - this is for the future + // comparisons, so that highly variable saturation doesn't weigh + // too heavily when the the lightness is in a narrow range. + for(i = 0; i < 256; i++) + { + s[i]=s[i]*(max_l-min_l)/255; + } + for(i = 0; i < 256; i++) + { + // Adjust (reduce) perceived saturation at both ends of L spectrum + if (l[i]>192) + s[i]=s[i]*(255-l[i])/64; + else if (l[i]<64) + s[i]=s[i]*l[i]/64; + } + + + // Find color nearest to min+2(max-min)/3 + // but at the same time we try to minimize the saturation so that the menu + // still looks grey + hi_l = min_l + 2*(max_l - min_l)/3; + + for (i = 0; i < 256; i++) + { + if ( abs(l[i] - hi_l) + s[i]/2 < delta_high && i!=MC_White && i!=MC_Black) + { + delta_high = abs(l[i] - hi_l) + s[i]/2; + MC_Light = i; + } + } + + // Target "Dark color" is 2/3 between Light and Black + low_l = ((int)l[MC_Light]*2+l[MC_Black])/3; + for (i = 0; i < 256; i++) + { + if ( abs((int)l[i] - low_l) + s[i]/6 < delta_low && i!=MC_White && i!=MC_Black && i!=MC_Light) + { + delta_low = abs((int)l[i] - low_l)+ s[i]/6; + MC_Dark = i; + } + } + + + //if (l[MC_Light]Cursor_sprite[k][j][i]); // Main menu bar - for (j=0; jMenu_block[j][i]); + for (k=0; k<3; k++) + for (j=0; jMenu_block[k][j][i]); // Menu sprites - for (k=0; kMenu_sprite[k][j][i]); + for (l=0; l<2; l++) + for (k=0; kMenu_sprite[l][k][j][i]); // Effects sprites for (k=0; kEffect_sprite[k][j][i]); // Layers buttons for (l=0; l<3; l++) @@ -2944,13 +3082,15 @@ void Remap_menu_sprites() Remap_pixel(&Gfx->Layer_sprite[l][k][j][i]); // Status bar - for (j=0; jStatusbar_block[j][i]); + for (k=0; k<3; k++) + for (j=0; jStatusbar_block[k][j][i]); // Layer bar - for (j=0; jLayerbar_block[j][i]); + for (k=0; k<3; k++) + for (j=0; jLayerbar_block[k][j][i]); // Help fonts for (k=0; k<256; k++) diff --git a/src/windows.h b/src/windows.h index 420d44c5..b5484247 100644 --- a/src/windows.h +++ b/src/windows.h @@ -89,7 +89,7 @@ void Window_display_frame_in(word x_pos,word y_pos,word width,word height); void Window_display_frame_out(word x_pos,word y_pos,word width,word height); void Window_display_frame(word x_pos,word y_pos,word width,word height); -void Display_sprite_in_menu(int btn_number,int sprite_number); +void Display_sprite_in_menu(int btn_number,char sprite_number); void Display_paintbrush_in_menu(void); void Display_paintbrush_in_window(word x,word y,int number); @@ -99,6 +99,7 @@ void Window_display_icon_sprite(word x_pos,word y_pos,byte type); byte Best_color(byte red,byte green,byte blue); byte Best_color_nonexcluded(byte red,byte green,byte blue); +byte Best_color_perceptual(byte r,byte g,byte b); void Horizontal_XOR_line_zoom(short x_pos, short y_pos, short width); void Vertical_XOR_line_zoom(short x_pos, short y_pos, short height); @@ -108,4 +109,7 @@ void Change_magnifier_factor(byte factor_index, byte point_at_mouse); /// Width of one layer button, in pixels before scaling extern word Layer_button_width; +/// Copy viewport settings and offsets from the Main to the Spare. +void Copy_view_to_spare(void); + #endif From 72e9892b53ee34aa5f1e663e55a5744b61f440c7 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Mon, 14 Feb 2011 13:37:35 +0000 Subject: [PATCH 4/9] Constraint mode is now switchable on/off in the effect screen. I did some changes to the effect screen to make some space : instead of displaying an "on/off" label, we now keep the button pressed for active effects. There is no "constraint menu" yet, we should allow to select different constraints there (C64, MO5, spectrum, ...) to activate their respective enforcer and plug the right thing to the associated checker. This should eventually allow drawers to : * Load any single-layer picture * Select the mode they want to use (without enabling it) * Run the checker and get the result as a multilayer (with an error layer) * Then, once they feel enough issues are solved, switch to "enforcer" mode for further manual tweaking. Now we need a checker for CPC Mode5... :) git-svn-id: svn://pulkomandy.tk/GrafX2/branches/cpcmode5@1721 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- src/brush.c | 4 +-- src/buttons.c | 80 ++++++++++++++++++++++++++++--------------- src/buttons.h | 3 ++ src/buttons_effects.c | 15 +++++++- src/global.h | 3 ++ src/graph.c | 19 +++++++++- src/pages.c | 2 +- 7 files changed, 94 insertions(+), 32 deletions(-) diff --git a/src/brush.c b/src/brush.c index bf4c0d39..6ed6addf 100644 --- a/src/brush.c +++ b/src/brush.c @@ -130,7 +130,7 @@ void Display_paintbrush(short x,short y,byte color,byte is_preview) if (is_preview && Mouse_K) // pas de curseur si on est en preview et return; // en train de cliquer - if (Main_current_layer < 4) + if (Constraint_mode && Main_current_layer < 4) { if (is_preview) goto single_pixel; @@ -2046,4 +2046,4 @@ void Brush_set_palette(T_Palette *palette) } } -*/ \ No newline at end of file +*/ diff --git a/src/buttons.c b/src/buttons.c index d483ea53..8d424254 100644 --- a/src/buttons.c +++ b/src/buttons.c @@ -4465,23 +4465,27 @@ void Display_effect_state(short x, short y, char * label, byte state) Print_in_window(x,y,label,(state)?MC_White:MC_Black,MC_Light); if (state) - Print_in_window(x+56,y,":ON ",MC_White,MC_Light); + Window_select_normal_button(x-23, y-5, 16, 16); else - Print_in_window(x+56,y,":OFF",MC_Black,MC_Light); + Window_unselect_normal_button(x-23, y-5, 16, 16); } +#define C2 92 + void Display_effect_states(void) { - Display_effect_state( 30, 24,"Shade" ,Shade_mode); - Display_effect_state( 30, 43,"Q-shade",Quick_shade_mode); - Display_effect_state( 30, 62,"Transp.",Colorize_mode); - Display_effect_state( 30, 81,"Smooth" ,Smooth_mode); - Display_effect_state( 30,100,"Smear" ,Smear_mode); - Display_effect_state(176, 24,"Stencil",Stencil_mode); - Display_effect_state(176, 43,"Mask" ,Mask_mode); - Display_effect_state(176, 62,"Sieve" ,Sieve_mode); - Display_effect_state(176, 81,"Grid" ,Snap_mode); - Display_effect_state(176,100,"Tiling" ,Tiling_mode); + Display_effect_state( 30, 24, "Shade" ,Shade_mode); + Display_effect_state( 30, 43, "Q-shade",Quick_shade_mode); + Display_effect_state( 30, 62, "Transp.",Colorize_mode); + Display_effect_state( 30, 81, "Smooth" ,Smooth_mode); + Display_effect_state( 30,100, "Smear" ,Smear_mode); + Display_effect_state(C2+23, 24, "Stencil",Stencil_mode); + Display_effect_state(C2+23, 43, "Mask" ,Mask_mode); + Display_effect_state(C2+23, 62, "Sieve" ,Sieve_mode); + Display_effect_state(C2+23, 81, "Grid" ,Snap_mode); + Display_effect_state(C2+23,100, "Tiling" ,Tiling_mode); + + Display_effect_state(177+23,24, "8 bit" ,Constraint_mode); } @@ -4503,25 +4507,29 @@ void Button_Effects(void) Window_set_normal_button( 7, 57, 16,16,"",0,1,Config_Key[SPECIAL_COLORIZE_MODE][0]); // 3 Window_set_normal_button( 7, 76, 16,16,"",0,1,Config_Key[SPECIAL_SMOOTH_MODE][0]); // 4 Window_set_normal_button( 7, 95, 16,16,"",0,1,Config_Key[SPECIAL_SMEAR_MODE][0]); // 5 - Window_set_normal_button(153, 19, 16,16,"",0,1,Config_Key[SPECIAL_STENCIL_MODE][0]); // 6 - Window_set_normal_button(153, 38, 16,16,"",0,1,Config_Key[SPECIAL_MASK_MODE][0]); // 7 - Window_set_normal_button(153, 57, 16,16,"",0,1,Config_Key[SPECIAL_SIEVE_MODE][0]); // 8 - Window_set_normal_button(153, 76, 16,16,"",0,1,Config_Key[SPECIAL_GRID_MODE][0]); // 9 - Window_set_normal_button(153, 95, 16,16,"",0,1,Config_Key[SPECIAL_TILING_MODE][0]); // 10 + Window_set_normal_button(C2, 19, 16,16,"",0,1,Config_Key[SPECIAL_STENCIL_MODE][0]); // 6 + Window_set_normal_button(C2, 38, 16,16,"",0,1,Config_Key[SPECIAL_MASK_MODE][0]); // 7 + Window_set_normal_button(C2, 57, 16,16,"",0,1,Config_Key[SPECIAL_SIEVE_MODE][0]); // 8 + Window_set_normal_button(C2, 76, 16,16,"",0,1,Config_Key[SPECIAL_GRID_MODE][0]); // 9 + Window_set_normal_button(C2, 95, 16,16,"",0,1,Config_Key[SPECIAL_TILING_MODE][0]); // 10 + Window_set_normal_button(195,131, 68,14,"Close",0,1,SDLK_RETURN); // 11 Window_set_normal_button( 7,131, 68,14,"All off",0,1,SDLK_DELETE); // 12 Window_set_normal_button( 83,131,104,14,"Feedback: ",1,1,SDLK_f); // 13 + + Window_set_normal_button(177, 19, 16,16,"",0,1,Config_Key[SPECIAL_FORMAT_CHECKER_MENU][0]); // 14 + Display_feedback_state(); Display_effect_sprite(0, 8,20); Display_effect_sprite(0, 8,39); Display_effect_sprite(1, 8,58); Display_effect_sprite(2, 8,77); Display_effect_sprite(8, 8,96); - Display_effect_sprite(4,154,20); - Display_effect_sprite(7,154,39); - Display_effect_sprite(5,154,58); - Display_effect_sprite(6,154,77); - Display_effect_sprite(3,154,96); + Display_effect_sprite(4,C2+1,20); + Display_effect_sprite(7,C2+1,39); + Display_effect_sprite(5,C2+1,58); + Display_effect_sprite(6,C2+1,77); + Display_effect_sprite(3,C2+1,96); Display_effect_states(); Print_in_window(12,117,"click: Left:Switch / Right:Edit",MC_Dark,MC_Light); @@ -4658,7 +4666,7 @@ void Button_Effects(void) { Button_Stencil_mode(); Hide_cursor(); - Display_effect_state(176,24,"Stencil",Stencil_mode); + Display_effect_state(C2+23,24,"Stencil",Stencil_mode); Display_cursor(); } else @@ -4674,7 +4682,7 @@ void Button_Effects(void) { Button_Mask_mode(); Hide_cursor(); - Display_effect_state(176,43,"Mask",Mask_mode); + Display_effect_state(C2+23,43,"Mask",Mask_mode); Display_cursor(); } else @@ -4690,7 +4698,7 @@ void Button_Effects(void) { Button_Sieve_mode(); Hide_cursor(); - Display_effect_state(176,62,"Sieve",Sieve_mode); + Display_effect_state(C2+23,62,"Sieve",Sieve_mode); Display_cursor(); } else @@ -4706,7 +4714,7 @@ void Button_Effects(void) { Button_Snap_mode(); Hide_cursor(); - Display_effect_state(176,81,"Grid",Snap_mode); + Display_effect_state(C2+23,81,"Grid",Snap_mode); Display_cursor(); } else @@ -4749,6 +4757,22 @@ void Button_Effects(void) Display_feedback_state(); Display_cursor(); break; + + + case 14: // Constraint checker/enforcer + if (Window_attribute1==LEFT_SIDE) + { + Button_Constraint_mode(); + Hide_cursor(); + Display_effect_state(177+23,24, "8 bit" ,Constraint_mode); + Display_cursor(); + } else { + Close_window(); + Display_cursor(); + // Contraint checker/enforcer menu + clicked_button = 11; + } + break; } } while (clicked_button!=11); @@ -4758,12 +4782,14 @@ void Button_Effects(void) else Hide_cursor(); - if (!(Shade_mode||Quick_shade_mode||Colorize_mode||Smooth_mode||Tiling_mode||Smear_mode||Stencil_mode||Mask_mode||Sieve_mode||Snap_mode)) + if (!(Shade_mode||Quick_shade_mode||Colorize_mode||Smooth_mode||Tiling_mode||Smear_mode||Stencil_mode||Mask_mode||Sieve_mode||Snap_mode||Constraint_mode)) Unselect_button(BUTTON_EFFECTS); Display_cursor(); } +#undef C2 + // Callback to display a font name in the list void Draw_one_font_name(word x, word y, word index, byte highlighted) { diff --git a/src/buttons.h b/src/buttons.h index eed881dc..4a755f5c 100644 --- a/src/buttons.h +++ b/src/buttons.h @@ -438,6 +438,9 @@ void Button_Tiling_mode(void); */ void Button_Tiling_menu(void); +void Button_Constraint_mode(void); +void Button_Constraint_menu(void); + /*! Callback for the command that turns off all drawaing effects. */ diff --git a/src/buttons_effects.c b/src/buttons_effects.c index d95e1514..614be571 100644 --- a/src/buttons_effects.c +++ b/src/buttons_effects.c @@ -162,6 +162,19 @@ void Menu_tag_colors(char * window_title, byte * table, byte * mode, byte can_ca } +// Constaint enforcer/checker ------------------------------------------------ +void Button_Constraint_mode(void) +{ + Constraint_mode=!Constraint_mode; +} + + +void Button_Constraint_menu(void) +{ + +} + + //--------------------------------- Stencil ---------------------------------- void Button_Stencil_mode(void) { @@ -547,7 +560,7 @@ void Button_Colorize_mode(void) switch(Colorize_current_mode) { case 0 : - Effect_function=Effect_layer_copy; + Effect_function=Effect_interpolated_colorize; break; case 1 : Effect_function=Effect_additive_colorize; diff --git a/src/global.h b/src/global.h index 3746126b..771e630e 100644 --- a/src/global.h +++ b/src/global.h @@ -726,6 +726,9 @@ GFX2_GLOBAL byte Mask_mode; /// Array of booleans. True if the indexed color is protected by the mask. GFX2_GLOBAL byte Mask_table[256]; +// -- Constraint enforcer +GFX2_GLOBAL byte Constraint_mode; + // -- Magnifier data #ifdef GLOBAL_VARIABLES diff --git a/src/graph.c b/src/graph.c index d2d09ae4..d263fc72 100644 --- a/src/graph.c +++ b/src/graph.c @@ -2977,7 +2977,24 @@ byte Read_pixel_from_current_screen (word x,word y) void Pixel_in_current_screen (word x,word y,byte color,int with_preview) { #ifndef NOLAYERS - if ( Main_current_layer == 4) + if (!Constraint_mode) + { + byte depth = *(Main_visible_image_depth_buffer.Image+x+y*Main_image_width); + *(Main_backups->Pages->Image[Main_current_layer] + x+y*Main_image_width)=color; + if ( depth <= Main_current_layer) + { + if (color == Main_backups->Pages->Transparent_color) // transparent color + // fetch pixel color from the topmost visible layer + color=*(Main_backups->Pages->Image[depth] + x+y*Main_image_width); + + *(x+y*Main_image_width+Main_screen)=color; + + if (with_preview) + Pixel_preview(x,y,color); + } + + } + else if ( Main_current_layer == 4) { if (color<4) { diff --git a/src/pages.c b/src/pages.c index 0669e963..b7901bb8 100644 --- a/src/pages.c +++ b/src/pages.c @@ -199,7 +199,7 @@ void Redraw_layered_image(void) // Re-construct the image with the visible layers byte layer=0; // First layer - if (Main_layers_visible & (1<<4)) + if (Constraint_mode && Main_layers_visible & (1<<4)) { // The raster result layer is visible: start there // Copy it in Main_visible_image From bf9c34d7fe41a43e3d10035f85bff4d8acd0dec1 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Tue, 15 Feb 2011 17:48:16 +0000 Subject: [PATCH 5/9] Code for loading "CM5" (CPC Mode 5) pixtures * Fix a bug in the Set_layer function : it was only possible to set a new layer, and this format needs us to write to previous layers too * Saving is missing (you need to save as png then convert back to cm5 using SyX converter) * Preview does not work (it does not use layers, so the result is broken) * Loading switches the "8bit" mode on automatically git-svn-id: svn://pulkomandy.tk/GrafX2/branches/cpcmode5@1723 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- src/const.h | 1 + src/loadsave.c | 12 ++- src/miscfileformats.c | 171 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 180 insertions(+), 4 deletions(-) diff --git a/src/const.h b/src/const.h index 69c844ca..2dcb9f6a 100644 --- a/src/const.h +++ b/src/const.h @@ -120,6 +120,7 @@ enum FILE_FORMATS FORMAT_KCF, FORMAT_PAL, FORMAT_SCR, + FORMAT_CM5, FORMAT_XPM, FORMAT_MISC, ///< Must be last of enum: others formats recognized by SDL_image }; diff --git a/src/loadsave.c b/src/loadsave.c index 87238a54..96213773 100644 --- a/src/loadsave.c +++ b/src/loadsave.c @@ -125,6 +125,10 @@ void Save_C64(T_IO_Context *); // -- SCR (Amstrad CPC) void Save_SCR(T_IO_Context *); +// -- CM5 (Amstrad CPC) +void Test_CM5(T_IO_Context *); +void Load_CM5(T_IO_Context *); + // -- XPM (X PixMap) // Loading is done through SDL_Image void Save_XPM(T_IO_Context*); @@ -142,7 +146,7 @@ void Load_SDL_Image(T_IO_Context *); // ENUM Name TestFunc LoadFunc SaveFunc PalOnly Comment Layers Ext Exts T_Format File_formats[] = { - {FORMAT_ALL_IMAGES, "(all)", NULL, NULL, NULL, 0, 0, 0, "", "gif;png;bmp;pcx;pkm;lbm;iff;img;sci;scq;scf;scn;sco;pi1;pc1;cel;neo;kcf;pal;c64;koa;koala;fli;bml;cdu;prg;tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff;ico"}, + {FORMAT_ALL_IMAGES, "(all)", NULL, NULL, NULL, 0, 0, 0, "", "gif;png;bmp;pcx;pkm;lbm;iff;img;sci;scq;scf;scn;sco;pi1;pc1;cel;neo;kcf;pal;c64;koa;koala;fli;bml;cdu;prg;tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff;ico;cm5"}, {FORMAT_ALL_FILES, "(*.*)", NULL, NULL, NULL, 0, 0, 0, "", "*"}, {FORMAT_GIF, " gif", Test_GIF, Load_GIF, Save_GIF, 0, 1, 1, "gif", "gif"}, #ifndef __no_pnglib__ @@ -162,6 +166,7 @@ T_Format File_formats[] = { {FORMAT_PAL, " pal", Test_PAL, Load_PAL, Save_PAL, 1, 0, 0, "pal", "pal"}, {FORMAT_C64, " c64", Test_C64, Load_C64, Save_C64, 0, 1, 0, "c64", "c64;koa;koala;fli;bml;cdu;prg"}, {FORMAT_SCR, " cpc", NULL, NULL, Save_SCR, 0, 0, 0, "cpc", "cpc;scr"}, + {FORMAT_CM5, " cm5", Test_CM5, Load_CM5, NULL, 0, 0, 1, "cm5", "cm5"}, {FORMAT_XPM, " xpm", NULL, NULL, Save_XPM, 0, 0, 0, "xpm", "xpm"}, {FORMAT_MISC,"misc.",NULL, NULL, NULL, 0, 0, 0, "", "tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff;ico"}, }; @@ -1262,7 +1267,7 @@ void Set_layer(T_IO_Context *context, byte layer) if (context->Type == CONTEXT_MAIN_IMAGE) { // This awful thing is the part that happens on load - while (layer > (context->Nb_layers-1)) + while (layer >= context->Nb_layers) { if (Add_layer(Main_backups, layer)) { @@ -1272,10 +1277,11 @@ void Set_layer(T_IO_Context *context, byte layer) break; } context->Nb_layers = Main_backups->Pages->Nb_layers; - Main_current_layer = layer; Main_layers_visible = (2<Target_address=Main_backups->Pages->Image[layer]; + + Main_current_layer = layer; } } diff --git a/src/miscfileformats.c b/src/miscfileformats.c index dd3c518c..1775cfd3 100644 --- a/src/miscfileformats.c +++ b/src/miscfileformats.c @@ -6,7 +6,7 @@ Copyright 2009 Petter Lindquist Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet - Copyright 2007 Adrien Destugues + Copyright 2007-2011 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or @@ -2926,3 +2926,172 @@ void Save_SCR(T_IO_Context * context) File_error = 0; } + +// CM5 - Amstrad CPC "Mode 5" picture +// This is a format designed by SyX. There is one .SCR file in the usual amstrad format, +// and a .CM5 file with the palette, which varies over time. + +void Test_CM5(T_IO_Context * context) +{ + // check cm5 file size == 2049 bytes + FILE *file; + char filename[MAX_PATH_CHARACTERS]; + long file_size; + + Get_full_filename(filename, context->File_name, context->File_directory); + + File_error = 1; + + if ((file = fopen(filename, "rb"))) + { + file_size = File_length_file(file); + if (file_size == 2049) + File_error = 0; + } + + // TODO: check existence of a .SCR file with the same name +} + + +void Load_CM5(T_IO_Context* context) +{ + // Ensure "8bit" constraint mode is switched on + // Set palette to the CPC hardware colors + // Load the palette data to the 4 colorlayers + FILE *file; + char filename[MAX_PATH_CHARACTERS]; + byte value = 0; + int mod; + short line = 0; + int tx, ty; + byte buffer[48*6/4]; + + Get_full_filename(filename, context->File_name, context->File_directory); + + if (!(file = fopen(filename, "rb"))) + { + File_error = 1; + return; + } + + Pre_load(context, 48*6, 256, 2049, FORMAT_CM5, PIXEL_SIMPLE, 0); + context->Width=48*6; + context->Height=256; + + // Setup the palette (amstrad hardware palette) + context->Palette[0x54].R = 0; context->Palette[0x54].G = 2; context->Palette[0x54].B = 1; + context->Palette[0x44].R = 0; context->Palette[0x44].G = 2; context->Palette[0x44].B = 0x6B; + context->Palette[0x55].R = 0x0C; context->Palette[0x55].G = 2; context->Palette[0x55].B = 0xF4; + context->Palette[0x5C].R = 0x6C; context->Palette[0x5C].G = 2; context->Palette[0x5C].B = 1; + context->Palette[0x58].R = 0x69; context->Palette[0x58].G = 2; context->Palette[0x58].B = 0x68; + context->Palette[0x5D].R = 0x6C; context->Palette[0x5D].G = 2; context->Palette[0x5D].B = 0xF2; + context->Palette[0x4C].R = 0xF3; context->Palette[0x4C].G = 5; context->Palette[0x4C].B = 6; + context->Palette[0x45].R = 0xF0; context->Palette[0x45].G = 2; context->Palette[0x45].B = 0x68; + context->Palette[0x4D].R = 0xF3; context->Palette[0x4D].G = 2; context->Palette[0x4D].B = 0xF4; + context->Palette[0x56].R = 2; context->Palette[0x56].G = 0x78; context->Palette[0x56].B = 1; + context->Palette[0x46].R = 0; context->Palette[0x46].G = 0x78; context->Palette[0x46].B = 0x68; + context->Palette[0x57].R = 0xC; context->Palette[0x57].G = 0x7B; context->Palette[0x57].B = 0xF4; + context->Palette[0x5E].R = 0x6E; context->Palette[0x5E].G = 0x7B; context->Palette[0x5E].B = 1; + context->Palette[0x40].R = 0x6E; context->Palette[0x40].G = 0x7D; context->Palette[0x40].B = 0x6B; + context->Palette[0x5F].R = 0x6E; context->Palette[0x5F].G = 0x7B; context->Palette[0x5F].B = 0xF6; + context->Palette[0x4E].R = 0xF3; context->Palette[0x4E].G = 0x7D; context->Palette[0x4E].B = 0xD; + context->Palette[0x47].R = 0xF3; context->Palette[0x47].G = 0x7D; context->Palette[0x47].B = 0x6B; + context->Palette[0x4F].R = 0xFA; context->Palette[0x4F].G = 0x80; context->Palette[0x4F].B = 0xF9; + context->Palette[0x52].R = 2; context->Palette[0x52].G = 0xF0; context->Palette[0x52].B = 1; + context->Palette[0x42].R = 0; context->Palette[0x42].G = 0xF3; context->Palette[0x42].B = 0x6B; + context->Palette[0x53].R = 0xF; context->Palette[0x53].G = 0xF3; context->Palette[0x53].B = 0xF2; + context->Palette[0x5A].R = 0x71; context->Palette[0x5A].G = 0xF5; context->Palette[0x5A].B = 4; + context->Palette[0x59].R = 0x71; context->Palette[0x59].G = 0xF3; context->Palette[0x59].B = 0x6B; + context->Palette[0x5B].R = 0x71; context->Palette[0x5B].G = 0xF3; context->Palette[0x5B].B = 0xF4; + context->Palette[0x4A].R = 0xF3; context->Palette[0x4A].G = 0xF3; context->Palette[0x4A].B = 0xD; + context->Palette[0x43].R = 0xF3; context->Palette[0x43].G = 0xF3; context->Palette[0x43].B = 0x6D; + context->Palette[0x4B].R = 255; context->Palette[0x4B].G = 0xF3; context->Palette[0x4B].B = 0xF9; + + Palette_loaded(context); + + if (Constraint_mode != 1) + Constraint_mode = 1; + + if (Read_byte(file, &value)!=1) + File_error = 2; + + Set_layer(context, 0); + for(ty=0; tyHeight; ty++) + for(tx=0; txWidth; tx++) + { + Set_pixel(context, tx, ty, value); + } + // Fill layer with color we just read + + while(Read_byte(file, &value) == 1) + { + switch(mod) + { + case 0: + // This is color for layer 1 + Set_layer(context, 1); + for(tx=0; txWidth; tx++) + Set_pixel(context, tx, line, value); + break; + case 1: + // This is color for layer 2 + Set_layer(context, 2); + for(tx=0; txWidth; tx++) + Set_pixel(context, tx, line, value); + break; + default: + // This is color for a block in layer 4 + Set_layer(context, 3); + for(tx=(mod-2)*48; tx<(mod-1)*48; tx++) + Set_pixel(context, tx, line, value); + break; + } + mod = mod + 1; + if (mod > 7) + { + mod = 0; + line ++; + } + } + + fclose(file); + + // Load the pixeldata to the 5th layer + filename[strlen(filename) - 3] = 0; + strcat(filename,"gfx"); + if (!(file = fopen(filename, "rb"))) + { + File_error = 1; + return; + } + + Set_layer(context, 4); + + for (ty = 0; ty < 256; ty++) + { + Read_bytes(file, buffer, 48*6/4); + for (tx = 0; tx < 48*6; tx+=4) + { + Set_pixel(context, tx+0, ty, 3-(((buffer[tx/4]&0x80) >> 7) |((buffer[tx/4]&0x8)>>2))); + Set_pixel(context, tx+1, ty, 3-(((buffer[tx/4]&0x40) >> 6) |((buffer[tx/4]&0x4)>>1))); + Set_pixel(context, tx+2, ty, 3-(((buffer[tx/4]&0x20) >> 5) |((buffer[tx/4]&0x2)>>0))); + Set_pixel(context, tx+3, ty, 3-(((buffer[tx/4]&0x10) >> 4) |((buffer[tx/4]&0x1)<<1))); + } + } + + fclose(file); + +} + + +void Save_CM5(T_IO_Context* context) +{ + // Check picture has 5 layers + // Check the constraints on the layers + // Layer 1 : 1 color Only + // Layer 2 and 3 : 1 color/line + // Layer 4 : 1 color / 48x1 block + // Layer 5 : colors 1 to 4 only used + // Layer 1..4 are written to the .CM5 file, then layer 5 is written to .scr file using + // the Save_SCR function. +} From cd8f3e40dadfdb9d1d18f4afd35b682bab872f6b Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Tue, 15 Feb 2011 19:34:36 +0000 Subject: [PATCH 6/9] * Save CM5 files. There seem to be a problem with "Supports_layers" field. setting it to 1 still triggers the warning that image will be flatenned... git-svn-id: svn://pulkomandy.tk/GrafX2/branches/cpcmode5@1724 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- src/loadsave.c | 3 +- src/miscfileformats.c | 72 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 69 insertions(+), 6 deletions(-) diff --git a/src/loadsave.c b/src/loadsave.c index 96213773..281879e5 100644 --- a/src/loadsave.c +++ b/src/loadsave.c @@ -128,6 +128,7 @@ void Save_SCR(T_IO_Context *); // -- CM5 (Amstrad CPC) void Test_CM5(T_IO_Context *); void Load_CM5(T_IO_Context *); +void Save_CM5(T_IO_Context *); // -- XPM (X PixMap) // Loading is done through SDL_Image @@ -166,7 +167,7 @@ T_Format File_formats[] = { {FORMAT_PAL, " pal", Test_PAL, Load_PAL, Save_PAL, 1, 0, 0, "pal", "pal"}, {FORMAT_C64, " c64", Test_C64, Load_C64, Save_C64, 0, 1, 0, "c64", "c64;koa;koala;fli;bml;cdu;prg"}, {FORMAT_SCR, " cpc", NULL, NULL, Save_SCR, 0, 0, 0, "cpc", "cpc;scr"}, - {FORMAT_CM5, " cm5", Test_CM5, Load_CM5, NULL, 0, 0, 1, "cm5", "cm5"}, + {FORMAT_CM5, " cm5", Test_CM5, Load_CM5, Save_CM5, 0, 0, 1, "cm5", "cm5"}, {FORMAT_XPM, " xpm", NULL, NULL, Save_XPM, 0, 0, 0, "xpm", "xpm"}, {FORMAT_MISC,"misc.",NULL, NULL, NULL, 0, 0, 0, "", "tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff;ico"}, }; diff --git a/src/miscfileformats.c b/src/miscfileformats.c index 1775cfd3..c0629c3c 100644 --- a/src/miscfileformats.c +++ b/src/miscfileformats.c @@ -3086,12 +3086,74 @@ void Load_CM5(T_IO_Context* context) void Save_CM5(T_IO_Context* context) { - // Check picture has 5 layers - // Check the constraints on the layers + char filename[MAX_PATH_CHARACTERS]; + FILE* file; + int tx, ty; + + + Get_full_filename(filename, context->File_name, context->File_directory); + // TODO: Check picture has 5 layers + // TODO: Check the constraints on the layers // Layer 1 : 1 color Only // Layer 2 and 3 : 1 color/line // Layer 4 : 1 color / 48x1 block - // Layer 5 : colors 1 to 4 only used - // Layer 1..4 are written to the .CM5 file, then layer 5 is written to .scr file using - // the Save_SCR function. + // TODO: handle filesize + + if (!(file = fopen(filename,"wb"))) + { + File_error = 1; + return; + } + + // Write layer 0 + Set_layer(context, 0); + Write_byte(file, Get_pixel(context, 0, 0)); + for(ty = 0; ty < 256; ty++) + { + Set_layer(context, 1); + Write_byte(file, Get_pixel(context, 0, ty)); + Set_layer(context, 2); + Write_byte(file, Get_pixel(context, 0, ty)); + Set_layer(context, 3); + for(tx = 0; tx < 6; tx++) + { + Write_byte(file, Get_pixel(context, tx*48, ty)); + } + } + + fclose(file); + + // Now the pixeldata + filename[strlen(filename) - 3] = 0; + strcat(filename,"gfx"); + if (!(file = fopen(filename, "wb"))) + { + File_error = 2; + return; + } + + Set_layer(context, 4); + + for (ty = 0; ty < 256; ty++) + { + for (tx = 0; tx < 48*6; tx+=4) + { + byte code = 0; + byte pixel; + + pixel = 3-Get_pixel(context, tx+3, ty); + code |= (pixel&2)>>1 | ((pixel & 1)<<4); + pixel = 3-Get_pixel(context, tx+2, ty); + code |= ((pixel&2)<<0) | ((pixel & 1)<<5); + pixel = 3-Get_pixel(context, tx+1, ty); + code |= ((pixel&2)<<1) | ((pixel & 1)<<6); + pixel = 3-Get_pixel(context, tx, ty); + code |= ((pixel&2)<<2) | ((pixel & 1)<<7); + Write_byte(file, code); + } + } + + fclose(file); + File_error = 0; + } From 7c6e05ef6b3d4204db0cb04dcf47bd7f5b1414e7 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Wed, 16 Feb 2011 19:23:54 +0000 Subject: [PATCH 7/9] mode5: Fix shortcuts of 'cycle colors' and format checker, mixup during merge git-svn-id: svn://pulkomandy.tk/GrafX2/branches/cpcmode5@1727 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- src/hotkeys.c | 8 ++++++++ src/hotkeys.h | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/hotkeys.c b/src/hotkeys.c index 302b5644..732d5ba1 100644 --- a/src/hotkeys.c +++ b/src/hotkeys.c @@ -1642,6 +1642,14 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { SDLK_BACKQUOTE|MOD_CTRL, // Ctrl + `~ 0}, {198, + "Toggle color cycling", + "Activates or desactivates color", + "cycling, if the current image has", + "cycling colors. (See gradient menu)", + true, + SDLK_BACKQUOTE|MOD_CTRL, // Ctrl + `~ + 0}, + {199, "Format checker", "Performs a format check on the", "current image.", diff --git a/src/hotkeys.h b/src/hotkeys.h index e6f97c63..6ffc2de1 100644 --- a/src/hotkeys.h +++ b/src/hotkeys.h @@ -33,7 +33,7 @@ #endif #include -#define NB_SHORTCUTS 199 ///< Number of actions that can have a key combination associated to it. +#define NB_SHORTCUTS 200 ///< Number of actions that can have a key combination associated to it. /*** Types definitions and structs ***/ From 9058926e4b40acaf502cbc35c66b5fd96168b0db Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Wed, 16 Feb 2011 19:36:14 +0000 Subject: [PATCH 8/9] mode5: Fix shortcut info for format checker/format menu git-svn-id: svn://pulkomandy.tk/GrafX2/branches/cpcmode5@1728 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- src/hotkeys.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/hotkeys.c b/src/hotkeys.c index 732d5ba1..3467b6b2 100644 --- a/src/hotkeys.c +++ b/src/hotkeys.c @@ -1642,21 +1642,21 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { SDLK_BACKQUOTE|MOD_CTRL, // Ctrl + `~ 0}, {198, - "Toggle color cycling", - "Activates or desactivates color", - "cycling, if the current image has", - "cycling colors. (See gradient menu)", - true, - SDLK_BACKQUOTE|MOD_CTRL, // Ctrl + `~ - 0}, - {199, "Format checker", "Performs a format check on the", "current image.", "", true, 0, - 0} + 0}, + {199, + "Format checker menu", + "Allows you to setup the checks", + "performed by the format checker.", + "", + true, + 0, + 0}, }; word Ordering[NB_SHORTCUTS]= From 55422d160e1e4b2dc210a59e46baa64104b3cfad Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Wed, 2 Mar 2011 22:07:24 +0000 Subject: [PATCH 9/9] (mode5 branch) Fix a bug in saving, including autosave every few minutes, that auto-selects the last layer to draw. git-svn-id: svn://pulkomandy.tk/GrafX2/branches/cpcmode5@1743 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- src/fileformats.c | 4 ++-- src/loadsave.c | 18 ++++++++++++++---- src/loadsave.h | 4 +++- src/miscfileformats.c | 26 +++++++++++++------------- 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/fileformats.c b/src/fileformats.c index 21d281e2..bef58bcc 100644 --- a/src/fileformats.c +++ b/src/fileformats.c @@ -2085,7 +2085,7 @@ void Load_GIF(T_IO_Context * context) // This a second layer/frame, or more. // Attempt to add a layer to current image current_layer++; - Set_layer(context, current_layer); + Set_loading_layer(context, current_layer); } number_LID++; @@ -2444,7 +2444,7 @@ void Save_GIF(T_IO_Context * context) GCE_block[3] |= 1; // Transparent color flag GCE_block[6] = context->Transparent_color; - Set_layer(context, current_layer); + Set_saving_layer(context, current_layer); if (current_layer == context->Nb_layers -1) { diff --git a/src/loadsave.c b/src/loadsave.c index 281879e5..e9e73edb 100644 --- a/src/loadsave.c +++ b/src/loadsave.c @@ -436,7 +436,7 @@ void Pre_load(T_IO_Context *context, short width, short height, long file_size, context->Nb_layers=1; Main_current_layer=0; Main_layers_visible=1<<0; - Set_layer(context,0); + Set_loading_layer(context,0); // Remove previous comment, unless we load just a palette if (! Get_fileformat(context->Format)->Palette_only) @@ -1261,7 +1261,18 @@ void Init_context_surface(T_IO_Context * context, char *file_name, char *file_di } /// Function to call when need to switch layers. -void Set_layer(T_IO_Context *context, byte layer) +void Set_saving_layer(T_IO_Context *context, byte layer) +{ + context->Current_layer = layer; + + if (context->Type == CONTEXT_MAIN_IMAGE) + { + context->Target_address=Main_backups->Pages->Image[layer]; + } +} + +/// Function to call when need to switch layers. +void Set_loading_layer(T_IO_Context *context, byte layer) { context->Current_layer = layer; @@ -1280,9 +1291,8 @@ void Set_layer(T_IO_Context *context, byte layer) context->Nb_layers = Main_backups->Pages->Nb_layers; Main_layers_visible = (2<Target_address=Main_backups->Pages->Image[layer]; - Main_current_layer = layer; + context->Target_address=Main_backups->Pages->Image[layer]; } } diff --git a/src/loadsave.h b/src/loadsave.h index 8fcd6376..ca05b6ef 100644 --- a/src/loadsave.h +++ b/src/loadsave.h @@ -215,7 +215,9 @@ void Set_pixel(T_IO_Context *context, short x, short y, byte c); /// Set the color of a 24bit pixel (on load) void Set_pixel_24b(T_IO_Context *context, short x, short y, byte r, byte g, byte b); /// Function to call when need to switch layers. -void Set_layer(T_IO_Context *context, byte layer); +void Set_loading_layer(T_IO_Context *context, byte layer); +/// Function to call when need to switch layers. +void Set_saving_layer(T_IO_Context *context, byte layer); // ================================================================= diff --git a/src/miscfileformats.c b/src/miscfileformats.c index c0629c3c..9747799a 100644 --- a/src/miscfileformats.c +++ b/src/miscfileformats.c @@ -2206,7 +2206,7 @@ void Load_C64_fli(T_IO_Context *context, byte *bitmap, byte *screen_ram, byte *c } } - Set_layer(context, 1); + Set_loading_layer(context, 1); for(cy=0; cy<25; cy++) { for(cx=0; cx<40; cx++) @@ -2222,7 +2222,7 @@ void Load_C64_fli(T_IO_Context *context, byte *bitmap, byte *screen_ram, byte *c } } - Set_layer(context, 2); + Set_loading_layer(context, 2); for(cy=0; cy<25; cy++) { for(cx=0; cx<40; cx++) @@ -2244,7 +2244,7 @@ void Load_C64_fli(T_IO_Context *context, byte *bitmap, byte *screen_ram, byte *c } } } - Set_layer(context, 3); + Set_loading_layer(context, 3); for(y=0; y<200; y++) { for(x=0; x<160; x++) @@ -3015,7 +3015,7 @@ void Load_CM5(T_IO_Context* context) if (Read_byte(file, &value)!=1) File_error = 2; - Set_layer(context, 0); + Set_loading_layer(context, 0); for(ty=0; tyHeight; ty++) for(tx=0; txWidth; tx++) { @@ -3029,19 +3029,19 @@ void Load_CM5(T_IO_Context* context) { case 0: // This is color for layer 1 - Set_layer(context, 1); + Set_loading_layer(context, 1); for(tx=0; txWidth; tx++) Set_pixel(context, tx, line, value); break; case 1: // This is color for layer 2 - Set_layer(context, 2); + Set_loading_layer(context, 2); for(tx=0; txWidth; tx++) Set_pixel(context, tx, line, value); break; default: // This is color for a block in layer 4 - Set_layer(context, 3); + Set_loading_layer(context, 3); for(tx=(mod-2)*48; tx<(mod-1)*48; tx++) Set_pixel(context, tx, line, value); break; @@ -3065,7 +3065,7 @@ void Load_CM5(T_IO_Context* context) return; } - Set_layer(context, 4); + Set_loading_layer(context, 4); for (ty = 0; ty < 256; ty++) { @@ -3106,15 +3106,15 @@ void Save_CM5(T_IO_Context* context) } // Write layer 0 - Set_layer(context, 0); + Set_saving_layer(context, 0); Write_byte(file, Get_pixel(context, 0, 0)); for(ty = 0; ty < 256; ty++) { - Set_layer(context, 1); + Set_saving_layer(context, 1); Write_byte(file, Get_pixel(context, 0, ty)); - Set_layer(context, 2); + Set_saving_layer(context, 2); Write_byte(file, Get_pixel(context, 0, ty)); - Set_layer(context, 3); + Set_saving_layer(context, 3); for(tx = 0; tx < 6; tx++) { Write_byte(file, Get_pixel(context, tx*48, ty)); @@ -3132,7 +3132,7 @@ void Save_CM5(T_IO_Context* context) return; } - Set_layer(context, 4); + Set_saving_layer(context, 4); for (ty = 0; ty < 256; ty++) {